be163442faff5602f3a3caba88899629e194ad21
[web/PetoskeyRobotics.git] /
1 <?php
2
3 /**
4  * Associates a Display Type with a collection of images
5  *
6  * * Properties:
7  * - source                             (gallery, album, recent_images, random_images, etc)
8  * - container_ids              (gallery ids, album ids, tag ids, etc)
9  * - display_type               (name of the display type being used)
10  * - display_settings   (settings for the display type)
11  * - exclusions                 (excluded entity ids)
12  * - entity_ids                 (specific images/galleries to include, sorted)
13  * - order_by
14  * - order_direction
15  */
16 class C_Displayed_Gallery extends C_DataMapper_Model
17 {
18         var $_mapper_interface = 'I_Displayed_Gallery_Mapper';
19
20         function define($properties=array(), $mapper=FALSE, $context=FALSE)
21         {
22                 parent::define($mapper, $properties, $context);
23                 $this->add_mixin('Mixin_Displayed_Gallery_Validation');
24                 $this->add_mixin('Mixin_Displayed_Gallery_Instance_Methods');
25                 $this->add_mixin('Mixin_Displayed_Gallery_Queries');
26                 $this->implement('I_Displayed_Gallery');
27         }
28
29
30         /**
31          * Initializes a display type with properties
32          * @param FALSE|C_Displayed_Gallery_Mapper $mapper
33          * @param array|stdClass|C_Displayed_Gallery $properties
34          * @param FALSE|string|array $context
35          */
36         function initialize($properties=array(), $mapper=FALSE, $context=FALSE)
37         {
38                 if (!$mapper) $mapper = $this->get_registry()->get_utility($this->_mapper_interface);
39                 parent::initialize($mapper, $properties);
40
41                 $this->select_random_variation();
42         }
43 }
44
45 /**
46  * Provides validation
47  */
48 class Mixin_Displayed_Gallery_Validation extends Mixin
49 {
50         function validation()
51         {
52                 // Valid sources
53                 $this->object->validates_presence_of('source');
54
55                 // Valid display type?
56                 $this->object->validates_presence_of('display_type');
57                 if (($display_type = $this->object->get_display_type())) {
58                         $display_type->settings = $this->object->display_settings;
59                         if (!$display_type->validate()) {
60                                 foreach ($display_type->get_errors() as $property => $errors) {
61                                         foreach ($errors as $error) {
62                                                 $this->object->add_error($error, $property);
63                                         }
64                                 }
65                         }
66
67                         // Is the display type compatible with the source? E.g., if we're
68                         // using a display type that expects images, we can't be feeding it
69                         // galleries and albums
70                         if (($source = $this->object->get_source())) {
71                                 if (!$display_type->is_compatible_with_source($source)) {
72                                         $this->object->add_error(
73                                                 _('Source not compatible with selected display type'),
74                                                 'display_type'
75                                         );
76                                 }
77                         }
78
79             // Allow ONLY recent & random galleries to have their own maximum_entity_count
80             if (!empty($this->object->display_settings['maximum_entity_count'])
81             &&  in_array($this->object->source, array('random_images', 'recent_images', 'random', 'recent'))) {
82                 $this->object->maximum_entity_count = $this->object->display_settings['maximum_entity_count'];
83             }
84
85             // If no maximum_entity_count has been given, then set a maximum
86                         if (!isset($this->object->maximum_entity_count))
87                         {
88                                 $this->object->maximum_entity_count = C_Photocrati_Settings_Manager::get('maximum_entity_count', 500);
89                         }
90                 }
91                 else {
92                         $this->object->add_error('Invalid display type', 'display_type');
93                 }
94
95                 return $this->object->is_valid();
96         }
97 }
98
99 class Mixin_Displayed_Gallery_Queries extends Mixin
100 {
101         function select_random_variation()
102         {
103                 $retval = FALSE;
104
105                 $source_obj = $this->object->get_source();
106                 if ($source_obj && $source_obj->has_variations) {
107                         $max = 0;
108                         if (!defined('NGG_MAX_VARIATIONS')) {
109                                 $settings = C_Photocrati_Global_Settings_Manager::get_instance();
110                                 $max = $settings->get('max_variations', 5);
111                                 define('NGG_MAX_VARIATIONS', $max);
112                         }
113                         else $max = NGG_MAX_VARIATIONS;
114
115                         $this->object->variation = floor(rand(1, $max));
116
117                         $retval = $this->object->variation;
118                 }
119
120                 return $retval;
121         }
122
123         function get_entities($limit=FALSE, $offset=FALSE, $id_only=FALSE, $returns='included')
124         {
125                 $retval = array();
126
127         // Honor the gallery 'maximum_entity_count' setting ONLY when dealing with random & recent galleries. All
128         // others will always obey the *global* 'maximum_entity_count' setting.
129         if (in_array($this->object->get_source()->name, array('random_images', 'recent_images', 'random', 'recent')))
130             $max = intval($this->object->maximum_entity_count);
131                 else
132             $max = intval(C_NextGen_Settings::get_instance()->get('maximum_entity_count', 500));
133
134         if (!$limit || (is_numeric($limit) && $limit > $max))
135             $limit = $max;
136
137                 // Ensure that all parameters have values that are expected
138                 if ($this->object->_parse_parameters())
139         {
140                         // Is this an image query?
141                         $source_obj = $this->object->get_source();
142                         if (in_array('image', $source_obj->returns)) {
143                                 $retval = $this->object->_get_image_entities($source_obj, $limit, $offset, $id_only, $returns);
144                         }
145
146                         // Is this a gallery/album query?
147                         elseif (in_array('gallery', $source_obj->returns)) {
148                                 $retval = $this->object->_get_album_and_gallery_entities($source_obj, $limit, $offset, $id_only, $returns);
149                         }
150                 }
151
152                 return $retval;
153         }
154
155         /**
156          * Gets all images in the displayed gallery
157          * @param C_Displayed_Gallery_Source $source_obj
158          * @param int $limit
159          * @param int $offset
160          * @param boolean $id_only
161          * @param string $returns
162          */
163         function _get_image_entities($source_obj, $limit, $offset, $id_only, $returns)
164         {
165                 // TODO: This method is very long, and therefore more difficult to read
166                 // Find a way to minimalize or segment
167                 $mapper = $this->get_registry()->get_utility('I_Image_Mapper');
168                 $image_key              = $mapper->get_primary_key_column();
169                 $select                 = $id_only ? $image_key : $mapper->get_table_name().'.*';
170                 $sort_direction = $this->object->order_direction;
171                 $sort_by                = $this->object->order_by;
172
173                 // Here's what this method is doing:
174                 // 1) Determines what results need returned
175                 // 2) Determines from what container ids the results should come from
176                 // 3) Applies ORDER BY clause
177                 // 4) Applies LIMIT/OFFSET clause
178                 // 5) Executes the query and returns the result
179
180                 // We start with the most difficult query. When returns is "both", we
181                 // need to return a list of both included and excluded entity ids, and
182                 // mark specifically which entities are excluded
183                 if ($returns == 'both') {
184
185                         // We need to add two dynamic columns, one called "sortorder" and
186                         // the other called "exclude".
187                         $if_true                = 1;
188                         $if_false               = 0;
189                         $excluded_set   = $this->object->entity_ids;
190                         if (!$excluded_set) {
191                                 $if_true        = 0;
192                                 $if_false       = 1;
193                                 $excluded_set = $this->object->exclusions;
194                         }
195                         $sortorder_set  = $this->object->sortorder ? $this->object->sortorder :  $excluded_set;
196
197                         // Add sortorder column
198                         if ($sortorder_set) {
199                                 $select = $this->object->_add_find_in_set_column(
200                                         $select,
201                                         $image_key,
202                                         $sortorder_set,
203                                         'new_sortorder',
204                                         TRUE
205                                 );
206                                 // A user might want to sort the results by the order of
207                                 // images that they specified to be included. For that,
208                                 // we need some trickery by reversing the order direction
209                                 $sort_direction = $this->object->order_direction == 'ASC' ? 'DESC' : 'ASC';
210                                 $sort_by = 'new_sortorder';
211                         }
212
213                         // Add exclude column
214                         if ($excluded_set) {
215                                 $select = $this->object->_add_find_in_set_column(
216                                         $select,
217                                         $image_key,
218                                         $excluded_set,
219                                         'exclude'
220                                 );
221                                 $select .= ", IF (exclude = 0 AND @exclude = 0, $if_true, $if_false) AS 'exclude'";
222                         }
223
224                         // Select what we want
225                         $mapper->select($select);
226                 }
227
228                 // When returns is "included", the query is relatively simple. We
229                 // just provide a where clause to limit how many images we're returning
230                 // based on the entity_ids, exclusions, and container_ids parameters
231                 if ($returns == 'included') {
232
233                         // If the sortorder propery is available, then we need to override
234                         // the sortorder
235                         if ($this->object->sortorder) {
236                                 $select = $this->object->_add_find_in_set_column(
237                                         $select,
238                                         $image_key,
239                                         $this->object->sortorder,
240                                         'new_sortorder',
241                                         TRUE
242                                 );
243                                 $sort_direction = $this->object->order_direction == 'ASC' ? 'DESC' : 'ASC';
244                                 $sort_by = 'new_sortorder';
245                         }
246                         $mapper->select($select);
247
248                         // Filter based on entity_ids selection
249                         if ($this->object->entity_ids) {
250                                 $mapper->where(array("{$image_key} IN %s", $this->object->entity_ids));
251                         }
252
253                         // Filter based on exclusions selection
254                         if ($this->object->exclusions) {
255                                 $mapper->where(array("{$image_key} NOT IN %s", $this->object->exclusions));
256                         }
257
258                         // Ensure that no images marked as excluded at the gallery level are
259                         // returned
260                         $mapper->where(array("exclude = %d", 0));
261                 }
262
263                 // When returns is "excluded", it's a little more complicated as the
264                 // query is the negated form of the "included". entity_ids become the
265                 // list of exclusions, and exclusions become the list of entity_ids to
266                 // return. All results we return must be marked as excluded
267                 elseif ($returns == 'excluded') {
268
269                         // If the sortorder propery is available, then we need to override
270                         // the sortorder
271                         if ($this->object->sortorder) {
272                                 $select = $this->object->_add_find_in_set_column(
273                                         $select,
274                                         $image_key,
275                                         $this->object->sortorder,
276                                         'new_sortorder',
277                                         TRUE
278                                 );
279                                 $sort_direction = $this->object->order_direction == 'ASC' ? 'DESC' : 'ASC';
280                                 $sort_by = 'new_sortorder';
281                         }
282
283                         // Mark each result as excluded
284                         $select .= ", 1 AS exclude";
285                         $mapper->select($select);
286
287                         // Is this case, entity_ids become the exclusions
288                         $exclusions = $this->object->entity_ids;
289
290                         // Remove the exclusions always takes precedence over entity_ids, so
291                         // we adjust the list of ids
292                         if ($this->object->exclusions) foreach ($this->object->exclusions as $excluded_entity_id) {
293                                 if (($index = array_search($excluded_entity_id, $exclusions)) !== FALSE) {
294                                         unset($exclusions[$index]);
295                                 }
296                         }
297
298                         // Filter based on exclusions selection
299                         if ($exclusions) {
300                                 $mapper->where(array("{$image_key} NOT IN %s", $exclusions));
301                         }
302
303                         // Filter based on selected exclusions
304                         else if ($this->object->exclusions) {
305                                 $mapper->where(array("{$image_key} IN %s", $this->object->exclusions));
306                         }
307
308                         // Ensure that images marked as excluded are returned as well
309                         $mapper->where(array("exclude = 1"));
310                 }
311
312                 // Filter based on containers_ids. Container ids is a little more
313                 // complicated as it can contain gallery ids or tags
314                 if ($this->object->container_ids) {
315
316                         // Container ids are tags
317                         if ($source_obj->name == 'tags') {
318                                 $term_ids = $this->object->get_term_ids_for_tags($this->object->container_ids);
319                                 $mapper->where(array("{$image_key} IN %s",get_objects_in_term($term_ids, 'ngg_tag')));
320                         }
321
322                         // Container ids are gallery ids
323                         else {
324                                 $mapper->where(array("galleryid IN %s", $this->object->container_ids));
325                         }
326                 }
327
328                 // Filter based on excluded container ids
329                 if ($this->object->excluded_container_ids) {
330
331                         // Container ids are tags
332                         if ($source_obj->name == 'tags') {
333                                 $term_ids = $this->object->get_term_ids_for_tags($this->object->excluded_container_ids);
334                                 $mapper->where(array("{$image_key} NOT IN %s",get_objects_in_term($term_ids, 'ngg_tag')));
335                         }
336
337                         // Container ids are gallery ids
338                         else {
339                                 $mapper->where(array("galleryid NOT IN %s", $this->object->excluded_container_ids));
340                         }
341                 }
342
343                 // Adjust the query more based on what source was selected
344                 if ($this->object->source == 'recent_images') {
345                         $sort_direction = 'DESC';
346                         $sort_by = 'imagedate';
347                 }
348         // If the source is random but entity_ids are present we assume that this is a temporary/"fake" random
349         // gallery created by randomly selecting X image ids that are then set as the gallery entity_ids
350                 elseif ($this->object->source == 'random_images' && empty($this->object->entity_ids)) {
351             $table_name = $mapper->get_table_name();
352             $mapper->_where_clauses[] = " /*NGG_NO_EXTRAS_TABLE*/ `{$image_key}` IN (SELECT `{$image_key}` FROM (SELECT `{$image_key}` FROM `{$table_name}` i ORDER BY RAND() LIMIT {$this->object->maximum_entity_count}) o) /*NGG_NO_EXTRAS_TABLE*/";
353                 }
354
355                 // Apply a sorting order
356                 if ($sort_by)  $mapper->order_by($sort_by, $sort_direction);
357
358                 // Apply a limit
359                 if ($limit) {
360                         if ($offset) $mapper->limit($limit, $offset);
361                         else             $mapper->limit($limit);
362                 }
363
364                 $results = $mapper->run_query();
365
366                 return $results;
367         }
368
369         /**
370          * Gets all gallery and album entities from albums specified, if any
371          * @param C_Displayed_Gallery_Source $source_obj
372          * @param int $limit
373          * @param int $offset
374          * @param boolean $id_only
375          * @param array $returns
376          */
377         function _get_album_and_gallery_entities($source_obj, $limit=FALSE, $offset=FALSE, $id_only=FALSE, $returns='included')
378         {
379                 // Albums queries and difficult and inefficient to perform due to the
380                 // database schema. To complicate things, we're returning two different
381                 // types of entities - galleries, and sub-albums.
382                 // The user prefixes entity_id's with an 'a' to distinguish album ids
383                 // from gallery ids. E.g. entity_ids=[1, "a2", 3]
384                 $album_mapper   = $this->get_registry()->get_utility('I_Album_Mapper');
385                 $album_key              = $album_mapper->get_primary_key_column();
386                 $gallery_mapper = $this->get_registry()->get_utility('I_Gallery_Mapper');
387                 $gallery_key    = $gallery_mapper->get_primary_key_column();
388                 $select                 = $id_only ? $album_key.", sortorder" : $album_mapper->get_table_name().'.*';
389                 $retval                 = array();
390
391                 // If no exclusions are specified, are entity_ids are specified,
392                 // and we're to return is "included", then we have a relatively easy
393                 // query to perform - we just fetch each entity listed in
394                 // the entity_ids field
395                 if ($returns == 'included' && $this->object->entity_ids && empty($this->object->exclusions)) {
396                         $retval = $this->object->_entities_to_galleries_and_albums(
397                                 $this->object->entity_ids, $id_only, array(), $limit, $offset
398                         );
399                 }
400
401                 // It's not going to be easy. We'll start by fetching the albums
402                 // and retrieving each of their entities
403                 else {
404                         // Start the query
405                         $album_mapper->select($select);
406
407             // Fetch the albums, and find the entity ids of the sub-albums and galleries
408             $entity_ids   = array();
409             $excluded_ids = array();
410
411                         // Filter by container ids. If container_ids === '0' we retrieve all existing gallery_ids and use
412             // them as the available entity_ids for comparability with 1.9x
413             $container_ids = $this->object->container_ids;
414                         if ($container_ids)
415             {
416                 if ($container_ids !== array('0') && $container_ids !== array(''))
417                 {
418                     $album_mapper->where(array("{$album_key} IN %s", $container_ids));
419                     foreach ($album_mapper->run_query() as $album) {
420                         $entity_ids = array_merge($entity_ids, (array) $album->sortorder);
421                     }
422                 }
423                 else if ($container_ids === array('0') || $container_ids === array('')) {
424                     foreach ($gallery_mapper->select($gallery_key)->run_query() as $gallery) {
425                         $entity_ids[] = $gallery->$gallery_key;
426                     }
427                 }
428                         }
429
430                         // Break the list of entities into two groups, included entities
431                         // and excluded entity ids
432                         // --
433                         // If a specific list of entity ids have been specified, then
434                         // we know what entity ids are meant to be included. We can compute
435                         // the intersect and also determine what entity ids are to be
436                         // excluded
437                         if ($this->object->entity_ids) {
438
439                                 // Determine the real list of included entity ids. Exclusions
440                                 // always take precedence
441                                 $included_ids = $this->object->entity_ids;
442                                 foreach ($this->object->exclusions as $excluded_id) {
443                                         if (($index = array_search($excluded_id, $included_ids)) !== FALSE) {
444                                                 unset($included_ids[$index]);
445                                         }
446                                 }
447                                 $excluded_ids = array_diff($entity_ids, $included_ids);
448                         }
449
450                         // We only have a list of exclusions.
451                         elseif ($this->object->exclusions) {
452                                 $included_ids = array_diff($entity_ids, $this->object->exclusions);
453                                 $excluded_ids = array_diff($entity_ids, $included_ids);
454                         }
455
456                         // We have no entity ids and no exclusions
457                         else {
458                                 $included_ids = $entity_ids;
459                         }
460
461                         // We've built our two groups. Let's determine how we'll focus on them
462                         // --
463                         // We're interested in only the included ids
464                         if ($returns == 'included')
465                                 $retval = $this->object->_entities_to_galleries_and_albums(
466                     $included_ids,
467                     $id_only,
468                     array(),
469                     $limit,
470                     $offset
471                 );
472
473                         // We're interested in only the excluded ids
474                         elseif ($returns == 'excluded')
475                                 $retval = $this->object->_entities_to_galleries_and_albums(
476                     $excluded_ids,
477                     $id_only,
478                     $excluded_ids,
479                     $limit,
480                     $offset
481                 );
482
483                         // We're interested in both groups
484                         else {
485                                 $retval = $this->object->_entities_to_galleries_and_albums(
486                     $entity_ids,
487                     $id_only,
488                     $excluded_ids,
489                     $limit,
490                     $offset
491                 );
492                         }
493                 }
494
495                 return $retval;
496         }
497
498         /**
499          * Takes a list of entities, and returns the mapped galleries and sub-albums
500      *
501          * @param array $entity_ids
502      * @param bool $id_only
503      * @param array $exclusions
504      * @param int $limit
505      * @param int $offset
506          * @return array
507          */
508         function _entities_to_galleries_and_albums($entity_ids,
509                                                $id_only = FALSE,
510                                                $exclusions = array(),
511                                                $limit = FALSE,
512                                                $offset = FALSE)
513         {
514                 $retval                 = array();
515                 $gallery_ids    = array();
516                 $album_ids              = array();
517                 $album_mapper   = $this->get_registry()->get_utility('I_Album_Mapper');
518                 $album_key              = $album_mapper->get_primary_key_column();
519                 $gallery_mapper = $this->get_registry()->get_utility('I_Gallery_Mapper');
520                 $image_mapper = $this->object->get_registry()->get_utility('I_Image_Mapper');
521                 $gallery_key    = $gallery_mapper->get_primary_key_column();
522                 $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";
523                 $gallery_select = ($id_only ? $gallery_key : $gallery_mapper->get_table_name().'.*').", 1 AS is_gallery, 0 AS is_album";
524
525                 // Modify the sort order of the entities
526                 if ($this->object->sortorder) {
527                         $sortorder = array_intersect($this->object->sortorder, $entity_ids);
528                         $entity_ids = array_merge($sortorder,array_diff($entity_ids, $sortorder));
529                 }
530
531                 // Segment entity ids into two groups - galleries and albums
532                 foreach ($entity_ids as $entity_id) {
533                         if (substr($entity_id, 0, 1) == 'a')
534                                 $album_ids[]    = intval(substr($entity_id, 1));
535                         else
536                                 $gallery_ids[]  = intval($entity_id);
537                 }
538
539                 // Adjust query to include an exclude property
540                 if ($exclusions) {
541                         $album_select = $this->object->_add_find_in_set_column(
542                                 $album_select,
543                                 $album_key,
544                                 $this->object->exclusions,
545                                 'exclude'
546                         );
547                         $album_select = $this->object->_add_if_column(
548                                 $album_select,
549                                 'exclude',
550                                 0,
551                                 1
552                         );
553                         $gallery_select = $this->object->_add_find_in_set_column(
554                                 $gallery_select,
555                                 $gallery_key,
556                                 $this->object->exclusions,
557                                 'exclude'
558                         );
559                         $gallery_select = $this->object->_add_if_column(
560                                 $gallery_select,
561                                 'exclude',
562                                 0,
563                                 1
564                         );
565                 }
566
567                 // Add sorting parameter to the gallery and album queries
568                 if ($gallery_ids) {
569                         $gallery_select = $this->object->_add_find_in_set_column(
570                                 $gallery_select,
571                                 $gallery_key,
572                                 $gallery_ids,
573                                 'ordered_by',
574                                 TRUE
575                         );
576                 }
577                 else {
578                         $gallery_select .= ", 0 AS ordered_by";
579                 }
580                 if ($album_ids) {
581                         $album_select = $this->object->_add_find_in_set_column(
582                                 $album_select,
583                                 $album_key,
584                                 $album_ids,
585                                 'ordered_by',
586                                 TRUE
587                         );
588                 }
589                 else {
590                         $album_select .= ", 0 AS ordered_by";
591                 }
592
593                 // Fetch entities
594                 $galleries      = $gallery_mapper->select($gallery_select)->where(
595                         array("{$gallery_key} IN %s", $gallery_ids)
596                 )->order_by('ordered_by', 'DESC')->run_query();
597                 $counts = $image_mapper->select('galleryid, COUNT(*) as counter')->where(
598                         array("galleryid IN %s", $gallery_ids))->group_by('galleryid')->run_query(FALSE, TRUE);
599                 $albums         = $album_mapper->select($album_select)->where(
600                         array("{$album_key} IN %s", $album_ids)
601                 )->order_by('ordered_by', 'DESC')->run_query();
602
603                 // Reorder entities according to order specified in entity_ids
604                 foreach ($entity_ids as $entity_id) {
605                         if (substr($entity_id, 0, 1) == 'a') {
606                 $album = array_shift($albums);
607                 if ($album) $retval[] = $album;
608             }
609
610                         else {
611                 $gallery = array_shift($galleries);
612                 if ($gallery) {
613                         foreach ($counts as $id => $gal_count) {
614                                 if ($gal_count->galleryid == $gallery->gid) {
615                                         $gallery->counter = intval($gal_count->counter);
616                                         unset($counts[$id]);
617                                 }
618                         }
619
620                         $retval[] = $gallery;
621                 }
622             }
623
624                 }
625
626                 // Sort the entities
627                 if ($this->object->order_by && $this->object->order_by != 'sortorder')
628                         usort($retval, array(&$this, '_sort_album_result'));
629                 if ($this->object->order_direction == 'DESC')
630                         $retval = array_reverse($retval);
631
632                 // Limit the entities
633                 if ($limit && $offset)
634                         $retval = array_slice($retval, $offset, $limit);
635
636                 return $retval;
637         }
638
639         /**
640          * Returns the total number of entities in this displayed gallery
641          * @param string $returns
642          * @returns int
643          */
644         function get_entity_count($returns='included')
645         {
646         $retval = 0;
647
648                 // Is this an image query?
649                 $source_obj = $this->object->get_source();
650                 if (in_array('image', $source_obj->returns)) {
651                         $retval =  count($this->object->_get_image_entities($source_obj, FALSE, FALSE, TRUE, $returns));
652                 }
653
654                 // Is this a gallery/album query?
655                 elseif (in_array('gallery', $source_obj->returns)) {
656                         $retval = count($this->object->_get_album_and_gallery_entities($source_obj, FALSE, FALSE, TRUE, $returns));
657                 }
658
659         // Determine the correct maximum_entity_count
660         if (in_array($this->object->get_source()->name, array('random_images', 'recent_images', 'random', 'recent')))
661             $max = intval($this->object->maximum_entity_count);
662         else
663             $max = intval(C_NextGen_Settings::get_instance()->get('maximum_entity_count', 500));
664
665         if ($retval > $max) {
666                 $retval = $max;
667         }
668
669         return $retval;
670         }
671
672         /**
673          * Returns all included entities for the displayed gallery
674          * @param int $limit
675          * @param int $offset
676          * @param boolean $id_only
677          * @return array
678          */
679         function get_included_entities($limit=FALSE, $offset=FALSE, $id_only=FALSE)
680         {
681                 return $this->object->get_entities($limit, $offset, $id_only, 'included');
682         }
683
684         /**
685          * Adds a FIND_IN_SET call to the select portion of the query, and
686          * optionally defines a dynamic column
687          * @param string $select
688          * @param string $key
689          * @param array $array
690          * @param string $alias
691          * @param boolean $add_column
692          * @return string
693          */
694         function _add_find_in_set_column($select, $key, $array, $alias, $add_column=FALSE)
695         {
696                 $set = implode(",", array_reverse($array));
697                 if (!$select) $select = "1";
698                 $select .= ", @{$alias} := FIND_IN_SET({$key}, '{$set}')";
699                 if ($add_column) $select .= " AS {$alias}";
700                 return $select;
701         }
702
703
704         function _add_if_column($select, $alias, $true=1, $false=0)
705         {
706                 if (!$select) $select = "1";
707                 $select .= ", IF(@{$alias} = 0, {$true}, {$false}) AS {$alias}";
708                 return $select;
709         }
710
711         /**
712          * Returns a list of valid source names, paired with the name of the
713          * underlying true source name
714          * @return array
715          */
716         function _get_source_map()
717         {
718                 $sources = array();
719                 $mapper = $this->get_registry()->get_utility('I_Displayed_Gallery_Source_Mapper');
720                 foreach ($mapper->find_all() as $entity) {
721                         $sources[$entity->name] = $entity->name;
722                         foreach ($entity->aliases as $alias) $sources[$alias] = $entity->name;
723                 }
724                 return $sources;
725         }
726
727         /**
728          * Parses the list of parameters provided in the displayed gallery, and
729          * ensures everything meets expectations
730          * @return boolean
731          */
732         function _parse_parameters()
733         {
734                 $valid = FALSE;
735
736                 // Ensure that the source is valid
737                 $sources = $this->object->_get_source_map();
738                 if (isset($sources[$this->object->source])) {
739                         $this->object->source = $sources[$this->object->source];
740                         $valid = TRUE;
741                 }
742
743                 // Ensure that exclusions, entity_ids, and sortorder have valid elements.
744                 // IE likes to send empty array as an array with a single element that
745                 // has no value
746                 if ($this->object->exclusions && !$this->object->exclusions[0]) {
747                         $this->object->exclusions = array();
748                 }
749                 if ($this->object->entity_ids && !$this->object->entity_ids[0]) {
750                         $this->object->entity_ids = array();
751                 }
752                 if ($this->object->sortorder && !$this->object->sortorder[0]) {
753                         $this->object->sortorder = array();
754                 }
755
756                 return $valid;
757         }
758
759         /**
760          * Returns a list of term ids for the list of tags
761          * @global wpdb $wpdb
762          * @param array $tags
763          * @return array
764          */
765         function get_term_ids_for_tags($tags=FALSE)
766         {
767                 global $wpdb;
768
769         // If no tags were provided, get them from the container_ids
770         if (!$tags || !is_array($tags)) $tags = $this->object->container_ids;
771
772                 // Convert container ids to a string suitable for WHERE IN
773                 $container_ids = array();
774         if (is_array($tags) && !in_array('all', array_map('strtolower', $tags))) {
775                         foreach ($tags as $ndx => $container) {
776                                 $container_ids[]= "'{$container}'";
777                         }
778                         $container_ids = implode(',', $container_ids);
779                 }
780
781                 // Construct query
782         $query = "SELECT {$wpdb->term_taxonomy}.term_id FROM {$wpdb->term_taxonomy}
783                   INNER JOIN {$wpdb->terms} ON {$wpdb->term_taxonomy}.term_id = {$wpdb->terms}.term_id
784                   WHERE {$wpdb->term_taxonomy}.term_id = {$wpdb->terms}.term_id
785                   AND {$wpdb->term_taxonomy}.taxonomy = %s";
786         if (!empty($container_ids))
787             $query .= " AND ({$wpdb->terms}.slug IN ({$container_ids}) OR {$wpdb->terms}.name IN ({$container_ids}))";
788         $query .= " ORDER BY {$wpdb->terms}.term_id";
789         $query = $wpdb->prepare($query, 'ngg_tag');
790
791                 // Get all term_ids for each image tag slug
792                 $term_ids = array();
793         $results = $wpdb->get_results($query);
794         if (is_array($results) && !empty($results))
795         {
796             foreach ($results as $row) {
797                 $term_ids[] = $row->term_id;
798             }
799         }
800
801                 return $term_ids;
802         }
803
804
805         /**
806          * Sorts the results of an album query
807          * @param stdClass $a
808          * @param stdClass $b
809          */
810         function _sort_album_result($a, $b)
811         {
812                 $key = $this->object->order_by;
813                 return strcmp($a->$key, $b->$key);
814         }
815 }
816
817 /**
818  * Provides instance methods useful for working with the C_Displayed_Gallery
819  * model
820  */
821 class Mixin_Displayed_Gallery_Instance_Methods extends Mixin
822 {
823         function get_entity()
824         {
825                 $entity = $this->call_parent('get_entity');
826                 unset($entity->post_author);
827                 unset($entity->post_date);
828                 unset($entity->post_date_gmt);
829                 unset($entity->post_title);
830                 unset($entity->post_excerpt);
831                 unset($entity->post_status);
832                 unset($entity->comment_status);
833                 unset($entity->ping_status);
834                 unset($entity->post_name);
835                 unset($entity->to_ping);
836                 unset($entity->pinged);
837                 unset($entity->post_modified);
838                 unset($entity->post_modified_gmt);
839                 unset($entity->post_parent);
840                 unset($entity->guid);
841                 unset($entity->post_type);
842                 unset($entity->post_mime_type);
843                 unset($entity->comment_count);
844                 unset($entity->filter);
845                 unset($entity->post_content_filtered);
846
847                 return $entity;
848         }
849
850
851         /**
852          * Gets the display type object used in this displayed gallery
853          * @return C_Display_Type
854          */
855         function get_display_type()
856         {
857                 $mapper = $this->object->get_registry()->get_utility('I_Display_Type_Mapper');
858                 return  $mapper->find_by_name($this->object->display_type, TRUE);
859         }
860
861         /**
862          * Gets the corresponding source instance
863          * @return C_Displayed_Gallery_Source
864          */
865         function get_source()
866         {
867                 $retval = NULL;
868                 $sources = $this->object->_get_source_map();
869                 if (isset($sources[$this->object->source])) {
870                         $mapper = $this->get_registry()->get_utility('I_Displayed_Gallery_Source_Mapper');
871                         $retval = $mapper->find_by_name($sources[$this->object->source], TRUE);
872                 }
873
874                 return $retval;
875         }
876
877         /**
878          * Returns the galleries queries in this displayed gallery
879          * @return array
880          */
881         function get_galleries()
882         {
883                 $retval = array();
884                 if (($source = $this->object->get_source())) {
885                         if (in_array('image', $source->returns)) {
886                                 $mapper                 = $this->object->get_registry()->get_utility('I_Gallery_Mapper');
887                                 $gallery_key    = $mapper->get_primary_key_column();
888                                 $mapper->select();
889                                 if ($this->object->container_ids) {
890                                         $mapper->where(array("{$gallery_key} IN %s", $this->object->container_ids));
891                                 }
892                                 $retval                 = $mapper->run_query();
893                         }
894                 }
895                 return $retval;
896         }
897
898         /**
899          * Gets albums queried in this displayed gallery
900          * @return array
901          */
902         function get_albums()
903         {
904                 $retval = array();
905                 if (($source = $this->object->get_source())) {
906                         if (in_array('album', $source->returns)) {
907                                 $mapper         = $this->get_registry()->get_utility('I_Album_Mapper');
908                                 $album_key      = $mapper->get_primary_key_column();
909                                 if ($this->object->container_ids) {
910                                         $mapper->select()->where(array("{$album_key} IN %s", $this->object->container_ids));
911                                 }
912                                 $retval         = $mapper->run_query();
913                         }
914                 }
915                 return $retval;
916         }
917
918     /**
919      * Returns a transient for the displayed gallery
920      * @return string
921      */
922     function to_transient()
923     {
924                 $group = 'displayed_galleries';
925                 $key = C_Photocrati_Cache::generate_key($this->object->get_entity(), $group);
926                 if (is_null(C_Photocrati_Cache::get($key, NULL, $group))) {
927                         C_Photocrati_Cache::set($key, $this->object->get_entity(), $group, NGG_DISPLAYED_GALLERY_CACHE_TTL);
928                 }
929
930                 $this->object->transient_id = $key;
931                 if (!$this->object->id()) $this->object->id($key);
932
933         return $key;
934     }
935
936
937     /**
938      * Applies the values of a transient to this object
939      * @param string $transient_id
940      */
941     function apply_transient($transient_id=NULL)
942     {
943                 $retval = FALSE;
944
945                 if (!$transient_id && isset($this->object->transient_id)) $transient_id = $this->object->transient_id;
946
947                 if ($transient_id && ($transient = C_Photocrati_Cache::get($transient_id, FALSE, 'displayed_galleries'))) {
948                         $this->object->_stdObject = $transient;
949             $this->object->transient_id = $transient_id;
950                         if (!$this->object->id()) $this->object->id($transient_id);
951                         $retval = TRUE;
952                 }
953
954                 return $retval;
955     }
956 }