Mixin_Displayed_Gallery_Queries

The NextGEN Gallery Mixin Displayed Gallery Queries class.

Defined (1)

The class is defined in the following location(s).

/products/photocrati_nextgen/modules/nextgen_gallery_display/package.module.nextgen_gallery_display.php  
  1. class Mixin_Displayed_Gallery_Queries extends Mixin 
  2. public function select_random_variation() 
  3. $retval = FALSE; 
  4. $source_obj = $this->object->get_source(); 
  5. if ($source_obj && $source_obj->has_variations) { 
  6. $max = 0; 
  7. if (!defined('NGG_MAX_VARIATIONS')) { 
  8. $settings = C_Photocrati_Global_Settings_Manager::get_instance(); 
  9. $max = $settings->get('max_variations', 5); 
  10. define('NGG_MAX_VARIATIONS', $max); 
  11. } else { 
  12. $max = NGG_MAX_VARIATIONS; 
  13. $this->object->variation = floor(rand(1, $max)); 
  14. $retval = $this->object->variation; 
  15. return $retval; 
  16. public function get_entities($limit = FALSE, $offset = FALSE, $id_only = FALSE, $returns = 'included') 
  17. $retval = array(); 
  18. $source_obj = $this->object->get_source(); 
  19. $max = $this->object->get_maximum_entity_count(); 
  20. if (!$limit || is_numeric($limit) && $limit > $max) { 
  21. $limit = $max; 
  22. // Ensure that all parameters have values that are expected 
  23. if ($this->object->_parse_parameters()) { 
  24. // Is this an image query? 
  25. if (in_array('image', $source_obj->returns)) { 
  26. $retval = $this->object->_get_image_entities($source_obj, $limit, $offset, $id_only, $returns); 
  27. } elseif (in_array('gallery', $source_obj->returns)) { 
  28. $retval = $this->object->_get_album_and_gallery_entities($source_obj, $limit, $offset, $id_only, $returns); 
  29. return $retval; 
  30. /** 
  31. * Gets all images in the displayed gallery 
  32. * @param stdClass $source_obj 
  33. * @param int $limit 
  34. * @param int $offset 
  35. * @param boolean $id_only 
  36. * @param string $returns 
  37. */ 
  38. public function _get_image_entities($source_obj, $limit, $offset, $id_only, $returns) 
  39. // TODO: This method is very long, and therefore more difficult to read 
  40. // Find a way to minimalize or segment 
  41. $mapper = C_Image_Mapper::get_instance(); 
  42. $image_key = $mapper->get_primary_key_column(); 
  43. $select = $id_only ? $image_key : $mapper->get_table_name() . '.*'; 
  44. $sort_direction = $this->object->order_direction; 
  45. $sort_by = $this->object->order_by; 
  46. // Here's what this method is doing: 
  47. // 1) Determines what results need returned 
  48. // 2) Determines from what container ids the results should come from 
  49. // 3) Applies ORDER BY clause 
  50. // 4) Applies LIMIT/OFFSET clause 
  51. // 5) Executes the query and returns the result 
  52. // We start with the most difficult query. When returns is "both", we 
  53. // need to return a list of both included and excluded entity ids, and 
  54. // mark specifically which entities are excluded 
  55. if ($returns == 'both') { 
  56. // We need to add two dynamic columns, one called "sortorder" and 
  57. // the other called "exclude". 
  58. $if_true = 1; 
  59. $if_false = 0; 
  60. $excluded_set = $this->object->entity_ids; 
  61. if (!$excluded_set) { 
  62. $if_true = 0; 
  63. $if_false = 1; 
  64. $excluded_set = $this->object->exclusions; 
  65. $sortorder_set = $this->object->sortorder ? $this->object->sortorder : $excluded_set; 
  66. // Add sortorder column 
  67. if ($sortorder_set) { 
  68. $select = $this->object->_add_find_in_set_column($select, $image_key, $sortorder_set, 'new_sortorder', TRUE); 
  69. // A user might want to sort the results by the order of 
  70. // images that they specified to be included. For that,  
  71. // we need some trickery by reversing the order direction 
  72. $sort_direction = $this->object->order_direction == 'ASC' ? 'DESC' : 'ASC'; 
  73. $sort_by = 'new_sortorder'; 
  74. // Add exclude column 
  75. if ($excluded_set) { 
  76. $select = $this->object->_add_find_in_set_column($select, $image_key, $excluded_set, 'exclude'); 
  77. $select .= ", IF (exclude = 0 AND @exclude = 0, {$if_true}, {$if_false}) AS 'exclude'"; 
  78. // Select what we want 
  79. $mapper->select($select); 
  80. // When returns is "included", the query is relatively simple. We 
  81. // just provide a where clause to limit how many images we're returning 
  82. // based on the entity_ids, exclusions, and container_ids parameters 
  83. if ($returns == 'included') { 
  84. // If the sortorder propery is available, then we need to override 
  85. // the sortorder 
  86. if ($this->object->sortorder) { 
  87. $select = $this->object->_add_find_in_set_column($select, $image_key, $this->object->sortorder, 'new_sortorder', TRUE); 
  88. $sort_direction = $this->object->order_direction == 'ASC' ? 'DESC' : 'ASC'; 
  89. $sort_by = 'new_sortorder'; 
  90. $mapper->select($select); 
  91. // Filter based on entity_ids selection 
  92. if ($this->object->entity_ids) { 
  93. $mapper->where(array("{$image_key} IN %s", $this->object->entity_ids)); 
  94. // Filter based on exclusions selection 
  95. if ($this->object->exclusions) { 
  96. $mapper->where(array("{$image_key} NOT IN %s", $this->object->exclusions)); 
  97. // Ensure that no images marked as excluded at the gallery level are returned 
  98. if (empty($this->object->skip_excluding_globally_excluded_images)) { 
  99. $mapper->where(array('exclude = %d', 0)); 
  100. } elseif ($returns == 'excluded') { 
  101. // If the sortorder propery is available, then we need to override 
  102. // the sortorder 
  103. if ($this->object->sortorder) { 
  104. $select = $this->object->_add_find_in_set_column($select, $image_key, $this->object->sortorder, 'new_sortorder', TRUE); 
  105. $sort_direction = $this->object->order_direction == 'ASC' ? 'DESC' : 'ASC'; 
  106. $sort_by = 'new_sortorder'; 
  107. // Mark each result as excluded 
  108. $select .= ', 1 AS exclude'; 
  109. $mapper->select($select); 
  110. // Is this case, entity_ids become the exclusions 
  111. $exclusions = $this->object->entity_ids; 
  112. // Remove the exclusions always takes precedence over entity_ids, so 
  113. // we adjust the list of ids 
  114. if ($this->object->exclusions) { 
  115. foreach ($this->object->exclusions as $excluded_entity_id) { 
  116. if (($index = array_search($excluded_entity_id, $exclusions)) !== FALSE) { 
  117. unset($exclusions[$index]); 
  118. // Filter based on exclusions selection 
  119. if ($exclusions) { 
  120. $mapper->where(array("{$image_key} NOT IN %s", $exclusions)); 
  121. } else { 
  122. if ($this->object->exclusions) { 
  123. $mapper->where(array("{$image_key} IN %s", $this->object->exclusions)); 
  124. // Ensure that images marked as excluded are returned as well 
  125. $mapper->where(array('exclude = 1')); 
  126. // Filter based on containers_ids. Container ids is a little more 
  127. // complicated as it can contain gallery ids or tags 
  128. if ($this->object->container_ids) { 
  129. // Container ids are tags 
  130. if ($source_obj->name == 'tags') { 
  131. $term_ids = $this->object->get_term_ids_for_tags($this->object->container_ids); 
  132. $mapper->where(array("{$image_key} IN %s", get_objects_in_term($term_ids, 'ngg_tag'))); 
  133. } else { 
  134. $mapper->where(array('galleryid IN %s', $this->object->container_ids)); 
  135. // Filter based on excluded container ids 
  136. if ($this->object->excluded_container_ids) { 
  137. // Container ids are tags 
  138. if ($source_obj->name == 'tags') { 
  139. $term_ids = $this->object->get_term_ids_for_tags($this->object->excluded_container_ids); 
  140. $mapper->where(array("{$image_key} NOT IN %s", get_objects_in_term($term_ids, 'ngg_tag'))); 
  141. } else { 
  142. $mapper->where(array('galleryid NOT IN %s', $this->object->excluded_container_ids)); 
  143. // Adjust the query more based on what source was selected 
  144. if (in_array($this->object->source, array('recent', 'recent_images'))) { 
  145. $sort_direction = 'DESC'; 
  146. $sort_by = 'imagedate'; 
  147. } elseif ($this->object->source == 'random_images' && empty($this->object->entity_ids)) { 
  148. $table_name = $mapper->get_table_name(); 
  149. $where_clauses = array(); 
  150. $sub_where_sql = ''; 
  151. foreach ($mapper->_where_clauses as $where) { 
  152. $where_clauses[] = '(' . $where . ')'; 
  153. if ($where_clauses) { 
  154. $sub_where_sql = 'WHERE ' . implode(' AND ', $where_clauses); 
  155. $mapper->_where_clauses = array(" /*NGG_NO_EXTRAS_TABLE*/ `{$image_key}` IN (SELECT `{$image_key}` FROM (SELECT `{$image_key}` FROM `{$table_name}` i {$sub_where_sql} ORDER BY RAND() LIMIT {$this->object->maximum_entity_count}) o) /*NGG_NO_EXTRAS_TABLE*/"); 
  156. // Apply a sorting order 
  157. if ($sort_by) { 
  158. $mapper->order_by($sort_by, $sort_direction); 
  159. // Apply a limit 
  160. if ($limit) { 
  161. if ($offset) { 
  162. $mapper->limit($limit, $offset); 
  163. } else { 
  164. $mapper->limit($limit); 
  165. $results = $mapper->run_query(); 
  166. return $results; 
  167. /** 
  168. * Gets all gallery and album entities from albums specified, if any 
  169. * @param stdClass $source_obj 
  170. * @param int $limit 
  171. * @param int $offset 
  172. * @param boolean $id_only 
  173. * @param array $returns 
  174. */ 
  175. public function _get_album_and_gallery_entities($source_obj, $limit = FALSE, $offset = FALSE, $id_only = FALSE, $returns = 'included') 
  176. // Albums queries and difficult and inefficient to perform due to the 
  177. // database schema. To complicate things, we're returning two different 
  178. // types of entities - galleries, and sub-albums. 
  179. // The user prefixes entity_id's with an 'a' to distinguish album ids 
  180. // from gallery ids. E.g. entity_ids=[1, "a2", 3] 
  181. $album_mapper = C_Album_Mapper::get_instance(); 
  182. $album_key = $album_mapper->get_primary_key_column(); 
  183. $gallery_mapper = C_Gallery_Mapper::get_instance(); 
  184. $gallery_key = $gallery_mapper->get_primary_key_column(); 
  185. $select = $id_only ? $album_key . ', sortorder' : $album_mapper->get_table_name() . '.*'; 
  186. $retval = array(); 
  187. // If no exclusions are specified, are entity_ids are specified,  
  188. // and we're to return is "included", then we have a relatively easy 
  189. // query to perform - we just fetch each entity listed in 
  190. // the entity_ids field 
  191. if ($returns == 'included' && $this->object->entity_ids && empty($this->object->exclusions)) { 
  192. $retval = $this->object->_entities_to_galleries_and_albums($this->object->entity_ids, $id_only, array(), $limit, $offset); 
  193. } else { 
  194. // Start the query 
  195. $album_mapper->select($select); 
  196. // Fetch the albums, and find the entity ids of the sub-albums and galleries 
  197. $entity_ids = array(); 
  198. $excluded_ids = array(); 
  199. // Filter by container ids. If container_ids === '0' we retrieve all existing gallery_ids and use 
  200. // them as the available entity_ids for comparability with 1.9x 
  201. $container_ids = $this->object->container_ids; 
  202. if ($container_ids) { 
  203. if ($container_ids !== array('0') && $container_ids !== array('')) { 
  204. $album_mapper->where(array("{$album_key} IN %s", $container_ids)); 
  205. foreach ($album_mapper->run_query() as $album) { 
  206. $entity_ids = array_merge($entity_ids, (array) $album->sortorder); 
  207. } else { 
  208. if ($container_ids === array('0') || $container_ids === array('')) { 
  209. foreach ($gallery_mapper->select($gallery_key)->run_query() as $gallery) { 
  210. $entity_ids[] = $gallery->{$gallery_key}; 
  211. // Break the list of entities into two groups, included entities 
  212. // and excluded entity ids 
  213. // -- 
  214. // If a specific list of entity ids have been specified, then 
  215. // we know what entity ids are meant to be included. We can compute 
  216. // the intersect and also determine what entity ids are to be 
  217. // excluded 
  218. if ($this->object->entity_ids) { 
  219. // Determine the real list of included entity ids. Exclusions 
  220. // always take precedence 
  221. $included_ids = $this->object->entity_ids; 
  222. foreach ($this->object->exclusions as $excluded_id) { 
  223. if (($index = array_search($excluded_id, $included_ids)) !== FALSE) { 
  224. unset($included_ids[$index]); 
  225. $excluded_ids = array_diff($entity_ids, $included_ids); 
  226. } elseif ($this->object->exclusions) { 
  227. $included_ids = array_diff($entity_ids, $this->object->exclusions); 
  228. $excluded_ids = array_diff($entity_ids, $included_ids); 
  229. } else { 
  230. $included_ids = $entity_ids; 
  231. // We've built our two groups. Let's determine how we'll focus on them 
  232. // -- 
  233. // We're interested in only the included ids 
  234. if ($returns == 'included') { 
  235. $retval = $this->object->_entities_to_galleries_and_albums($included_ids, $id_only, array(), $limit, $offset); 
  236. } elseif ($returns == 'excluded') { 
  237. $retval = $this->object->_entities_to_galleries_and_albums($excluded_ids, $id_only, $excluded_ids, $limit, $offset); 
  238. } else { 
  239. $retval = $this->object->_entities_to_galleries_and_albums($entity_ids, $id_only, $excluded_ids, $limit, $offset); 
  240. return $retval; 
  241. /** 
  242. * Takes a list of entities, and returns the mapped galleries and sub-albums 
  243. * @param array $entity_ids 
  244. * @param bool $id_only 
  245. * @param array $exclusions 
  246. * @param int $limit 
  247. * @param int $offset 
  248. * @return array 
  249. */ 
  250. public function _entities_to_galleries_and_albums($entity_ids, $id_only = FALSE, $exclusions = array(), $limit = FALSE, $offset = FALSE) 
  251. $retval = array(); 
  252. $gallery_ids = array(); 
  253. $album_ids = array(); 
  254. $album_mapper = C_Album_Mapper::get_instance(); 
  255. $album_key = $album_mapper->get_primary_key_column(); 
  256. $gallery_mapper = C_Gallery_Mapper::get_instance(); 
  257. $image_mapper = C_Image_Mapper::get_instance(); 
  258. $gallery_key = $gallery_mapper->get_primary_key_column(); 
  259. $album_select = ($id_only ? $album_key : $album_mapper->get_table_name() . '.*') . ', 1 AS is_album, 0 AS is_gallery, name AS title, albumdesc AS galdesc'; 
  260. $gallery_select = ($id_only ? $gallery_key : $gallery_mapper->get_table_name() . '.*') . ', 1 AS is_gallery, 0 AS is_album'; 
  261. // Modify the sort order of the entities 
  262. if ($this->object->sortorder) { 
  263. $sortorder = array_intersect($this->object->sortorder, $entity_ids); 
  264. $entity_ids = array_merge($sortorder, array_diff($entity_ids, $sortorder)); 
  265. // Segment entity ids into two groups - galleries and albums 
  266. foreach ($entity_ids as $entity_id) { 
  267. if (substr($entity_id, 0, 1) == 'a') { 
  268. $album_ids[] = intval(substr($entity_id, 1)); 
  269. } else { 
  270. $gallery_ids[] = intval($entity_id); 
  271. // Adjust query to include an exclude property 
  272. if ($exclusions) { 
  273. $album_select = $this->object->_add_find_in_set_column($album_select, $album_key, $this->object->exclusions, 'exclude'); 
  274. $album_select = $this->object->_add_if_column($album_select, 'exclude', 0, 1); 
  275. $gallery_select = $this->object->_add_find_in_set_column($gallery_select, $gallery_key, $this->object->exclusions, 'exclude'); 
  276. $gallery_select = $this->object->_add_if_column($gallery_select, 'exclude', 0, 1); 
  277. // Add sorting parameter to the gallery and album queries 
  278. if ($gallery_ids) { 
  279. $gallery_select = $this->object->_add_find_in_set_column($gallery_select, $gallery_key, $gallery_ids, 'ordered_by', TRUE); 
  280. } else { 
  281. $gallery_select .= ', 0 AS ordered_by'; 
  282. if ($album_ids) { 
  283. $album_select = $this->object->_add_find_in_set_column($album_select, $album_key, $album_ids, 'ordered_by', TRUE); 
  284. } else { 
  285. $album_select .= ', 0 AS ordered_by'; 
  286. // Fetch entities 
  287. $galleries = $gallery_mapper->select($gallery_select)->where(array("{$gallery_key} IN %s", $gallery_ids))->order_by('ordered_by', 'DESC')->run_query(); 
  288. $counts = $image_mapper->select('galleryid, COUNT(*) as counter')->where(array(array('galleryid IN %s', $gallery_ids), array('exclude = %d', 0)))->group_by('galleryid')->run_query(FALSE, FALSE, TRUE); 
  289. $albums = $album_mapper->select($album_select)->where(array("{$album_key} IN %s", $album_ids))->order_by('ordered_by', 'DESC')->run_query(); 
  290. // Reorder entities according to order specified in entity_ids 
  291. foreach ($entity_ids as $entity_id) { 
  292. if (substr($entity_id, 0, 1) == 'a') { 
  293. $album = array_shift($albums); 
  294. if ($album) { 
  295. $retval[] = $album; 
  296. } else { 
  297. $gallery = array_shift($galleries); 
  298. if ($gallery) { 
  299. foreach ($counts as $id => $gal_count) { 
  300. if ($gal_count->galleryid == $gallery->gid) { 
  301. $gallery->counter = intval($gal_count->counter); 
  302. unset($counts[$id]); 
  303. $retval[] = $gallery; 
  304. // Sort the entities 
  305. if ($this->object->order_by && $this->object->order_by != 'sortorder') { 
  306. usort($retval, array(&$this, '_sort_album_result')); 
  307. if ($this->object->order_direction == 'DESC') { 
  308. $retval = array_reverse($retval); 
  309. // Limit the entities 
  310. if ($limit) { 
  311. $retval = array_slice($retval, $offset, $limit); 
  312. return $retval; 
  313. /** 
  314. * Returns the total number of entities in this displayed gallery 
  315. * @param string $returns 
  316. * @returns int 
  317. */ 
  318. public function get_entity_count($returns = 'included') 
  319. $retval = 0; 
  320. // Is this an image query? 
  321. $source_obj = $this->object->get_source(); 
  322. if (in_array('image', $source_obj->returns)) { 
  323. $retval = count($this->object->_get_image_entities($source_obj, FALSE, FALSE, TRUE, $returns)); 
  324. } elseif (in_array('gallery', $source_obj->returns)) { 
  325. $retval = count($this->object->_get_album_and_gallery_entities($source_obj, FALSE, FALSE, TRUE, $returns)); 
  326. $max = $this->get_maximum_entity_count(); 
  327. if ($retval > $max) { 
  328. $retval = $max; 
  329. return $retval; 
  330. // Honor the gallery 'maximum_entity_count' setting ONLY when dealing with random & recent galleries. All 
  331. // others will always obey the *global* 'maximum_entity_count' setting. 
  332. public function get_maximum_entity_count() 
  333. $max = intval(C_NextGen_Settings::get_instance()->get('maximum_entity_count', 500)); 
  334. $sources = C_Displayed_Gallery_Source_Manager::get_instance(); 
  335. $source_obj = $this->object->get_source(); 
  336. if (in_array($source_obj, array($sources->get('random'), $sources->get('random_images'), $sources->get('recent'), $sources->get('recent_images')))) { 
  337. $max = intval($this->object->maximum_entity_count); 
  338. return $max; 
  339. /** 
  340. * Returns all included entities for the displayed gallery 
  341. * @param int $limit 
  342. * @param int $offset 
  343. * @param boolean $id_only 
  344. * @return array 
  345. */ 
  346. public function get_included_entities($limit = FALSE, $offset = FALSE, $id_only = FALSE) 
  347. return $this->object->get_entities($limit, $offset, $id_only, 'included'); 
  348. /** 
  349. * Adds a FIND_IN_SET call to the select portion of the query, and 
  350. * optionally defines a dynamic column 
  351. * @param string $select 
  352. * @param string $key 
  353. * @param array $array 
  354. * @param string $alias 
  355. * @param boolean $add_column 
  356. * @return string 
  357. */ 
  358. public function _add_find_in_set_column($select, $key, $array, $alias, $add_column = FALSE) 
  359. $array = array_map('intval', $array); 
  360. $set = implode(', ', array_reverse($array)); 
  361. if (!$select) { 
  362. $select = '1'; 
  363. $select .= ", @{$alias} := FIND_IN_SET({$key}, '{$set}')"; 
  364. if ($add_column) { 
  365. $select .= " AS {$alias}"; 
  366. return $select; 
  367. public function _add_if_column($select, $alias, $true = 1, $false = 0) 
  368. if (!$select) { 
  369. $select = '1'; 
  370. $select .= ", IF(@{$alias} = 0, {$true}, {$false}) AS {$alias}"; 
  371. return $select; 
  372. /** 
  373. * Parses the list of parameters provided in the displayed gallery, and 
  374. * ensures everything meets expectations 
  375. * @return boolean 
  376. */ 
  377. public function _parse_parameters() 
  378. $valid = FALSE; 
  379. // Ensure that the source is valid 
  380. if (C_Displayed_Gallery_Source_Manager::get_instance()->get($this->object->source)) { 
  381. $valid = TRUE; 
  382. // Ensure that exclusions, entity_ids, and sortorder have valid elements. 
  383. // IE likes to send empty array as an array with a single element that 
  384. // has no value 
  385. if ($this->object->exclusions && !$this->object->exclusions[0]) { 
  386. $this->object->exclusions = array(); 
  387. if ($this->object->entity_ids && !$this->object->entity_ids[0]) { 
  388. $this->object->entity_ids = array(); 
  389. if ($this->object->sortorder && !$this->object->sortorder[0]) { 
  390. $this->object->sortorder = array(); 
  391. return $valid; 
  392. /** 
  393. * Returns a list of term ids for the list of tags 
  394. * @global wpdb $wpdb 
  395. * @param array $tags 
  396. * @return array 
  397. */ 
  398. public function get_term_ids_for_tags($tags = FALSE) 
  399. global $wpdb; 
  400. // If no tags were provided, get them from the container_ids 
  401. if (!$tags || !is_array($tags)) { 
  402. $tags = $this->object->container_ids; 
  403. // Convert container ids to a string suitable for WHERE IN 
  404. $container_ids = array(); 
  405. if (is_array($tags) && !in_array('all', array_map('strtolower', $tags))) { 
  406. foreach ($tags as $ndx => $container) { 
  407. $container_ids[] = "'{$container}'"; 
  408. $container_ids = implode(', ', $container_ids); 
  409. // Construct query 
  410. $query = "SELECT {$wpdb->term_taxonomy}.term_id FROM {$wpdb->term_taxonomy}\n INNER JOIN {$wpdb->terms} ON {$wpdb->term_taxonomy}.term_id = {$wpdb->terms}.term_id\n WHERE {$wpdb->term_taxonomy}.term_id = {$wpdb->terms}.term_id\n AND {$wpdb->term_taxonomy}.taxonomy = %s"; 
  411. if (!empty($container_ids)) { 
  412. $query .= " AND ({$wpdb->terms}.slug IN ({$container_ids}) OR {$wpdb->terms}.name IN ({$container_ids}))"; 
  413. $query .= " ORDER BY {$wpdb->terms}.term_id"; 
  414. $query = $wpdb->prepare($query, 'ngg_tag'); 
  415. // Get all term_ids for each image tag slug 
  416. $term_ids = array(); 
  417. $results = $wpdb->get_results($query); 
  418. if (is_array($results) && !empty($results)) { 
  419. foreach ($results as $row) { 
  420. $term_ids[] = $row->term_id; 
  421. return $term_ids; 
  422. /** 
  423. * Sorts the results of an album query 
  424. * @param stdClass $a 
  425. * @param stdClass $b 
  426. */ 
  427. public function _sort_album_result($a, $b) 
  428. $key = $this->object->order_by; 
  429. return strcmp($a->{$key}, $b->{$key});