root/trunk/wifidog-auth/wifidog/classes/Content.php @ 849

Revision 849, 43.0 KB (checked in by fproulx, 7 years ago)

2005-11-28 Fran�ois Proulx <francois.proulx@…>

  • Improved Flickr user output
  • Mostly completed Flickr admin UI
  • Changed display algorithm to display sequentially
  • 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
4/********************************************************************\
5 * This program is free software; you can redistribute it and/or    *
6 * modify it under the terms of the GNU General Public License as   *
7 * published by the Free Software Foundation; either version 2 of   *
8 * the License, or (at your option) any later version.              *
9 *                                                                  *
10 * This program is distributed in the hope that it will be useful,  *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
13 * GNU General Public License for more details.                     *
14 *                                                                  *
15 * You should have received a copy of the GNU General Public License*
16 * along with this program; if not, contact:                        *
17 *                                                                  *
18 * Free Software Foundation           Voice:  +1-617-542-5942       *
19 * 59 Temple Place - Suite 330        Fax:    +1-617-542-2652       *
20 * Boston, MA  02111-1307,  USA       gnu@gnu.org                   *
21 *                                                                  *
22 \********************************************************************/
23/**@file Content.php
24 * @author Copyright (C) 2005 Benoit Grégoire <bock@step.polymtl.ca>,
25 * Technologies Coeus inc.
26 */
27require_once BASEPATH.'include/common.php';
28require_once BASEPATH.'classes/FormSelectGenerator.php';
29require_once BASEPATH.'classes/GenericObject.php';
30
31/** Any type of content */
32class Content implements GenericObject
33{
34        protected $id;
35        protected $content_row;
36        private $content_type;
37        private $is_trivial_content;
38        private $is_logging_enabled;
39
40        /** Create a new Content object in the database
41         * @param $content_type Optionnal, the content type to be given to the new object
42         * @param $id Optionnal, the id to be given to the new Content.  If null, a new id will be assigned
43         * @return the newly created Content object, or null if there was an error (an exception is also trown
44         */
45        static function createNewObject($content_type = 'Content', $id = null)
46        {
47                global $db;
48                if (empty ($id))
49                {
50                        $content_id = get_guid();
51                }
52                else
53                {
54                        $content_id = $db->EscapeString($id);
55                }
56
57                if (empty ($content_type))
58                {
59                        throw new Exception(_('Content type is optionnal, but cannot be empty!'));
60                }
61                else
62                {
63                        $content_type = $db->EscapeString($content_type);
64                }
65                $sql = "INSERT INTO content (content_id, content_type) VALUES ('$content_id', '$content_type')";
66
67                if (!$db->ExecSqlUpdate($sql, false))
68                {
69                        throw new Exception(_('Unable to insert new content into database!'));
70                }
71
72                $object = self :: getObject($content_id);
73                /* At least add the current user as the default owner */
74                $object->AddOwner(User :: getCurrentUser());
75                /* By default, make it persistent */
76                $object->setIsPersistent(true);
77
78                return $object;
79        }
80
81        /** Get an interface to create a new object.
82        * @return html markup
83        */
84        public static function getCreateNewObjectUI()
85        {
86                $html = '';
87                $i = 0;
88                $tab = array ();
89                foreach (self :: getAvailableContentTypes() as $classname)
90                {
91                        $tab[$i][0] = $classname;
92                        $tab[$i][1] = $classname;
93                        $i ++;
94                }
95                $name = "new_content_content_type";
96                $default = 'TrivialLangstring';
97                if (empty ($tab))
98                        $html .= _("It appears that you have not installed any Content plugin !");
99                else
100                {
101                        $html .= _("You must select a content type: ");
102                        $html .= FormSelectGenerator :: generateFromArray($tab, $default, $name, "Content", false);
103                }
104                return $html;
105        }
106
107        /** Process the new object interface.
108         *  Will       return the new object if the user has the credentials
109         * necessary (Else an exception is thrown) and and the form was fully
110         * filled (Else the object returns null).
111         * @return the node object or null if no new node was created.
112         */
113        static function processCreateNewObjectUI()
114        {
115                $retval = null;
116                $name = "new_content_content_type";
117                $content_type = FormSelectGenerator :: getResult($name, "Content");
118                if ($content_type)
119                {
120                        $retval = self :: createNewObject($content_type);
121                }
122
123                return $retval;
124        }
125
126        /** Get the Content object, specific to it's content type
127         * @param $content_id The content id
128         * @return the Content object, or null if there was an error (an exception is also thrown)
129         */
130        static function getObject($content_id)
131        {
132                global $db;
133                $content_id = $db->EscapeString($content_id);
134                $sql = "SELECT content_type FROM content WHERE content_id='$content_id'";
135                $db->ExecSqlUniqueRes($sql, $row, false);
136                if ($row == null)
137                {
138                        throw new Exception(_("The content with the following id could not be found in the database: ").$content_id);
139                }
140                $content_type = $row['content_type'];
141                $object = new $content_type ($content_id);
142                return $object;
143        }
144
145        /** Get the list of available content type on the system
146         * @return an array of class names */
147        public static function getAvailableContentTypes()
148        {
149                $dir = BASEPATH.'classes/Content';
150                if ($dir_handle = @opendir($dir))
151                {
152                        $content_types = array();
153                       
154                        /* This is the correct way to loop over the directory. */
155                        while (false !== ($sub_dir = readdir($dir_handle)))
156                        {
157                                // Loop through sub-directories of Content
158                                if ($sub_dir != '.' && $sub_dir != '..' && is_dir("{$dir}/{$sub_dir}"))
159                                {
160                                        // Only add directories containing corresponding initial Content class
161                                        if(is_file("{$dir}/{$sub_dir}/{$sub_dir}.php"))
162                                                $content_types[] = $sub_dir;
163                                }
164                        }
165                        closedir($dir_handle);
166                }
167                else
168                {
169                        throw new Exception(_('Unable to open directory ').$dir);
170                }
171               
172                // Cleanup PHP file extensions and sort the result array
173                $content_types = str_ireplace('.php', '', $content_types);
174                sort($content_types);
175               
176                return $content_types;
177        }
178
179        /**
180         * Get all content, can be restricted to a given content type
181         */
182        public static function getAllContent($content_type = "")
183        {
184                global $db;
185                $where_clause = "";
186                if (!empty ($content_type))
187                {
188                        $content_type = $db->EscapeString($content_type);
189                        $where_clause = "WHERE content_type = '$content_type'";
190                }
191                $db->ExecSql("SELECT content_id FROM content $where_clause", $rows, false);
192                $objects = array ();
193                if ($rows)
194                        foreach ($rows as $row)
195                                $objects[] = self :: getObject($row['content_id']);
196                return $objects;
197        }
198
199        /** Get a flexible interface to generate new content objects
200         * @param $user_prefix A identifier provided by the programmer to recognise it's generated html form
201         * @param $content_type If set, the created content will be of this type, otherwise, the user will have to chose
202         * @return html markup
203         */
204        static function getNewContentUI($user_prefix, $content_type = null)
205        {
206                global $db;
207                $html = '';
208                $available_content_types = self :: getAvailableContentTypes();
209
210                $name = "get_new_content_{$user_prefix}_content_type";
211                if (empty ($content_type))
212                {
213                        $html .= _("Content type: ");
214                        $i = 0;
215                        foreach ($available_content_types as $classname)
216                        {
217                                $tab[$i][0] = $classname;
218                                $tab[$i][1] = $classname;
219                                $i ++;
220                        }
221                        $html .= FormSelectGenerator :: generateFromArray($tab, 'TrivialLangstring', $name, null, false);
222                }
223                else
224                {
225                        if (false === array_search($content_type, $available_content_types, true))
226                        {
227                                throw new Exception(_("The following content type isn't valid: ").$content_type);
228                        }
229                        $html .= "<input type='hidden' name='$name' value='$content_type'>";
230                }
231                $name = "get_new_content_{$user_prefix}_add";
232
233                if ($content_type)
234                {
235                        $value = _("Add a")." $content_type";
236                }
237                else
238                {
239                        $value = _("Add");
240                }
241                $html .= "<input type='submit' name='$name' value='$value'>";
242                return $html;
243        }
244
245        /** Get the created Content object, IF one was created
246         * OR Get existing content ( depending on what the user clicked )
247         * @param $user_prefix A identifier provided by the programmer to recognise it's generated form
248         * @param $associate_existing_content boolean if true allows to get existing
249         * object
250         * @return the Content object, or null if the user didn't greate one
251         */
252        static function processNewContentUI($user_prefix, $associate_existing_content = false)
253        {
254                $object = null;
255                if ($associate_existing_content == true)
256                        $name = "{$user_prefix}_add";
257                else
258                        $name = "get_new_content_{$user_prefix}_add";
259                if (!empty ($_REQUEST[$name]) && $_REQUEST[$name] == true)
260                {
261                        if ($associate_existing_content == true)
262                                $name = "{$user_prefix}";
263                        else
264                                $name = "get_new_content_{$user_prefix}_content_type";
265
266                        // The result can be either a Content type or a Content ID depending on the form ( associate_existing_content or NOT )
267                        $content_ui_result = FormSelectGenerator :: getResult($name, null);
268                        if ($associate_existing_content == true)
269                                $object = self :: getObject($content_ui_result);
270                        else
271                                $object = self :: createNewObject($content_ui_result);
272                }
273                return $object;
274        }
275
276        /** Get a flexible interface to manage content linked to a node, a network or anything else
277         * @param $user_prefix A identifier provided by the programmer to recognise it's generated html form
278         * @param $content_type If set, the created content will be of this type, otherwise, the user will have to chose
279         * @return html markup
280         */
281        static function getLinkedContentUI($user_prefix, $link_table, $link_table_obj_key_col, $link_table_obj_key, $display_location)
282        {
283                global $db;
284                $html = '';
285                $link_table = $db->EscapeString($link_table);
286                $link_table_obj_key_col = $db->EscapeString($link_table_obj_key_col);
287                $link_table_obj_key = $db->EscapeString($link_table_obj_key);
288                $display_location = $db->EscapeString($display_location);
289                $name = "{$user_prefix}_display_location";
290
291                $html .= "<input type='hidden' name='{$name}' value='{$display_location}'>\n";
292                $current_content_sql = "SELECT * FROM $link_table WHERE $link_table_obj_key_col='$link_table_obj_key' AND display_location='$display_location' ORDER BY subscribe_timestamp DESC";
293                $rows = null;
294                $db->ExecSql($current_content_sql, $rows, false);
295                $html .= "<ul class='admin_section_list'>\n";
296                if ($rows)
297                        foreach ($rows as $row)
298                        {
299                                $content = Content :: getObject($row['content_id']);
300                                $html .= "<li class='admin_section_list_item'>\n";
301                                $html .= "<div class='admin_section_data'>\n";
302                                $html .= $content->getListUI();
303                                $html .= "</div>\n";
304                                $html .= "<div class='admin_section_tools'>\n";
305                                $name = "{$user_prefix}_".$content->GetId()."_edit";
306                                $html .= "<input type='button' name='$name' value='"._("Edit")."' onClick='window.location.href = \"".GENERIC_OBJECT_ADMIN_ABS_HREF."?object_class=Content&action=edit&object_id=".$content->GetId()."\";'>\n";
307                                $name = "{$user_prefix}_".$content->GetId()."_erase";
308                                $html .= "<input type='submit' name='$name' value='"._("Remove")."'>";
309                                $html .= "</div>\n";
310                                $html .= "</li>\n";
311                        }
312                $html .= "<li class='admin_section_list_item'>\n";
313                $name = "{$user_prefix}_new_existing";
314                $html .= Content :: getSelectContentUI($name, "AND content_id NOT IN (SELECT content_id FROM $link_table WHERE $link_table_obj_key_col='$link_table_obj_key')");
315                $name = "{$user_prefix}_new_display_location";
316
317                $html .= "<input type='hidden' name='{$name}' value='{$display_location}'>\n";
318                $name = "{$user_prefix}_new_existing_submit";
319                $html .= "<input type='submit' name='$name' value='"._("Add")."'>";
320                $html .= "</li>\n";
321                $html .= "<li class='admin_section_list_item'>\n";
322                $html .= "Add new content: ";
323                $name = "{$user_prefix}_new";
324                $html .= self :: getNewContentUI($name, $content_type = null);
325                $html .= "</li>\n";
326                $html .= "</ul>\n";
327
328                return $html;
329        }
330
331        /** Get the created Content object, IF one was created
332         * OR Get existing content ( depending on what the user clicked )
333         * @param $user_prefix A identifier provided by the programmer to recognise it's generated form
334         * @param $associate_existing_content boolean if true allows to get existing
335         * object
336         * @return the Content object, or null if the user didn't greate one
337         */
338        static function processLinkedContentUI($user_prefix, $link_table, $link_table_obj_key_col, $link_table_obj_key)
339        {
340
341                global $db;
342                $link_table = $db->EscapeString($link_table);
343                $link_table_obj_key_col = $db->EscapeString($link_table_obj_key_col);
344                $link_table_obj_key = $db->EscapeString($link_table_obj_key);
345                $name = "{$user_prefix}_display_location";
346                $display_location = $db->EscapeString($_REQUEST[$name]);
347                $name = "{$user_prefix}_new_display_location";
348                $display_location_new = $db->EscapeString($_REQUEST[$name]);
349                $current_content_sql = "SELECT * FROM $link_table WHERE $link_table_obj_key_col='$link_table_obj_key' AND display_location='$display_location' ORDER BY subscribe_timestamp DESC";
350                $rows = null;
351                $db->ExecSql($current_content_sql, $rows, false);
352                if ($rows)
353                        foreach ($rows as $row)
354                        {
355                                $content = Content :: getObject($row['content_id']);
356                                $content_id = $db->EscapeString($content->getId());
357                                $name = "{$user_prefix}_".$content->GetId()."_erase";
358                                if (!empty ($_REQUEST[$name]))
359                                {
360                                        $sql = "DELETE FROM $link_table WHERE $link_table_obj_key_col='$link_table_obj_key' AND content_id = '$content_id'";
361                                        $db->ExecSqlUpdate($sql, $rows, false);
362                                }
363                        }
364
365                $name = "{$user_prefix}_new_existing_submit";
366                if (!empty ($_REQUEST[$name]))
367                {
368                        $name = "{$user_prefix}_new_existing";
369                        $content = Content :: processSelectContentUI($name);
370                        if ($content)
371                        {
372                                $content_id = $db->EscapeString($content->getId());
373                                $sql = "INSERT INTO $link_table (content_id, $link_table_obj_key_col, display_location) VALUES ('$content_id', '$link_table_obj_key', '$display_location_new');\n";
374                                $db->ExecSqlUpdate($sql, $rows, false);
375                        }
376                }
377                $name = "{$user_prefix}_new";
378                $content = self :: processNewContentUI($name);
379                if ($content)
380                {
381                        $content_id = $db->EscapeString($content->getId());
382                        $sql = "INSERT INTO $link_table (content_id, $link_table_obj_key_col, display_location) VALUES ('$content_id', '$link_table_obj_key', '$display_location_new');\n";
383                        $db->ExecSqlUpdate($sql, $rows, false);
384                }
385
386        }
387
388        /** Get an interface to pick content from all persistent content.
389        * @param $user_prefix A identifier provided by the programmer to recognise it's generated html form
390          @param $sql_additional_where Addidional where conditions to restrict the candidate objects
391        * @return html markup
392        */
393        public static function getSelectContentUI($user_prefix, $sql_additional_where = null)
394        {
395                $html = '';
396                $name = "{$user_prefix}";
397                $html .= _("Select existing Content : ")."\n";
398                global $db;
399                $retval = array ();
400                $sql = "SELECT * FROM content WHERE is_persistent=TRUE $sql_additional_where ORDER BY creation_timestamp";
401                $db->ExecSql($sql, $content_rows, false);
402                if ($content_rows != null)
403                {
404                        $i = 0;
405                        foreach ($content_rows as $content_row)
406                        {
407                                $content = Content :: getObject($content_row['content_id']);
408                                $tab[$i][0] = $content->getId();
409                                $tab[$i][1] = $content->__toString()." (".get_class($content).")";
410                                $i ++;
411                        }
412                        $html .= FormSelectGenerator :: generateFromArray($tab, null, $name, null, false);
413
414                }
415                else
416                {
417                        $html .= "<div class='warningmsg'>"._("Sorry, no content available in the database")."</div>\n";
418                }
419                return $html;
420        }
421
422        /** Get the selected Content object.
423         * @param $user_prefix A identifier provided by the programmer to recognise it's generated form
424         * @return the Content object
425         */
426        static function processSelectContentUI($user_prefix)
427        {
428                $name = "{$user_prefix}";
429                if (!empty ($_REQUEST[$name]))
430                        return Content :: getObject($_REQUEST[$name]);
431                else
432                        return null;
433        }
434
435        private function __construct($content_id)
436        {
437                global $db;
438
439                $content_id = $db->EscapeString($content_id);
440                $sql = "SELECT * FROM content WHERE content_id='$content_id'";
441                $db->ExecSqlUniqueRes($sql, $row, false);
442                if ($row == null)
443                {
444                        throw new Exception(_("The content with the following id could not be found in the database: ").$content_id);
445                }
446                $this->content_row = $row;
447                $this->id = $row['content_id'];
448                $this->content_type = $row['content_type'];
449
450                // By default Content display logging is enabled
451                $this->setLoggingStatus(true);
452        }
453
454        /** A short string representation of the content */
455        public function __toString()
456        {
457                if (empty ($this->content_row['title']))
458                {
459                        $string = _("Untitled content");
460                }
461                else
462                {
463                        $title = self :: getObject($this->content_row['title']);
464                        $string = $title->__toString();
465                }
466                return $string;
467        }
468
469        /** Get the true object type represented by this isntance
470         * @return an array of class names */
471        public function getObjectType()
472        {
473                return $this->content_type;
474        }
475
476        /**
477         * Get content title
478         * @return content a content sub-class
479         */
480        public function getTitle()
481        {
482                try
483                {
484                        return self :: getObject($this->content_row['title']);
485                }
486                catch (Exception $e)
487                {
488                        return null;
489                }
490        }
491
492        /**
493         * Get content description
494         * @return content a content sub-class
495         */
496        public function getDescription()
497        {
498                try
499                {
500                        return self :: getObject($this->content_row['description']);
501                }
502                catch (Exception $e)
503                {
504                        return null;
505                }
506        }
507
508        /**
509         * Get content long description
510         * @return content a content sub-class
511         */
512        public function getLongDescription()
513        {
514                try
515                {
516                        return self :: getObject($this->content_row['long_description']);
517                }
518                catch (Exception $e)
519                {
520                        return null;
521                }
522        }
523
524        /**
525         * Get content project info
526         * @return content a content sub-class
527         */
528        public function getProjectInfo()
529        {
530                try
531                {
532                        return self :: getObject($this->content_row['project_info']);
533                }
534                catch (Exception $e)
535                {
536                        return null;
537                }
538        }
539
540        /**
541         * Get content sponsor info
542         * @return content a content sub-class
543         */
544        public function getSponsorInfo()
545        {
546                try
547                {
548                        return self :: getObject($this->content_row['sponsor_info']);
549                }
550                catch (Exception $e)
551                {
552                        return null;
553                }
554        }
555
556        /** Set the object type of this object
557         * Note that after using this, the object must be re-instanciated to have the right type
558         * */
559        private function setContentType($content_type)
560        {
561                global $db;
562                $content_type = $db->EscapeString($content_type);
563                $available_content_types = self :: getAvailableContentTypes();
564                if (false === array_search($content_type, $available_content_types, true))
565                {
566                        throw new Exception(_("The following content type isn't valid: ").$content_type);
567                }
568                $sql = "UPDATE content SET content_type = '$content_type' WHERE content_id='$this->id'";
569
570                if (!$db->ExecSqlUpdate($sql, false))
571                {
572                        throw new Exception(_("Update was unsuccessfull (database error)"));
573                }
574
575        }
576
577        /** Check if a user is one of the owners of the object
578         * @param $user The user to be added to the owners list
579         * @param $is_author Optionnal, true or false.  Set to true if the user is one of the actual authors of the Content
580         * @return true on success, false on failure */
581        public function addOwner(User $user, $is_author = false)
582        {
583                global $db;
584                $content_id = "'".$this->id."'";
585                $user_id = "'".$db->EscapeString($user->getId())."'";
586                $is_author ? $is_author = 'TRUE' : $is_author = 'FALSE';
587                $sql = "INSERT INTO content_has_owners (content_id, user_id, is_author) VALUES ($content_id, $user_id, $is_author)";
588
589                if (!$db->ExecSqlUpdate($sql, false))
590                {
591                        throw new Exception(_('Unable to insert the new Owner into database.'));
592                }
593
594                return true;
595        }
596
597        /** Remove an owner of the content
598         * @param $user The user to be removed from the owners list
599         */
600        public function deleteOwner(User $user, $is_author = false)
601        {
602                global $db;
603                $content_id = "'".$this->id."'";
604                $user_id = "'".$db->EscapeString($user->getId())."'";
605
606                $sql = "DELETE FROM content_has_owners WHERE content_id=$content_id AND user_id=$user_id";
607
608                if (!$db->ExecSqlUpdate($sql, false))
609                {
610                        throw new Exception(_('Unable to remove the owner from the database.'));
611                }
612
613                return true;
614        }
615
616        /**
617         * Indicates display logging status
618         */
619        public function getLoggingStatus()
620        {
621                return $this->is_logging_enabled;
622        }
623
624        /**
625         * Sets display logging status
626         */
627        public function setLoggingStatus($status)
628        {
629                if (is_bool($status))
630                        $this->is_logging_enabled = $status;
631        }
632
633        /** Get the PHP timestamp of the last time this content was displayed
634         * @param $user User, Optional, if present, restrict to the selected user
635         * @param $node Node, Optional, if present, restrict to the selected node
636         * @return PHP timestamp (seconds since UNIX epoch) if the content has been
637         * displayed before, an empty string otherwise.
638         */
639        public function getLastDisplayTimestamp($user = null, $node = null)
640        {
641                global $db;
642                $retval = '';
643                $sql = "SELECT EXTRACT(EPOCH FROM last_display_timestamp) as last_display_unix_timestamp FROM content_display_log WHERE content_id='{$this->id}' \n";
644
645                if ($user)
646                {
647                        $user_id = $db->EscapeString($user->getId());
648                        $sql .= " AND user_id = '{$user_id}' \n";
649                }
650                if ($node)
651                {
652                        $node_id = $db->EscapeString($node->getId());
653                        $sql .= " AND node_id = '{$node_id}' \n";
654                }
655                $sql .= " ORDER BY last_display_timestamp DESC ";
656                $db->ExecSql($sql, $log_rows, false);
657                if ($log_rows)
658                {
659                        $retval = $log_rows[0]['last_display_unix_timestamp'];
660                }
661
662                return $retval;
663        }
664
665        /** Is this Content element displayable at this hotspot, many classer override this
666         * @param $node Node, optionnal
667         * @return true or false */
668        public function isDisplayableAt($node)
669        {
670                return true;
671        }
672
673        /** Check if a user is one of the owners of the object
674         * @param $user User object:  the user to be tested.
675         * @return true if the user is a owner, false if he isn't of the user is null */
676        public function isOwner($user)
677        {
678                global $db;
679                $retval = false;
680                if ($user != null)
681                {
682                        $user_id = $db->EscapeString($user->GetId());
683                        $sql = "SELECT * FROM content_has_owners WHERE content_id='$this->id' AND user_id='$user_id'";
684                        $db->ExecSqlUniqueRes($sql, $content_owner_row, false);
685                        if ($content_owner_row != null)
686                        {
687                                $retval = true;
688                        }
689                }
690
691                return $retval;
692        }
693        /** Get the authors of the Content
694         * @return null or array of User objects */
695        public function getAuthors()
696        {
697                global $db;
698                $retval = array ();
699                $sql = "SELECT user_id FROM content_has_owners WHERE content_id='$this->id' AND is_author=TRUE";
700                $db->ExecSqlUniqueRes($sql, $content_owner_row, false);
701                if ($content_owner_row != null)
702                {
703                        $user = User :: getObject($content_owner_row['user_id']);
704                        $retval[] = $user;
705                }
706
707                return $retval;
708        }
709        /** @see GenricObject
710         * @return The id */
711        public function getId()
712        {
713                return $this->id;
714        }
715
716        /** When a content object is set as trivial, it means that is is used merely to contain it's own data.  No title, description or other data will be set or displayed, during display or administration
717         * @param $is_trivial true or false */
718        public function setIsTrivialContent($is_trivial)
719        {
720                $this->is_trivial_content = $is_trivial;
721        }
722
723        /** 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.
724         * @param $subclass_admin_interface Html content of the interface element of a children
725         * @return The HTML fragment for this interface */
726        public function getUserUI($subclass_user_interface = null)
727        {
728                $html = '';
729                $html .= "<div class='user_ui_main_outer'>\n";
730                $html .= "<div class='user_ui_main_inner'>\n";
731                $html .= "<div class='user_ui_object_class'>Content (".get_class($this)." instance)</div>\n";
732
733                if (!empty ($this->content_row['title']))
734                {
735                        $html .= "<div class='user_ui_title'>\n";
736                        $title = self :: getObject($this->content_row['title']);
737                        // If the content logging is disabled, all the children will inherit this property temporarly
738                        if ($this->getLoggingStatus() == false)
739                                $title->setLoggingStatus(false);
740                        $html .= $title->getUserUI();
741                        $html .= "</div>\n";
742                }
743
744                $html .= "<table><tr>\n";
745                $html .= "<td>\n$subclass_user_interface</td>\n";
746               
747                $html .= "<td>\n";
748                $authors = $this->getAuthors();
749                if (count($authors) > 0)
750                {
751                        $html .= "<div class='user_ui_authors'>\n";
752                        $html .= _("Author(s):");
753                        foreach ($authors as $user)
754                        {
755                                $html .= $user->getUsername()." ";
756                        }
757                        $html .= "</div>\n";
758                }
759
760                if (!empty ($this->content_row['description']))
761                {
762                        $html .= "<div class='user_ui_description'>\n";
763                        $description = self :: getObject($this->content_row['description']);
764                        // If the content logging is disabled, all the children will inherit this property temporarly
765                        if ($this->getLoggingStatus() == false)
766                                $description->setLoggingStatus(false);
767                        $html .= $description->getUserUI();
768                        $html .= "</div>\n";
769                }
770
771                if (!empty ($this->content_row['project_info']) || !empty ($this->content_row['sponsor_info']))
772                {
773                        if (!empty ($this->content_row['project_info']))
774                        {
775                                $html .= "<div class='user_ui_projet_info'>\n";
776                                $html .= "<b>"._("Project information:")."</b>";
777                                $project_info = self :: getObject($this->content_row['project_info']);
778                                // If the content logging is disabled, all the children will inherit this property temporarly
779                                if ($this->getLoggingStatus() == false)
780                                        $project_info->setLoggingStatus(false);
781                                $html .= $project_info->getUserUI();
782                                $html .= "</div>\n";
783                        }
784
785                        if (!empty ($this->content_row['sponsor_info']))
786                        {
787                                $html .= "<div class='user_ui_sponsor_info'>\n";
788                                $html .= "<b>"._("Project sponsor:")."</b>";
789                                $sponsor_info = self :: getObject($this->content_row['sponsor_info']);
790                                // If the content logging is disabled, all the children will inherit this property temporarly
791                                if ($this->getLoggingStatus() == false)
792                                        $sponsor_info->setLoggingStatus(false);
793                                $html .= $sponsor_info->getUserUI();
794                                $html .= "</div>\n";
795                        }
796                }
797               
798                $html .= "</td>\n";
799                $html .= "</tr></table>\n";
800
801                $html .= "</div>\n";
802                $html .= "</div>\n";
803                $this->logContentDisplay();
804                return $html;
805        }
806
807        /** Log that this content has just been displayed to the user.  Will only log if the user is logged in */
808        private function logContentDisplay()
809        {
810                if ($this->getLoggingStatus() == true)
811                {
812                        // DEBUG::
813                        //echo "Logging ".get_class($this)." :: ".$this->__toString()."<br>";
814                        $user = User :: getCurrentUser();
815                        $node = Node :: getCurrentNode();
816                        if ($user != null && $node != null)
817                        {
818                                $user_id = $user->getId();
819                                $node_id = $node->getId();
820                                global $db;
821
822                                $sql = "SELECT * FROM content_display_log WHERE user_id='$user_id' AND node_id='$node_id' AND content_id='$this->id'";
823                                $db->ExecSql($sql, $log_rows, false);
824                                if ($log_rows != null)
825                                {
826                                        $sql = "UPDATE content_display_log SET last_display_timestamp = NOW() WHERE user_id='$user_id' AND content_id='$this->id' AND node_id='$node_id'";
827                                }
828                                else
829                                {
830                                        $sql = "INSERT INTO content_display_log (user_id, content_id, node_id) VALUES ('$user_id', '$this->id', '$node_id')";
831                                }
832                                $db->ExecSqlUpdate($sql, false);
833                        }
834                }
835        }
836
837        /** Retreives the list interface of this object.  Anything that overrides this method should call the parent method with it's output at the END of processing.
838         * @param $subclass_admin_interface Html content of the interface element of a children
839         * @return The HTML fragment for this interface */
840        public function getListUI($subclass_list_interface = null)
841        {
842                $html = '';
843                $html .= "<div class='list_ui_container'>\n";
844                $html .= $this->__toString()." (".get_class($this).")\n";
845                $html .= $subclass_list_interface;
846                $html .= "</div>\n";
847                return $html;
848        }
849
850        /** Retreives the admin interface of this object.  Anything that overrides this method should call the parent method with it's output at the END of processing.
851         * @param $subclass_admin_interface Html content of the interface element of a children
852         * @return The HTML fragment for this interface */
853        public function getAdminUI($subclass_admin_interface = null)
854        {
855                global $db;
856                $html = '';
857                $html .= "<div class='admin_container'>\n";
858                $html .= "<div class='admin_class'>Content (".get_class($this)." instance)</div>\n";
859                if ($this->getObjectType() == 'Content') /* The object hasn't yet been typed */
860                {
861                        $html .= _("You must select a content type: ");
862                        $i = 0;
863                        foreach (self :: getAvailableContentTypes() as $classname)
864                        {
865                                $tab[$i][0] = $classname;
866                                $tab[$i][1] = $classname;
867                                $i ++;
868                        }
869                        $html .= FormSelectGenerator :: generateFromArray($tab, null, "content_".$this->id."_content_type", "Content", false);
870                }
871                else
872                        if ($this->is_trivial_content == false)
873                        {
874                                /* title */
875                                $html .= "<div class='admin_section_container'>\n";
876                                $html .= "<div class='admin_section_title'>"._("Title:")."</div>\n";
877                                $html .= "<div class='admin_section_data'>\n";
878                                if (empty ($this->content_row['title']))
879                                {
880                                        $html .= self :: getNewContentUI("title_{$this->id}_new");
881                                        $html .= "</div>\n";
882                                }
883                                else
884                                {
885                                        $title = self :: getObject($this->content_row['title']);
886                                        $html .= $title->getAdminUI();
887                                        $html .= "</div>\n";
888                                        $html .= "<div class='admin_section_tools'>\n";
889                                        $name = "content_".$this->id."_title_erase";
890                                        $html .= "<input type='submit' name='$name' value='"._("Delete")."'>";
891                                        $html .= "</div>\n";
892                                }
893                                $html .= "</div>\n";
894
895                                /* is_persistent */
896                                $html .= "<div class='admin_section_container'>\n";
897                                $html .= "<div class='admin_section_title'>Is persistent (reusable and read-only)?: </div>\n";
898                                $html .= "<div class='admin_section_data'>\n";
899                                $name = "content_".$this->id."_is_persistent";
900                                $this->isPersistent() ? $checked = 'CHECKED' : $checked = '';
901                                $html .= "<input type='checkbox' name='$name' $checked>\n";
902                                $html .= "</div>\n";
903                                $html .= "</div>\n";
904
905                                /* description */
906                                $html .= "<div class='admin_section_container'>\n";
907                                $html .= "<div class='admin_section_title'>"._("Description:")."</div>\n";
908                                $html .= "<div class='admin_section_data'>\n";
909                                if (empty ($this->content_row['description']))
910                                {
911                                        $html .= self :: getNewContentUI("description_{$this->id}_new");
912                                        $html .= "</div>\n";
913                                }
914                                else
915                                {
916                                        $description = self :: getObject($this->content_row['description']);
917                                        $html .= $description->getAdminUI();
918                                        $html .= "</div>\n";
919                                        $html .= "<div class='admin_section_tools'>\n";
920                                        $name = "content_".$this->id."_description_erase";
921                                        $html .= "<input type='submit' name='$name' value='"._("Delete")."'>";
922                                        $html .= "</div>\n";
923                                }
924                                $html .= "</div>\n";
925
926                                /* long description */
927                                $html .= "<div class='admin_section_container'>\n";
928                                $html .= "<div class='admin_section_title'>"._("Long description:")."</div>\n";
929                                $html .= "<div class='admin_section_data'>\n";
930                                if (empty ($this->content_row['long_description']))
931                                {
932                                        $html .= self :: getNewContentUI("long_description_{$this->id}_new");
933                                        $html .= "</div>\n";
934                                }
935                                else
936                                {
937                                        $description = self :: getObject($this->content_row['long_description']);
938                                        $html .= $description->getAdminUI();
939                                        $html .= "</div>\n";
940                                        $html .= "<div class='admin_section_tools'>\n";
941                                        $name = "content_".$this->id."_long_description_erase";
942                                        $html .= "<input type='submit' name='$name' value='"._("Delete")."'>";
943                                        $html .= "</div>\n";
944                                }
945                                $html .= "</div>\n";
946
947                                /* project_info */
948                                $html .= "<div class='admin_section_container'>\n";
949                                $html .= "<div class='admin_section_title'>"._("Information on this project:")."</div>\n";
950                                $html .= "<div class='admin_section_data'>\n";
951                                if (empty ($this->content_row['project_info']))
952                                {
953                                        $html .= self :: getNewContentUI("project_info_{$this->id}_new");
954                                        $html .= "</div>\n";
955                                }
956                                else
957                                {
958                                        $project_info = self :: getObject($this->content_row['project_info']);
959                                        $html .= $project_info->getAdminUI();
960                                        $html .= "</div>\n";
961                                        $html .= "<div class='admin_section_tools'>\n";
962                                        $name = "content_".$this->id."_project_info_erase";
963                                        $html .= "<input type='submit' name='$name' value='"._("Delete")."'>";
964                                        $html .= "</div>\n";
965                                }
966                                $html .= "</div>\n";
967
968                                /* sponsor_info */
969                                $html .= "<div class='admin_section_container'>\n";
970                                $html .= "<div class='admin_section_title'>"._("Sponsor of this project:")."</div>\n";
971                                $html .= "<div class='admin_section_data'>\n";
972                                if (empty ($this->content_row['sponsor_info']))
973                                {
974                                        $html .= self :: getNewContentUI("sponsor_info_{$this->id}_new");
975                                        $html .= "</div>\n";
976                                }
977                                else
978                                {
979                                        $sponsor_info = self :: getObject($this->content_row['sponsor_info']);
980                                        $html .= $sponsor_info->getAdminUI();
981                                        $html .= "</div>\n";
982                                        $html .= "<div class='admin_section_tools'>\n";
983                                        $name = "content_".$this->id."_sponsor_info_erase";
984                                        $html .= "<input type='submit' name='$name' value='"._("Delete")."'>";
985                                        $html .= "</div>\n";
986                                }
987                                $html .= "</div>\n";
988
989                                /* content_has_owners */
990                                $html .= "<div class='admin_section_container'>\n";
991                                $html .= "<span class='admin_section_title'>"._("Content owner list")."</span>\n";
992                                $html .= "<ul class='admin_section_list'>\n";
993
994                                global $db;
995                                $sql = "SELECT * FROM content_has_owners WHERE content_id='$this->id'";
996                                $db->ExecSql($sql, $content_owner_rows, false);
997                                if ($content_owner_rows != null)
998                                {
999                                        foreach ($content_owner_rows as $content_owner_row)
1000                                        {
1001                                                $html .= "<li class='admin_section_list_item'>\n";
1002                                                $html .= "<div class='admin_section_data'>\n";
1003                                                $user = User :: getObject($content_owner_row['user_id']);
1004
1005                                                $html .= $user->getUserListUI();
1006                                                $name = "content_".$this->id."_owner_".$user->GetId()."_is_author";
1007                                                $html .= " Is content author? ";
1008
1009                                                $content_owner_row['is_author'] == 't' ? $checked = 'CHECKED' : $checked = '';
1010                                                $html .= "<input type='checkbox' name='$name' $checked>\n";
1011                                                $html .= "</div>\n";
1012                                                $html .= "<div class='admin_section_tools'>\n";
1013                                                $name = "content_".$this->id."_owner_".$user->GetId()."_remove";
1014                                                $html .= "<input type='submit' name='$name' value='"._("Remove")."'>";
1015                                                $html .= "</div>\n";
1016                                                $html .= "</li>\n";
1017                                        }
1018                                }
1019
1020                                $html .= "<li class='admin_section_list_item'>\n";
1021                                $html .= "<div class='admin_section_data'>\n";
1022                                $html .= User :: getSelectUserUI("content_{$this->id}_new_owner");
1023                                $html .= "</div>\n";
1024                                $html .= "<div class='admin_section_tools'>\n";
1025                                $name = "content_{$this->id}_add_owner_submit";
1026                                $value = _("Add owner");
1027                                $html .= "<input type='submit' name='$name' value='$value'>";
1028                                $html .= "</div>\n";
1029                                $html .= "</li>\n";
1030                                $html .= "</ul>\n";
1031                                $html .= "</div>\n";
1032                        }
1033                $html .= $subclass_admin_interface;
1034                $html .= "</div>\n";
1035                return $html;
1036        }
1037        /** Process admin interface of this object.  When an object overrides this method, they should call the parent processAdminUI at the BEGINING of processing.
1038       
1039        */
1040        public function processAdminUI()
1041        {
1042                if ($this->isOwner(User :: getCurrentUser()) || User :: getCurrentUser()->isSuperAdmin())
1043                {
1044                        global $db;
1045                        if ($this->getObjectType() == 'Content') /* The object hasn't yet been typed */
1046                        {
1047                                $content_type = FormSelectGenerator :: getResult("content_".$this->id."_content_type", "Content");
1048                                $this->setContentType($content_type);
1049                        }
1050                        else
1051                                if ($this->is_trivial_content == false)
1052                                {
1053                                        /* title */
1054                                        if (empty ($this->content_row['title']))
1055                                        {
1056                                                $title = self :: processNewContentUI("title_{$this->id}_new");
1057                                                if ($title != null)
1058                                                {
1059                                                        $title_id = $title->GetId();
1060                                                        $db->ExecSqlUpdate("UPDATE content SET title = '$title_id' WHERE content_id = '$this->id'", FALSE);
1061                                                }
1062                                        }
1063                                        else
1064                                        {
1065                                                $title = self :: getObject($this->content_row['title']);
1066                                                $name = "content_".$this->id."_title_erase";
1067                                                if (!empty ($_REQUEST[$name]) && $_REQUEST[$name] == true)
1068                                                {
1069                                                        $db->ExecSqlUpdate("UPDATE content SET title = NULL WHERE content_id = '$this->id'", FALSE);
1070                                                        $title->delete($errmsg);
1071                                                }
1072                                                else
1073                                                {
1074                                                        $title->processAdminUI();
1075                                                }
1076                                        }
1077
1078                                        /* is_persistent */
1079                                        $name = "content_".$this->id."_is_persistent";
1080                                        !empty ($_REQUEST[$name]) ? $this->setIsPersistent(true) : $this->setIsPersistent(false);
1081
1082                                        /* description */
1083                                        if (empty ($this->content_row['description']))
1084                                        {
1085                                                $description = self :: processNewContentUI("description_{$this->id}_new");
1086                                                if ($description != null)
1087                                                {
1088                                                        $description_id = $description->GetId();
1089                                                        $db->ExecSqlUpdate("UPDATE content SET description = '$description_id' WHERE content_id = '$this->id'", FALSE);
1090                                                }
1091                                        }
1092                                        else
1093                                        {
1094                                                $description = self :: getObject($this->content_row['description']);
1095                                                $name = "content_".$this->id."_description_erase";
1096                                                if (!empty ($_REQUEST[$name]) && $_REQUEST[$name] == true)
1097                                                {
1098                                                        $db->ExecSqlUpdate("UPDATE content SET description = NULL WHERE content_id = '$this->id'", FALSE);
1099                                                        $description->delete($errmsg);
1100                                                }
1101                                                else
1102                                                {
1103                                                        $description->processAdminUI();
1104                                                }
1105                                        }
1106
1107                                        /* long description */
1108                                        if (empty ($this->content_row['long_description']))
1109                                        {
1110                                                $long_description = self :: processNewContentUI("long_description_{$this->id}_new");
1111                                                if ($long_description != null)
1112                                                {
1113                                                        $long_description_id = $long_description->GetId();
1114                                                        $db->ExecSqlUpdate("UPDATE content SET long_description = '$long_description_id' WHERE content_id = '$this->id'", FALSE);
1115                                                }
1116                                        }
1117                                        else
1118                                        {
1119                                                $long_description = self :: getObject($this->content_row['long_description']);
1120                                                $name = "content_".$this->id."_long_description_erase";
1121                                                if (!empty ($_REQUEST[$name]) && $_REQUEST[$name] == true)
1122                                                {
1123                                                        $db->ExecSqlUpdate("UPDATE content SET long_description = NULL WHERE content_id = '$this->id'", FALSE);
1124                                                        $long_description->delete($errmsg);
1125                                                }
1126                                                else
1127                                                {
1128                                                        $long_description->processAdminUI();
1129                                                }
1130                                        }
1131
1132                                        /* project_info */
1133                                        if (empty ($this->content_row['project_info']))
1134                                        {
1135                                                $project_info = self :: processNewContentUI("project_info_{$this->id}_new");
1136                                                if ($project_info != null)
1137                                                {
1138                                                        $project_info_id = $project_info->GetId();
1139                                                        $db->ExecSqlUpdate("UPDATE content SET project_info = '$project_info_id' WHERE content_id = '$this->id'", FALSE);
1140                                                }
1141                                        }
1142                                        else
1143                                        {
1144                                                $project_info = self :: getObject($this->content_row['project_info']);
1145                                                $name = "content_".$this->id."_project_info_erase";
1146                                                if (!empty ($_REQUEST[$name]) && $_REQUEST[$name] == true)
1147                                                {
1148                                                        $db->ExecSqlUpdate("UPDATE content SET project_info = NULL WHERE content_id = '$this->id'", FALSE);
1149                                                        $project_info->delete($errmsg);
1150                                                }
1151                                                else
1152                                                {
1153                                                        $project_info->processAdminUI();
1154                                                }
1155                                        }
1156
1157                                        /* sponsor_info */
1158                                        if (empty ($this->content_row['sponsor_info']))
1159                                        {
1160                                                $sponsor_info = self :: processNewContentUI("sponsor_info_{$this->id}_new");
1161                                                if ($sponsor_info != null)
1162                                                {
1163                                                        $sponsor_info_id = $sponsor_info->GetId();
1164                                                        $db->ExecSqlUpdate("UPDATE content SET sponsor_info = '$sponsor_info_id' WHERE content_id = '$this->id'", FALSE);
1165                                                }
1166                                        }
1167                                        else
1168                                        {
1169                                                $sponsor_info = self :: getObject($this->content_row['sponsor_info']);
1170                                                $name = "content_".$this->id."_sponsor_info_erase";
1171                                                if (!empty ($_REQUEST[$name]) && $_REQUEST[$name] == true)
1172                                                {
1173                                                        $db->ExecSqlUpdate("UPDATE content SET sponsor_info = NULL WHERE content_id = '$this->id'", FALSE);
1174                                                        $sponsor_info->delete($errmsg);
1175                                                }
1176                                                else
1177                                                {
1178                                                        $sponsor_info->processAdminUI();
1179                                                }
1180                                        }
1181                                        /* content_has_owners */
1182                                        $sql = "SELECT * FROM content_has_owners WHERE content_id='$this->id'";
1183                                        $db->ExecSql($sql, $content_owner_rows, false);
1184                                        if ($content_owner_rows != null)
1185                                        {
1186                                                foreach ($content_owner_rows as $content_owner_row)
1187                                                {
1188                                                        $user = User :: getObject($content_owner_row['user_id']);
1189                                                        $user_id = $user->getId();
1190                                                        $name = "content_".$this->id."_owner_".$user->GetId()."_remove";
1191                                                        if (!empty ($_REQUEST[$name]))
1192                                                        {
1193                                                                $this->deleteOwner($user);
1194                                                        }
1195                                                        else
1196                                                        {
1197                                                                $name = "content_".$this->id."_owner_".$user->GetId()."_is_author";
1198                                                                $content_owner_row['is_author'] == 't' ? $is_author = true : $is_author = false;
1199                                                                !empty ($_REQUEST[$name]) ? $should_be_author = true : $should_be_author = false;
1200                                                                if ($is_author != $should_be_author)
1201                                                                {
1202                                                                        $should_be_author ? $is_author_sql = 'TRUE' : $is_author_sql = 'FALSE';
1203                                                                        $sql = "UPDATE content_has_owners SET is_author=$is_author_sql WHERE content_id='$this->id' AND user_id='$user_id'";
1204
1205                                                                        if (!$db->ExecSqlUpdate($sql, false))
1206                                                                        {
1207                                                                                throw new Exception(_('Unable to set as author in the database.'));
1208                                                                        }
1209
1210                                                                }
1211
1212                                                        }
1213                                                }
1214                                        }
1215                                        $user = User :: processSelectUserUI("content_{$this->id}_new_owner");
1216                                        $name = "content_{$this->id}_add_owner_submit";
1217                                        if (!empty ($_REQUEST[$name]) && $user != null)
1218                                        {
1219                                                $this->addOwner($user);
1220                                        }
1221
1222                                }
1223                        $this->refresh();
1224                }
1225        }
1226
1227        /**
1228         * Tell if a given user is already subscribed to this content
1229         * @param User the given user
1230         * @return boolean
1231         */
1232        public function isUserSubscribed(User $user)
1233        {
1234                global $db;
1235                $sql = "SELECT content_id FROM user_has_content WHERE user_id = '{$user->getId()}' AND content_id = '{$this->getId()}';";
1236                $db->ExecSqlUniqueRes($sql, $row, false);
1237
1238                if ($row)
1239                        return true;
1240                else
1241                        return false;
1242        }
1243
1244        /** Subscribe to the project
1245         * @return true on success, false on failure */
1246        public function subscribe(User $user)
1247        {
1248                return $user->addContent($this);
1249        }
1250        /** Unsubscribe to the project
1251         * @return true on success, false on failure */
1252        public function unsubscribe(User $user)
1253        {
1254                return $user->removeContent($this);
1255        }
1256
1257        /** Persistent (or read-only) content is meant for re-use.  It will not be deleted when the delete() method is called.  When a containing element (ContentGroup, ContentGroupElement) is deleted, it calls delete on all the content it includes.  If the content is persistent, only the association will be removed.
1258        * @return true or false */
1259        public function isPersistent()
1260        {
1261                if ($this->content_row['is_persistent'] == 't')
1262                {
1263                        $retval = true;
1264                }
1265                else
1266                {
1267                        $retval = false;
1268                }
1269                return $retval;
1270        }
1271
1272        /** Set if the content group is persistent
1273         * @param $is_locative_content true or false
1274         * */
1275        public function setIsPersistent($is_persistent)
1276        {
1277                if ($is_persistent != $this->isPersistent()) /* Only update database if there is an actual change */
1278                {
1279                        $is_persistent ? $is_persistent_sql = 'TRUE' : $is_persistent_sql = 'FALSE';
1280
1281                        global $db;
1282                        $db->ExecSqlUpdate("UPDATE content SET is_persistent = $is_persistent_sql WHERE content_id = '$this->id'", false);
1283                        $this->refresh();
1284                }
1285
1286        }
1287
1288        /** Reloads the object from the database.  Should normally be called after a set operation.
1289         * This function is private because calling it from a subclass will call the
1290         * constructor from the wrong scope */
1291        private function refresh()
1292        {
1293                $this->__construct($this->id);
1294        }
1295
1296        /** @see GenericObject
1297         * @note Persistent content will not be deleted
1298        */
1299        public function delete(& $errmsg)
1300        {
1301                $retval = false;
1302                if ($this->isPersistent())
1303                {
1304                        $errmsg = _("Content is persistent (you must make it non persistent before you can delete it)");
1305                }
1306                else
1307                {
1308                        global $db;
1309                        if ($this->isOwner(User :: getCurrentUser()) || User :: getCurrentUser()->isSuperAdmin())
1310                        {
1311                                $sql = "DELETE FROM content WHERE content_id='$this->id'";
1312                                $db->ExecSqlUpdate($sql, false);
1313                                $retval = true;
1314                        }
1315                        else
1316                        {
1317                                $errmsg = _("Access denied (not owner of content)");
1318                        }
1319                }
1320                return $retval;
1321        }
1322
1323} // End class
1324
1325/* This allows the class to enumerate it's children properly */
1326$class_names = Content :: getAvailableContentTypes();
1327foreach ($class_names as $class_name)
1328{
1329        require_once BASEPATH."classes/Content/{$class_name}/{$class_name}.php";
1330}
1331?>
Note: See TracBrowser for help on using the browser.