root/trunk/wifidog-auth/wifidog/classes/Content/ContentGroup/ContentGroup.php @ 1013

Revision 1013, 32.5 KB (checked in by benoitg, 7 years ago)

* dump_initial_data_postgres.sh: Add the
content_available_display_pages table to the dump, can someone
re-generate the initial data from a working install
* Remove the ?> tags from all the classes.

  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
Line 
1<?php
2
3/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
4
5// +-------------------------------------------------------------------+
6// | WiFiDog Authentication Server                                     |
7// | =============================                                     |
8// |                                                                   |
9// | The WiFiDog Authentication Server is part of the WiFiDog captive  |
10// | portal suite.                                                     |
11// +-------------------------------------------------------------------+
12// | PHP version 5 required.                                           |
13// +-------------------------------------------------------------------+
14// | Homepage:     http://www.wifidog.org/                             |
15// | Source Forge: http://sourceforge.net/projects/wifidog/            |
16// +-------------------------------------------------------------------+
17// | This program is free software; you can redistribute it and/or     |
18// | modify it under the terms of the GNU General Public License as    |
19// | published by the Free Software Foundation; either version 2 of    |
20// | the License, or (at your option) any later version.               |
21// |                                                                   |
22// | This program is distributed in the hope that it will be useful,   |
23// | but WITHOUT ANY WARRANTY; without even the implied warranty of    |
24// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the     |
25// | GNU General Public License for more details.                      |
26// |                                                                   |
27// | You should have received a copy of the GNU General Public License |
28// | along with this program; if not, contact:                         |
29// |                                                                   |
30// | Free Software Foundation           Voice:  +1-617-542-5942        |
31// | 59 Temple Place - Suite 330        Fax:    +1-617-542-2652        |
32// | Boston, MA  02111-1307,  USA       gnu@gnu.org                    |
33// |                                                                   |
34// +-------------------------------------------------------------------+
35
36/**
37 * @package    WiFiDogAuthServer
38 * @subpackage ContentClasses
39 * @author     Benoit Gregoire <bock@step.polymtl.ca>
40 * @copyright  2005-2006 Benoit Gregoire, Technologies Coeus inc.
41 * @version    Subversion $Id$
42 * @link       http://www.wifidog.org/
43 */
44
45/**
46 * Load ContentGroupElement class
47 */
48require_once('classes/Content/ContentGroup/ContentGroupElement.php');
49
50/**
51 * A generic content group
52 *
53 * @package    WiFiDogAuthServer
54 * @subpackage ContentClasses
55 * @author     Benoit Gregoire <bock@step.polymtl.ca>
56 * @copyright  2005-2006 Benoit Gregoire, Technologies Coeus inc.
57 */
58class ContentGroup extends Content
59{
60
61    private $CONTENT_ORDERING_MODES = array ('RANDOM' => "Pick content elements randomly", 'SEQUENTIAL' => "Pick content elements in sequential order");
62    private $CONTENT_CHANGES_ON_MODES = array ('ALWAYS' => "Content always rotates", 'NEXT_DAY' => "Content rotates once per day", 'NEXT_LOGIN' => "Content rotates once per session", 'NEXT_NODE' => "Content rotates each time you change node");
63    private $ALLOW_REPEAT_MODES = array ('YES' => "Content can be shown more than once", 'NO' => "Content can only be shown once", 'ONCE_PER_NODE' => "Content can be shown more than once, but not at the same node");
64
65    protected $is_artistic_content;
66    protected $is_locative_content;
67
68    // is_expandable is ONLY for internal use, it use normally only set by the constructor
69    private $is_expandable = true;
70    // this is the actual publicly available status ( so if is_expandable == true it CANNOT be true )
71    private $expand_status = false;
72    private $temporary_display_num_elements;
73
74    private $content_selection_mode;
75    private $content_group_row;
76
77    protected function __construct($content_id)
78    {
79        // Define globals
80        global $db;
81
82        // Init values
83        $row = null;
84
85        parent :: __construct($content_id);
86
87        $content_id = $db->escapeString($content_id);
88
89        $sql = "SELECT * FROM content_group WHERE content_group_id='$content_id'";
90        $db->execSqlUniqueRes($sql, $row, false);
91        if ($row == null)
92        {
93            /*Since the parent Content exists, the necessary data in content_group had not yet been created */
94            $sql = "INSERT INTO content_group (content_group_id) VALUES ('$content_id')";
95            $db->execSqlUpdate($sql, false);
96            $sql = "SELECT * FROM content_group WHERE content_group_id='$content_id'";
97            $db->execSqlUniqueRes($sql, $row, false);
98            if ($row == null)
99            {
100                throw new Exception(_("The content with the following id could not be found in the database: ").$content_id);
101            }
102
103        }
104
105        $this->content_group_row = $row;
106
107        // These are for internal use only ( private and protected methods ) for dealing with expanding content
108        $this->setTemporaryDisplayNumElements(null);
109    }
110
111    /** Is the content group artistic in nature?
112     * @return true or false */
113    public function isArtisticContent()
114    {
115        if ($this->content_group_row['is_artistic_content'] == 't')
116        {
117            $retval = true;
118        }
119        else
120        {
121            $retval = false;
122        }
123        return $retval;
124    }
125
126    /** Set if the content group is artistic in nature,
127     * @param $is_artistic_content true or false*/
128    public function setIsArtisticContent($is_artistic_content)
129    {
130        if ($is_artistic_content != $this->isArtisticContent()) /* Only update database if there is an actual change */
131        {
132            $is_artistic_content ? $is_artistic_content_sql = 'TRUE' : $is_artistic_content_sql = 'FALSE';
133
134            global $db;
135            $db->execSqlUpdate("UPDATE content_group SET is_artistic_content = $is_artistic_content_sql WHERE content_group_id = '$this->id'", false);
136            $this->refresh();
137        }
138
139    }
140
141    /** Does the content shown or generated by the content group directly related to where it is viewed from?
142     * @return true or false */
143    public function isLocativeContent()
144    {
145        if ($this->content_group_row['is_locative_content'] == 't')
146        {
147            $retval = true;
148        }
149        else
150        {
151            $retval = false;
152        }
153        return $retval;
154    }
155
156    /** Set if the content group is locative
157     * @param $is_locative_content true or false
158     * */
159    public function setIsLocativeContent($is_locative_content)
160    {
161        if ($is_locative_content != $this->isLocativeContent()) /* Only update database if there is an actual change */
162        {
163            $is_locative_content ? $is_locative_content_sql = 'TRUE' : $is_locative_content_sql = 'FALSE';
164
165            global $db;
166            $db->execSqlUpdate("UPDATE content_group SET is_locative_content = $is_locative_content_sql WHERE content_group_id = '$this->id'", false);
167            $this->refresh();
168        }
169
170    }
171
172    /** In what order is the content displayed to the user
173    * @return string, a key of CONTENT_SELECTION_MODES */
174    public function getContentOrderingMode()
175    {
176        return $this->content_group_row['content_ordering_mode'];
177    }
178
179    /** In what order is the content displayed to the user
180     * @param $content_ordering_mode One of the CONTENT_ORDERING_MODES constants defined in the class
181     * @return true if successfull
182     * */
183    protected function setContentOrderingMode($content_ordering_mode, & $errormsg = null)
184    {
185        $retval = false;
186        if (isset ($this->CONTENT_ORDERING_MODES[$content_ordering_mode]) && $content_ordering_mode != $this->getContentOrderingMode()) /* Only update database if the mode is valid and there is an actual change */
187        {
188            global $db;
189            $content_ordering_mode = $db->escapeString($content_ordering_mode);
190            $db->execSqlUpdate("UPDATE content_group SET content_ordering_mode = '$content_ordering_mode' WHERE content_group_id = '$this->id'", false);
191            $this->refresh();
192            $retval = true;
193        }
194        elseif (!isset ($this->CONTENT_ORDERING_MODES[$content_ordering_mode]))
195        {
196            $errormsg = _("Invalid content selection mode (must be part of CONTENT_ORDERING_MODES)");
197            $retval = false;
198        }
199        else
200        {
201            /* Successfull, but nothing modified */
202            $retval = true;
203        }
204        return $retval;
205    }
206
207    /** When does the content rotate?
208    * @return string, a key of CONTENT_SELECTION_MODES */
209    public function getContentChangesOnMode()
210    {
211        return $this->content_group_row['content_changes_on_mode'];
212    }
213
214    /** When does the content rotate?
215     * @param $content_changes_on_mode One of the content_changes_on_modeS constants defined in the class
216     * @return true if successfull
217     * */
218    protected function setContentChangesOnMode($content_changes_on_mode, & $errormsg = null)
219    {
220        $retval = false;
221        if (isset ($this->CONTENT_CHANGES_ON_MODES[$content_changes_on_mode]) && $content_changes_on_mode != $this->getContentChangesOnMode()) /* Only update database if the mode is valid and there is an actual change */
222        {
223            global $db;
224            $content_changes_on_mode = $db->escapeString($content_changes_on_mode);
225            $db->execSqlUpdate("UPDATE content_group SET content_changes_on_mode = '$content_changes_on_mode' WHERE content_group_id = '$this->id'", false);
226            $this->refresh();
227            $retval = true;
228        }
229        elseif (!isset ($this->CONTENT_CHANGES_ON_MODES[$content_changes_on_mode]))
230        {
231            $errormsg = _("Invalid content selection mode (must be part of CONTENT_CHANGES_ON_MODES)");
232            $retval = false;
233        }
234        else
235        {
236            /* Successfull, but nothing modified */
237            $retval = true;
238        }
239        return $retval;
240    }
241
242    /** Can the same content be shown twice
243     * @return 'YES', 'NO', 'ONCE_PER_NODE' */
244    public function getAllowRepeat()
245    {
246        return $this->content_group_row['allow_repeat'];
247    }
248
249    /** When does the content rotate?
250     * @param $allow_repeat One of the allow_repeatS constants defined in the class
251     * @return true if successfull
252     * */
253    protected function setAllowRepeat($allow_repeat, & $errormsg = null)
254    {
255        $retval = false;
256        if (isset ($this->ALLOW_REPEAT_MODES[$allow_repeat]) && $allow_repeat != $this->getAllowRepeat()) /* Only update database if the mode is valid and there is an actual change */
257        {
258            global $db;
259            $allow_repeat = $db->escapeString($allow_repeat);
260            $db->execSqlUpdate("UPDATE content_group SET allow_repeat = '$allow_repeat' WHERE content_group_id = '$this->id'", false);
261            $this->refresh();
262            $retval = true;
263        }
264        elseif (!isset ($this->ALLOW_REPEAT_MODES[$allow_repeat]))
265        {
266            $errormsg = _("Invalid content selection mode (must be part of ALLOW_REPEAT_MODES)");
267            $retval = false;
268        }
269        else
270        {
271            /* Successfull, but nothing modified */
272            $retval = true;
273        }
274        return $retval;
275    }
276
277    /** How many element should be picked for display at once?
278    * @return integer */
279    public function getDisplayNumElements()
280    {
281        if($this->temporary_display_num_elements == null)
282            return $this->content_group_row['display_num_elements'];
283        else
284            return $this->temporary_display_num_elements;
285    }
286
287    /** How many element should be picked for display at once?
288    * @param $display_num_elements integer, must be greater than zero.
289    * @return true if successfull
290    * */
291    protected function setDisplayNumElements($display_num_elements, & $errormsg = null)
292    {
293        $retval = false;
294        if (($display_num_elements > 0) && $display_num_elements != $this->getDisplayNumElements()) /* Only update database if the mode is valid and there is an actual change */
295        {
296            global $db;
297            $display_num_elements = $db->escapeString($display_num_elements);
298            $db->execSqlUpdate("UPDATE content_group SET display_num_elements = '$display_num_elements' WHERE content_group_id = '$this->id'", false);
299            $this->refresh();
300            $retval = true;
301        }
302        elseif ($display_num_elements <= 0)
303        {
304            $errormsg = _("You must display at least one element");
305            $retval = false;
306        }
307        else
308        {
309            /* Successfull, but nothing modified */
310            $retval = true;
311        }
312        return $retval;
313    }
314
315    /**
316     * This will a temporary limit ( NOT ACTUALLY STORED IN DATABASE )
317     * Use getDisplayNumElements to get the number of elements that can be shown
318     * at once
319     */
320    private function setTemporaryDisplayNumElements($temporary_num_elements)
321    {
322        $this->temporary_display_num_elements = $temporary_num_elements;
323    }
324
325    public function getAdminUI($subclass_admin_interface = null)
326    {
327        $html = '';
328        $html .= "<div class='admin_class'>ContentGroup (".get_class($this)." instance)</div>\n";
329
330        /* is_artistic_content */
331        $html .= "<div class='admin_section_container'>\n";
332        $html .= "<div class='admin_section_title'>Is artistic content?: </div>\n";
333        $html .= "<div class='admin_section_data'>\n";
334        $name = "content_group_".$this->id."_is_artistic_content";
335        $this->isArtisticContent() ? $checked = 'CHECKED' : $checked = '';
336        $html .= "<input type='checkbox' name='$name' $checked>\n";
337        $html .= "</div>\n";
338        $html .= "</div>\n";
339
340        /* is_locative_content */
341        $html .= "<div class='admin_section_container'>\n";
342        $html .= "<div class='admin_section_title'>". ("Is locative content?").": </div>\n";
343        $html .= "<div class='admin_section_data'>\n";
344        $name = "content_group_".$this->id."_is_locative_content";
345        $this->isLocativeContent() ? $checked = 'CHECKED' : $checked = '';
346        $html .= "<input type='checkbox' name='$name' $checked>\n";
347        $html .= "</div>\n";
348        $html .= "</div>\n";
349
350        /* content_ordering_mode */
351        $html .= "<div class='admin_section_container'>\n";
352        $html .= "<div class='admin_section_title'>"._("In what order should the content displayed?").": </div>\n";
353        $html .= "<div class='admin_section_data'>\n";
354        $name = "content_group_".$this->id."_content_ordering_mode";
355
356        $i = 0;
357        $tab = null;
358        foreach ($this->CONTENT_ORDERING_MODES as $select_mode_id => $select_mode_descr)
359        {
360            $tab[$i][0] = $select_mode_id;
361            $tab[$i][1] = $select_mode_descr;
362            $i ++;
363        }
364        $html .= FormSelectGenerator :: generateFromArray($tab, $this->getContentOrderingMode(), $name, null, false);
365        $html .= "</div>\n";
366        $html .= "</div>\n";
367
368        /*content_changes_on_mode */
369        $html .= "<div class='admin_section_container'>\n";
370        $html .= "<div class='admin_section_title'>"._("When does the content rotate?").": </div>\n";
371        $html .= "<div class='admin_section_data'>\n";
372        $name = "content_group_".$this->id."_content_changes_on_mode";
373        $i = 0;
374        $tab = null;
375        foreach ($this->CONTENT_CHANGES_ON_MODES as $select_mode_id => $select_mode_descr)
376        {
377            $tab[$i][0] = $select_mode_id;
378            $tab[$i][1] = $select_mode_descr;
379            $i ++;
380        }
381        $html .= FormSelectGenerator :: generateFromArray($tab, $this->getContentChangesOnMode(), $name, null, false);
382        $html .= "</div>\n";
383        $html .= "</div>\n";
384
385        /* allow_repeat*/
386        $html .= "<div class='admin_section_container'>\n";
387        $html .= "<div class='admin_section_title'>"._("Can content be shown more than once to the same user?").": </div>\n";
388        $html .= "<div class='admin_section_data'>\n";
389        $name = "content_group_".$this->id."_allow_repeat";
390        $i = 0;
391        $tab = null;
392        foreach ($this->ALLOW_REPEAT_MODES as $select_mode_id => $select_mode_descr)
393        {
394            $tab[$i][0] = $select_mode_id;
395            $tab[$i][1] = $select_mode_descr;
396            $i ++;
397        }
398        $html .= FormSelectGenerator :: generateFromArray($tab, $this->getAllowRepeat(), $name, null, false);
399        $html .= "</div>\n";
400        $html .= "</div>\n";
401
402        /*display_num_elements*/
403        $html .= "<div class='admin_section_container'>\n";
404        $html .= "<div class='admin_section_title'>". ("Pick how many elements for each display?").": </div>\n";
405        $html .= "<div class='admin_section_data'>\n";
406        $name = "content_group_".$this->id."_display_num_elements";
407        $value = $this->getDisplayNumElements();
408        $html .= "<input type='text' size='2' value='$value' name='$name'>\n";
409        $html .= "</div>\n";
410        $html .= "</div>\n";
411
412        /* content_group_element (table)*/
413        $html .= "<div class='admin_section_container'>\n";
414        $html .= "<div class='admin_section_title'>"._("Content group elements:")."</div>\n";
415
416        $html .= "<ul class='admin_section_list'>\n";
417        foreach ($this->getElements() as $element)
418        {
419            $html .= "<li class='admin_section_list_item'>\n";
420            $html .= "<div class='admin_section_data'>\n";
421            $html .= $element->getAdminUI();
422            $html .= "</div'>\n";
423            $html .= "<div class='admin_section_tools'>\n";
424            $name = "content_group_".$this->id."_element_".$element->GetId()."_erase";
425            $html .= "<input type='submit' name='$name' value='"._("Delete")."'>";
426            $html .= "</div>\n";
427            $html .= "</li>\n";
428        }
429        $html .= "<li class='admin_section_list_item'>\n";
430        $html .= "<b>"._("Add a new content OR select previously created content")."</b><br>";
431        $html .= self :: getNewContentUI("content_group_{$this->id}_new_element")."<br>";
432        $html .= self :: getSelectContentUI("content_group_{$this->id}_existing_element", "AND content_id != '$this->id'");
433        $html .= "<input type='submit' name='content_group_{$this->id}_existing_element_add' value='"._("Add")."'>";
434        $html .= "</li>\n";
435        $html .= "</ul>\n";
436        $html .= "</div>\n";
437
438        $html .= $subclass_admin_interface;
439        return parent :: getAdminUI($html);
440    }
441
442    function processAdminUI()
443    {
444        // Init values
445        $errmsg = null;
446
447        if ($this->isOwner(User :: getCurrentUser()) || User :: getCurrentUser()->isSuperAdmin())
448        {
449            parent :: processAdminUI();
450
451            /* is_artistic_content */
452            $name = "content_group_".$this->id."_is_artistic_content";
453            !empty ($_REQUEST[$name]) ? $this->setIsArtisticContent(true) : $this->setIsArtisticContent(false);
454
455            /* is_locative_content */
456            $name = "content_group_".$this->id."_is_locative_content";
457            !empty ($_REQUEST[$name]) ? $this->setIsLocativeContent(true) : $this->setIsLocativeContent(false);
458
459            /* content_ordering_mode */
460            $name = "content_group_".$this->id."_content_ordering_mode";
461            $this->setContentOrderingMode(FormSelectGenerator :: getResult($name, null));
462
463            /*content_changes_on_mode */
464            $name = "content_group_".$this->id."_content_changes_on_mode";
465            $this->setContentChangesOnMode(FormSelectGenerator :: getResult($name, null));
466
467            /* allow_repeat*/
468            $name = "content_group_".$this->id."_allow_repeat";
469            $this->setAllowRepeat(FormSelectGenerator :: getResult($name, null));
470
471            /*display_num_elements*/
472            $name = "content_group_".$this->id."_display_num_elements";
473            $this->setDisplayNumElements($_REQUEST[$name]);
474
475            /* content_group_element */
476            foreach ($this->getElements() as $element)
477            {
478                $name = "content_group_".$this->id."_element_".$element->GetId()."_erase";
479                if (!empty ($_REQUEST[$name]) && $_REQUEST[$name] == true)
480                {
481                    $element->delete($errmsg);
482                }
483                else
484                {
485                    $element->processAdminUI();
486                }
487            }
488
489            // The two following calls will either add a new element or add an existing one ( depending on what button the user clicked
490            /* We explicitely call the ContentGroupElement version of processNewContentUI */
491            ContentGroupElement :: processNewContentUI("content_group_{$this->id}_new_element", $this);
492            // Last parameters allows for existing content ( if any was selected )
493            ContentGroupElement :: processNewContentUI("content_group_{$this->id}_existing_element", $this, true);
494        }
495    }
496
497    /** Is this Content element displayable at this hotspot
498     * @param $node Node, optionnal
499     * @return true or false */
500    public function isDisplayableAt($node)
501    {
502        $old_curent_node = Node::getCurrentNode();
503        Node::setCurrentNode($node);
504
505        if (count($this->getDisplayElements())>0) {
506            $retval = true;
507        } else {
508            $retval = false;
509        }
510
511        if ($old_curent_node != null) {
512            Node::setCurrentNode($old_curent_node);
513        }
514
515        return $retval;
516    }
517
518
519    /**Get the next element or elements to be displayed, depending on the display mode
520    * @return an array of ContentGroupElement or an empty arrray */
521    function getDisplayElements()
522    {
523        // Define globals
524        global $db;
525
526        // Init values
527        $retval = array ();
528        $user = User :: getCurrentUser();
529        $redisplay_rows = null;
530        $last_order_row = null;
531        $element_rows = null;
532
533        if ($user)
534        {
535            $user_id = $user->getId();
536        }
537        else
538        {
539            $user_id = '';
540        }
541        $node = Node :: getCurrentNode();
542        if ($node)
543        {
544            $node_id = $node->getId();
545        }
546        else
547        {
548            $node_id = '';
549        }
550        $display_num_elements = $this->getDisplayNumElements();
551
552        /** First, find if we have content to display again because we haven't passed the rotation period */
553        /*  'ALWAYS' => "Content always rotates"
554         *  'NEXT_DAY' => "Content rotates once per day"
555         *  'NEXT_LOGIN' => "Content rotates once per session"
556         *  'NEXT_NODE' => "Content rotates each time you change node"*/
557        $content_changes_on_mode = $this->getContentChangesOnMode();
558
559        $redisplay_objects = array ();
560        if ($content_changes_on_mode != 'ALWAYS')
561        {
562            $sql = "SELECT content_group_element_id FROM content_group_element \n";
563            $sql .= "JOIN content_display_log ON (content_group_element_id=content_id) \n";
564            $sql .= " WHERE content_group_id='$this->id' \n";
565
566            if ($content_changes_on_mode == 'NEXT_DAY')
567            {
568                $sql .= "AND date_trunc('day', last_display_timestamp) = date_trunc('day', CURRENT_DATE) \n";
569            }
570            if ($content_changes_on_mode == 'NEXT_LOGIN')
571            {
572                /**@todo Must fix, this will fail if the user never really connected from a hotspot... */
573                $sql .= "AND last_display_timestamp > (SELECT timestamp_in FROM connections WHERE user_id='$user_id' ORDER BY timestamp_in DESC LIMIT 1) \n";
574            }
575            if ($content_changes_on_mode == 'NEXT_NODE')
576            {
577                /** We find the close time of the last connection from another node */
578                $sql .= "AND last_display_timestamp > (SELECT timestamp_out FROM connections WHERE user_id='$user_id' AND node_id != '$node_id' ORDER BY timestamp_in DESC LIMIT 1) \n";
579            }
580            /* There usually won't be more than one, but if there is, we want the most recents */
581            $sql .= " ORDER BY last_display_timestamp DESC ";
582            $db->execSql($sql, $redisplay_rows, false);
583            $redisplay_objects = array ();
584            if ($redisplay_rows != null)
585            {
586                foreach ($redisplay_rows as $redisplay_row)
587                {
588                    $object = self :: getObject($redisplay_row['content_group_element_id']);
589                    if ($object->isDisplayableAt(Node :: GetCurrentNode()) == true) /** Only content available at this hotspot are considered */
590                    {
591                        $redisplay_objects[] = $object;
592                    }
593                }
594            }
595            /* Pick the proper number of elements to be re-displayed */
596            $redisplay_objects = array_slice($redisplay_objects, 0, $display_num_elements);
597
598        }
599
600        $new_objects = array ();
601        if (count($redisplay_objects) < $display_num_elements)
602        {
603            /* We need new content */
604
605            $sql = "SELECT content_group_element_id FROM content_group_element WHERE content_group_id='$this->id' \n";
606
607            /*'YES' => "Content can be shown more than once", 'NO' => "Content can only be shown once", 'ONCE_PER_NODE' => "Content can be shown more than once, but not at the same node"*/
608            $allow_repeat = $this->getAllowRepeat();
609
610            if ($allow_repeat == 'NO')
611            {
612                $sql .= "AND content_group_element_id NOT IN (SELECT content_id FROM content_display_log WHERE user_id = '$user_id') \n";
613            }
614            elseif ($allow_repeat == 'ONCE_PER_NODE')
615            {
616                $sql .= "AND content_group_element_id NOT IN (SELECT content_id FROM content_display_log WHERE user_id = '$user_id' AND  node_id = '$node_id') \n";
617            }
618
619            /* 'RANDOM' => "Pick content elements randomly",'SEQUENTIAL' => "Pick content elements in sequential order" */
620            $content_ordering_mode = $this->getContentOrderingMode();
621
622            if ($content_ordering_mode == 'SEQUENTIAL')
623            {
624                $order_by = ' ORDER BY display_order ';
625            $sql_last_order = "SELECT display_order FROM content_group_element \n";
626            $sql_last_order .= "JOIN content_display_log ON (content_group_element_id=content_id) \n";
627            $sql_last_order .= " WHERE content_group_id='$this->id' \n";
628            $sql_last_order .= " ORDER BY last_display_timestamp DESC LIMIT 1";
629            $db->execSqlUniqueRes($sql_last_order, $last_order_row, false);
630            if($last_order_row['display_order']!=null)
631            {
632            $last_order=$last_order_row['display_order'];
633            }
634            else
635            {
636            $last_order=0;
637            }
638            }
639            else
640            {
641                $order_by = ' ';
642            }
643            $sql .= $order_by;
644
645            $db->execSql($sql, $element_rows, false);
646            if ($element_rows == null)
647            {
648                $element_rows = array ();
649            }
650            foreach ($element_rows as $element_row)
651            {
652                $object = self :: getObject($element_row['content_group_element_id']);
653                if ($object->isDisplayableAt(Node :: GetCurrentNode()) == true) /** Only content available at this hotspot are considered */
654                {
655                    $new_objects[] = $object;
656                }
657            }
658
659            if ($content_ordering_mode == 'RANDOM')
660            {
661                shuffle($new_objects);
662            }
663            elseif($content_ordering_mode == 'SEQUENTIAL')
664            {
665                foreach($new_objects as $object)
666                {
667                    if($object->getDisplayOrder()<=$last_order)
668                    {
669                        array_push ( $new_objects, array_shift ( $new_objects ));
670                        //echo " Pushed ".$object->getDisplayOrder();
671                    }
672                }
673            }
674
675            /** Pick the proper number of elements */
676            $num_to_pick = $display_num_elements - count($redisplay_objects);
677            $new_objects = array_slice($new_objects, 0, $num_to_pick);
678        }
679        /*
680        echo "<pre>Redisplay: ";
681        print_r($redisplay_objects);
682        echo "New objects: ";
683        print_r($new_objects);
684        echo "</pre>";
685*/
686        $retval = array_merge($new_objects, $redisplay_objects);
687        //echo count($retval).' returned <br>';
688        return $retval;
689    }
690
691    /**
692     * This attribute is for internal use ( to tell if a certain class could be
693     * expanded )
694     * @param $status boolean
695     */
696    protected function setIsExpandable($status)
697    {
698        if(is_bool($status))
699            $this->is_expandable = $status;
700    }
701
702    /**
703     * Tells if this object could be expanded
704     */
705    protected function isExpandable()
706    {
707        return $this->is_expandable;
708    }
709
710    /**
711     * Will expand content ONLY if allowed by isExpandable (which is protected)
712     * @param $status boolean
713     */
714    public function setExpandStatus($status)
715    {
716        if($this->isExpandable() && is_bool($status))
717        {
718            //TODO: Try to find a better solution to this problem...
719            if($status == true)
720                $this->setTemporaryDisplayNumElements(3000);
721            else
722                $this->setTemporaryDisplayNumElements(null);
723            $this->expand_status = $status;
724        }
725    }
726
727    /**
728     * Get the expand status
729     *
730     * WARNING
731     * NON expandable contents ie PatternLanguage will NEVER return true
732     */
733    public function getExpandStatus()
734    {
735        if($this->expand_status == null)
736            return false;
737        return $this->expand_status;
738    }
739
740    /** Retreives the user interface of this object.  Anything that overrides this method should call the parent method with it's output at the END of processing.
741     * @param $subclass_admin_interface Html content of the interface element of a children
742     * @param boolean $hide_elements allows the child class ( for example
743     * Pattern Language) to tell the content group not to display elements ) for
744     * elements that need to be hidden before subscription
745     * @return The HTML fragment for this interface */
746    public function getUserUI($subclass_user_interface = null, $hide_elements = false)
747    {
748        $html = '';
749        $html .= "<div class='user_ui_container'>\n";
750        $html .= "<div class='user_ui_object_class'>ContentGroup (".get_class($this)." instance)</div>\n";
751
752        if($hide_elements == false)
753        {
754            $display_elements = $this->getDisplayElements();
755            if (count($display_elements) > 0)
756            {
757                foreach ($display_elements as $display_element)
758                {
759                    // If the content group logging is disabled, all the children will inherit this property temporarly
760                    if($this->getLoggingStatus() == false)
761                        $display_element->setLoggingStatus(false);
762                    $html .= $display_element->getUserUI();
763                }
764            }
765            else
766            {
767                $html .= '<p class="warningmsg">'._("Sorry, no elements available at this hotspot or all elements of the content group have already been shown")."</p>\n";
768            }
769        }
770
771        $html .= $subclass_user_interface;
772        $html .= "</div>\n";
773
774        return parent :: getUserUI($html);
775    }
776
777    /**Get all elements
778     * @return an array of ContentGroupElement or an empty arrray */
779    function getElements()
780    {
781        // Define globals
782        global $db;
783
784        // Init values
785        $retval = array ();
786        $element_rows = null;
787
788        $sql = "SELECT content_group_element_id FROM content_group_element WHERE content_group_id='$this->id' ORDER BY display_order";
789        $db->execSql($sql, $element_rows, false);
790        if ($element_rows != null)
791        {
792            foreach ($element_rows as $element_row)
793            {
794                $retval[] = self :: getObject($element_row['content_group_element_id']);
795            }
796        }
797        return $retval;
798    }
799
800    /** Delete this Content from the database
801    */
802    public function delete(& $errmsg)
803    {
804        if ($this->isPersistent() == false)
805        {
806            foreach ($this->getElements() as $element)
807            {
808                $element->delete($errmsg);
809            }
810        }
811        return parent :: delete($errmsg);
812    }
813        /** Reloads the object from the database.  Should normally be called after a set operation.
814     * This function is private because calling it from a subclass will call the
815     * constructor from the wrong scope */
816    private function refresh()
817    {
818        $this->__construct($this->id);
819    }
820
821}
822
823/*
824 * Local variables:
825 * tab-width: 4
826 * c-basic-offset: 4
827 * c-hanging-comment-ender-p: nil
828 * End:
829 */
830
831
Note: See TracBrowser for help on using the browser.