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

Revision 874, 32.4 KB (checked in by max-horvath, 7 years ago)

2005-12-28 Max Horvath <max.horvath@…>

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