| 1 | <?php |
|---|
| 2 | |
|---|
| 3 | |
|---|
| 4 | /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ |
|---|
| 5 | |
|---|
| 6 | // +-------------------------------------------------------------------+ |
|---|
| 7 | // | WiFiDog Authentication Server | |
|---|
| 8 | // | ============================= | |
|---|
| 9 | // | | |
|---|
| 10 | // | The WiFiDog Authentication Server is part of the WiFiDog captive | |
|---|
| 11 | // | portal suite. | |
|---|
| 12 | // +-------------------------------------------------------------------+ |
|---|
| 13 | // | PHP version 5 required. | |
|---|
| 14 | // +-------------------------------------------------------------------+ |
|---|
| 15 | // | Homepage: http://www.wifidog.org/ | |
|---|
| 16 | // | Source Forge: http://sourceforge.net/projects/wifidog/ | |
|---|
| 17 | // +-------------------------------------------------------------------+ |
|---|
| 18 | // | This program is free software; you can redistribute it and/or | |
|---|
| 19 | // | modify it under the terms of the GNU General Public License as | |
|---|
| 20 | // | published by the Free Software Foundation; either version 2 of | |
|---|
| 21 | // | the License, or (at your option) any later version. | |
|---|
| 22 | // | | |
|---|
| 23 | // | This program is distributed in the hope that it will be useful, | |
|---|
| 24 | // | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
|---|
| 25 | // | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
|---|
| 26 | // | GNU General Public License for more details. | |
|---|
| 27 | // | | |
|---|
| 28 | // | You should have received a copy of the GNU General Public License | |
|---|
| 29 | // | along with this program; if not, contact: | |
|---|
| 30 | // | | |
|---|
| 31 | // | Free Software Foundation Voice: +1-617-542-5942 | |
|---|
| 32 | // | 59 Temple Place - Suite 330 Fax: +1-617-542-2652 | |
|---|
| 33 | // | Boston, MA 02111-1307, USA gnu@gnu.org | |
|---|
| 34 | // | | |
|---|
| 35 | // +-------------------------------------------------------------------+ |
|---|
| 36 | |
|---|
| 37 | /** |
|---|
| 38 | * @package WiFiDogAuthServer |
|---|
| 39 | * @subpackage ContentClasses |
|---|
| 40 | * @author Benoit Grégoire <benoitg@coeus.ca> |
|---|
| 41 | * @copyright 2005-2006 Benoit Grégoire, Technologies Coeus inc. |
|---|
| 42 | * @version Subversion $Id$ |
|---|
| 43 | * @link http://www.wifidog.org/ |
|---|
| 44 | */ |
|---|
| 45 | |
|---|
| 46 | /** |
|---|
| 47 | * Load required classes |
|---|
| 48 | */ |
|---|
| 49 | require_once ('classes/FormSelectGenerator.php'); |
|---|
| 50 | require_once ('classes/GenericObject.php'); |
|---|
| 51 | require_once ('classes/Cache.php'); |
|---|
| 52 | require_once ('classes/HyperLinkUtils.php'); |
|---|
| 53 | |
|---|
| 54 | /** |
|---|
| 55 | * Defines any type of content |
|---|
| 56 | * |
|---|
| 57 | * @package WiFiDogAuthServer |
|---|
| 58 | * @subpackage ContentClasses |
|---|
| 59 | * @author Benoit Grégoire <benoitg@coeus.ca> |
|---|
| 60 | * @copyright 2005-2006 Benoit Grégoire, Technologies Coeus inc. |
|---|
| 61 | */ |
|---|
| 62 | class Content implements GenericObject { |
|---|
| 63 | /** Object cache for the object factory (getObject())*/ |
|---|
| 64 | private static $instanceArray = array (); |
|---|
| 65 | /** |
|---|
| 66 | * Id of content |
|---|
| 67 | * |
|---|
| 68 | * @var string */ |
|---|
| 69 | protected $id; |
|---|
| 70 | |
|---|
| 71 | /** |
|---|
| 72 | * Array containg content from database |
|---|
| 73 | * |
|---|
| 74 | * @var array */ |
|---|
| 75 | protected $content_row; |
|---|
| 76 | |
|---|
| 77 | /** |
|---|
| 78 | * Array containg the key-value pairs (KVP) for this content instance |
|---|
| 79 | * |
|---|
| 80 | * @var array */ |
|---|
| 81 | protected $kvps; |
|---|
| 82 | /** |
|---|
| 83 | * Type of content |
|---|
| 84 | * |
|---|
| 85 | * @var string |
|---|
| 86 | */ |
|---|
| 87 | private $content_type; |
|---|
| 88 | |
|---|
| 89 | /** |
|---|
| 90 | * Defines if logging is enabled or not |
|---|
| 91 | * |
|---|
| 92 | * @var bool |
|---|
| 93 | */ |
|---|
| 94 | private $is_logging_enabled; |
|---|
| 95 | |
|---|
| 96 | /** Log as part of this other content */ |
|---|
| 97 | private $log_as_content; |
|---|
| 98 | |
|---|
| 99 | /** The html to be shown in the interaction area of the content */ |
|---|
| 100 | private $user_ui_interaction_area; |
|---|
| 101 | |
|---|
| 102 | /** The html to be shown in the main display area of the content */ |
|---|
| 103 | private $user_ui_main_content; |
|---|
| 104 | /** |
|---|
| 105 | * Constructor |
|---|
| 106 | * |
|---|
| 107 | * @param string $content_id Id of content |
|---|
| 108 | * |
|---|
| 109 | * @return void |
|---|
| 110 | */ |
|---|
| 111 | protected function __construct($content_id) { |
|---|
| 112 | //echo "Content::__construct($content_id)<br/>\n"; |
|---|
| 113 | $db = AbstractDb :: getObject(); |
|---|
| 114 | |
|---|
| 115 | // Init values |
|---|
| 116 | $row = null; |
|---|
| 117 | |
|---|
| 118 | // Get content from database |
|---|
| 119 | $content_id = $db->escapeString($content_id); |
|---|
| 120 | $sql = "SELECT * FROM content WHERE content_id='$content_id'"; |
|---|
| 121 | $db->execSqlUniqueRes($sql, $row, false); |
|---|
| 122 | |
|---|
| 123 | if ($row == null) { |
|---|
| 124 | throw new Exception(_("The content with the following id could not be found in the database: ") . $content_id); |
|---|
| 125 | } |
|---|
| 126 | |
|---|
| 127 | $this->content_row = $row; |
|---|
| 128 | $this->id = $row['content_id']; |
|---|
| 129 | $this->content_type = $row['content_type']; |
|---|
| 130 | $kvp_rows = null; |
|---|
| 131 | $sql = "SELECT key, value FROM content_key_value_pairs WHERE content_id='$content_id'"; |
|---|
| 132 | $db->execSql($sql, $kvp_rows, false); |
|---|
| 133 | if ($kvp_rows) { |
|---|
| 134 | foreach ($kvp_rows as $kvp_row) { |
|---|
| 135 | $this->kvps[$kvp_row['key']] = $kvp_row['value']; |
|---|
| 136 | } |
|---|
| 137 | } |
|---|
| 138 | // By default content display logging is enabled |
|---|
| 139 | $this->setLoggingStatus(true); |
|---|
| 140 | $this->log_as_content = & $this; |
|---|
| 141 | } |
|---|
| 142 | |
|---|
| 143 | /** |
|---|
| 144 | * A short string representation of the content |
|---|
| 145 | * |
|---|
| 146 | * @return string String representation of the content |
|---|
| 147 | */ |
|---|
| 148 | public function __toString() { |
|---|
| 149 | if (empty ($this->content_row['title'])) { |
|---|
| 150 | $string = _("Untitled content"); |
|---|
| 151 | } else { |
|---|
| 152 | $title = self :: getObject($this->content_row['title']); |
|---|
| 153 | $string = $title->__toString(); |
|---|
| 154 | } |
|---|
| 155 | |
|---|
| 156 | return $string; |
|---|
| 157 | } |
|---|
| 158 | |
|---|
| 159 | /** |
|---|
| 160 | * Create a new Content object in the database |
|---|
| 161 | * |
|---|
| 162 | * @param string $content_type The content type to be given to the new object |
|---|
| 163 | * @param string $id The id to be given to the new Content. If |
|---|
| 164 | * null, a new id will be assigned |
|---|
| 165 | * |
|---|
| 166 | * @return object The newly created Content object, or null if there was an |
|---|
| 167 | * error (an exception is also trown) |
|---|
| 168 | |
|---|
| 169 | */ |
|---|
| 170 | public static function createNewObject($content_type = "Content", $id = null) { |
|---|
| 171 | |
|---|
| 172 | $db = AbstractDb :: getObject(); |
|---|
| 173 | |
|---|
| 174 | if (empty ($id)) { |
|---|
| 175 | $contentId = get_guid(); |
|---|
| 176 | } else { |
|---|
| 177 | $contentId = $db->escapeString($id); |
|---|
| 178 | } |
|---|
| 179 | |
|---|
| 180 | if (empty ($content_type)) { |
|---|
| 181 | throw new Exception(_('Content type is optionnal, but cannot be empty!')); |
|---|
| 182 | } else { |
|---|
| 183 | $content_type = $db->escapeString($content_type); |
|---|
| 184 | } |
|---|
| 185 | |
|---|
| 186 | $sql = "INSERT INTO content (content_id, content_type) VALUES ('$contentId', '$content_type')"; |
|---|
| 187 | |
|---|
| 188 | if (!$db->execSqlUpdate($sql, false)) { |
|---|
| 189 | throw new Exception(_('Unable to insert new content into database!')); |
|---|
| 190 | } |
|---|
| 191 | |
|---|
| 192 | $object = self :: getObject($contentId); |
|---|
| 193 | |
|---|
| 194 | // At least add the current user as the default owner |
|---|
| 195 | $object->AddOwner(User :: getCurrentUser()); |
|---|
| 196 | |
|---|
| 197 | // By default, make it persistent |
|---|
| 198 | $object->setIsPersistent(true); |
|---|
| 199 | |
|---|
| 200 | return $object; |
|---|
| 201 | } |
|---|
| 202 | |
|---|
| 203 | /** |
|---|
| 204 | * Get an interface to create a new object. |
|---|
| 205 | * |
|---|
| 206 | * @return string HTML markup |
|---|
| 207 | */ |
|---|
| 208 | public static function getCreateNewObjectUI() { |
|---|
| 209 | // Init values |
|---|
| 210 | $html = ""; |
|---|
| 211 | $i = 0; |
|---|
| 212 | $tab = array (); |
|---|
| 213 | |
|---|
| 214 | foreach (self :: getAvailableContentTypes() as $className) { |
|---|
| 215 | $tab[$i][0] = $className; |
|---|
| 216 | $tab[$i][1] = $className; |
|---|
| 217 | $i++; |
|---|
| 218 | } |
|---|
| 219 | |
|---|
| 220 | if (empty ($tab)) { |
|---|
| 221 | $html .= _("It appears that you have not installed any Content plugin !"); |
|---|
| 222 | } else { |
|---|
| 223 | $html .= _("You must select a content type: "); |
|---|
| 224 | $html .= FormSelectGenerator :: generateFromArray($tab, "TrivialLangstring", "new_content_content_type", "Content", false); |
|---|
| 225 | } |
|---|
| 226 | |
|---|
| 227 | return $html; |
|---|
| 228 | } |
|---|
| 229 | |
|---|
| 230 | /** |
|---|
| 231 | * Process the new object interface |
|---|
| 232 | * |
|---|
| 233 | * Will return the new object if the user has the credentials |
|---|
| 234 | * necessary (else an exception is thrown) and if the form was fully |
|---|
| 235 | * filled (else the object returns null). |
|---|
| 236 | * |
|---|
| 237 | * @return object The node object or null if no new node was created |
|---|
| 238 | */ |
|---|
| 239 | public static function processCreateNewObjectUI() { |
|---|
| 240 | // Init values |
|---|
| 241 | $retVal = null; |
|---|
| 242 | |
|---|
| 243 | $contentType = FormSelectGenerator :: getResult("new_content_content_type", "Content"); |
|---|
| 244 | |
|---|
| 245 | if ($contentType) { |
|---|
| 246 | $retVal = self :: createNewObject($contentType); |
|---|
| 247 | } |
|---|
| 248 | |
|---|
| 249 | return $retVal; |
|---|
| 250 | } |
|---|
| 251 | |
|---|
| 252 | /** |
|---|
| 253 | * Get the content object, specific to it's content type |
|---|
| 254 | * |
|---|
| 255 | * @param string $content_id The content Id |
|---|
| 256 | * |
|---|
| 257 | * @return object The Content object, or null if there was an error |
|---|
| 258 | * (an exception is also thrown) |
|---|
| 259 | |
|---|
| 260 | */ |
|---|
| 261 | public static function &getObject($content_id) { |
|---|
| 262 | //echo "Content::g e tObject(".$content_id.")<br/>\n"; |
|---|
| 263 | if (!isset (self :: $instanceArray[$content_id])) { |
|---|
| 264 | //echo "Cache MISS!<br/>\n"; |
|---|
| 265 | $db = AbstractDb :: getObject(); |
|---|
| 266 | |
|---|
| 267 | // Init values |
|---|
| 268 | $row = null; |
|---|
| 269 | |
|---|
| 270 | $content_id = $db->escapeString($content_id); |
|---|
| 271 | $sql = "SELECT content_type FROM content WHERE content_id='$content_id'"; |
|---|
| 272 | $db->execSqlUniqueRes($sql, $row, false); |
|---|
| 273 | |
|---|
| 274 | if ($row == null) { |
|---|
| 275 | throw new Exception(_("The content with the following id could not be found in the database: ") . $content_id); |
|---|
| 276 | } |
|---|
| 277 | if (!class_exists($row['content_type'])) { |
|---|
| 278 | //throw new Exception(_("The following content type isn't valid: ").$row['content_type']); |
|---|
| 279 | $object = null; |
|---|
| 280 | } else { |
|---|
| 281 | self :: $instanceArray[$content_id] = new $row['content_type'] ($content_id); |
|---|
| 282 | $object = self :: $instanceArray[$content_id]; |
|---|
| 283 | } |
|---|
| 284 | } else { |
|---|
| 285 | //echo "Cache HIT!<br/>\n"; |
|---|
| 286 | $object = self :: $instanceArray[$content_id]; |
|---|
| 287 | } |
|---|
| 288 | return $object; |
|---|
| 289 | |
|---|
| 290 | } |
|---|
| 291 | |
|---|
| 292 | /** |
|---|
| 293 | * Get the list of available content type on the system |
|---|
| 294 | * |
|---|
| 295 | * @return array An array of class names |
|---|
| 296 | */ |
|---|
| 297 | public static function getAvailableContentTypes() { |
|---|
| 298 | // Init values |
|---|
| 299 | $contentTypes = array (); |
|---|
| 300 | $useCache = false; |
|---|
| 301 | $cachedData = null; |
|---|
| 302 | |
|---|
| 303 | // Create new cache object with a lifetime of one week |
|---|
| 304 | $cache = new Cache("ContentClasses", "ClassFileCaches", 604800); |
|---|
| 305 | |
|---|
| 306 | // Check if caching has been enabled. |
|---|
| 307 | if ($cache->isCachingEnabled) { |
|---|
| 308 | $cachedData = $cache->getCachedData("mixed"); |
|---|
| 309 | |
|---|
| 310 | if ($cachedData) { |
|---|
| 311 | // Return cached data. |
|---|
| 312 | $useCache = true; |
|---|
| 313 | $contentTypes = $cachedData; |
|---|
| 314 | } |
|---|
| 315 | } |
|---|
| 316 | |
|---|
| 317 | if (!$useCache) { |
|---|
| 318 | $dir = WIFIDOG_ABS_FILE_PATH . "classes/Content"; |
|---|
| 319 | $dirHandle = @ opendir($dir); |
|---|
| 320 | |
|---|
| 321 | if ($dirHandle) { |
|---|
| 322 | // Loop over the directory |
|---|
| 323 | while (false !== ($subDir = readdir($dirHandle))) { |
|---|
| 324 | // Loop through sub-directories of Content |
|---|
| 325 | if ($subDir != '.' && $subDir != '..' && is_dir("{$dir}/{$subDir}")) { |
|---|
| 326 | // Only add directories containing corresponding initial Content class |
|---|
| 327 | if (is_file("{$dir}/{$subDir}/{$subDir}.php")) { |
|---|
| 328 | $contentTypes[] = $subDir; |
|---|
| 329 | } |
|---|
| 330 | } |
|---|
| 331 | } |
|---|
| 332 | |
|---|
| 333 | closedir($dirHandle); |
|---|
| 334 | } else { |
|---|
| 335 | throw new Exception(_('Unable to open directory ') . $dir); |
|---|
| 336 | } |
|---|
| 337 | |
|---|
| 338 | // Cleanup PHP file extensions and sort the result array |
|---|
| 339 | $contentTypes = str_ireplace('.php', '', $contentTypes); |
|---|
| 340 | sort($contentTypes); |
|---|
| 341 | |
|---|
| 342 | // Check if caching has been enabled. |
|---|
| 343 | if ($cache->isCachingEnabled) { |
|---|
| 344 | // Save results into cache, because it wasn't saved into cache before. |
|---|
| 345 | $cache->saveCachedData($contentTypes, "mixed"); |
|---|
| 346 | } |
|---|
| 347 | } |
|---|
| 348 | |
|---|
| 349 | return $contentTypes; |
|---|
| 350 | } |
|---|
| 351 | /** |
|---|
| 352 | * Check if this specific ContentType is usable (all Dependency |
|---|
| 353 | * met,etc. |
|---|
| 354 | * This method is meant to be overloaded by the different content classes |
|---|
| 355 | * @return true or flase |
|---|
| 356 | */ |
|---|
| 357 | public static function isContentTypeFunctional() { |
|---|
| 358 | return true; |
|---|
| 359 | } |
|---|
| 360 | |
|---|
| 361 | /** |
|---|
| 362 | * Check if the ContentType is available on the system * |
|---|
| 363 | * @param string $classname The classname to check |
|---|
| 364 | * @return true or flase |
|---|
| 365 | */ |
|---|
| 366 | public static function isContentTypeAvailable($classname) { |
|---|
| 367 | if (false === array_search($classname, Content :: getAvailableContentTypes(), true)) { |
|---|
| 368 | //throw new Exception(_("The following content type isn't valid: ").$contentType); |
|---|
| 369 | return false; |
|---|
| 370 | } else { |
|---|
| 371 | return call_user_func(array($classname, 'isContentTypeFunctional')); |
|---|
| 372 | } |
|---|
| 373 | } |
|---|
| 374 | |
|---|
| 375 | /** |
|---|
| 376 | * Check if this class is a class or subclass of one of the content types given as parameter |
|---|
| 377 | * * |
|---|
| 378 | * @param array $candidates The classnames to check |
|---|
| 379 | * @return true or flase |
|---|
| 380 | */ |
|---|
| 381 | public static function isContentType($candidates, $classname) { |
|---|
| 382 | $retval = false; |
|---|
| 383 | if (false === is_array($candidates)) { |
|---|
| 384 | throw new exception("classnames must be an array"); |
|---|
| 385 | } |
|---|
| 386 | $classname_reflector = new ReflectionClass($classname); |
|---|
| 387 | |
|---|
| 388 | foreach ($candidates as $candidate) { |
|---|
| 389 | $candidate_reflector = new ReflectionClass($candidate); |
|---|
| 390 | //echo"classname: $classname, candidate: $candidate<br>"; |
|---|
| 391 | if ($candidate == $classname || $classname_reflector->isSubclassOf($candidate_reflector)) { |
|---|
| 392 | //As of PHP5.2, it would apear that isSubclass means a strict sublclass, so the first check was added. |
|---|
| 393 | //The content meets the criteria |
|---|
| 394 | //echo "TRUE<br>"; |
|---|
| 395 | $retval = true; |
|---|
| 396 | break; |
|---|
| 397 | } |
|---|
| 398 | } |
|---|
| 399 | return $retval; |
|---|
| 400 | } |
|---|
| 401 | |
|---|
| 402 | /** |
|---|
| 403 | * Check if this class is a class or subclass of one of the content types given as parameter |
|---|
| 404 | * * |
|---|
| 405 | * @param array $candidates The classnames to check |
|---|
| 406 | * @return true or flase |
|---|
| 407 | */ |
|---|
| 408 | public static function isExactContentType($candidates, $classname) { |
|---|
| 409 | $retval = false; |
|---|
| 410 | if (false === is_array($candidates)) { |
|---|
| 411 | throw new exception("classnames must be an array"); |
|---|
| 412 | } |
|---|
| 413 | //$classname_reflector = new ReflectionClass($classname); |
|---|
| 414 | |
|---|
| 415 | foreach ($candidates as $candidate) { |
|---|
| 416 | //$candidate_reflector = new ReflectionClass($candidate); |
|---|
| 417 | //echo"classname: $classname, candidate: $candidate<br>"; |
|---|
| 418 | if ($candidate == $classname) { |
|---|
| 419 | $retval = true; |
|---|
| 420 | break; |
|---|
| 421 | } |
|---|
| 422 | } |
|---|
| 423 | return $retval; |
|---|
| 424 | } |
|---|
| 425 | |
|---|
| 426 | /** |
|---|
| 427 | * Check if this class is NOT any of the class or subclass of one of the content types given as parameter |
|---|
| 428 | * It's the opposite of isContentType() |
|---|
| 429 | * |
|---|
| 430 | * @param array $candidates The classnames to check |
|---|
| 431 | * @return true or flase |
|---|
| 432 | */ |
|---|
| 433 | public static function isNotContentType($candidates, $classname) { |
|---|
| 434 | return !self :: isContentType($candidates, $classname); |
|---|
| 435 | } |
|---|
| 436 | /** |
|---|
| 437 | * Get all content |
|---|
| 438 | * |
|---|
| 439 | * Can be restricted to a given content type |
|---|
| 440 | * |
|---|
| 441 | * @param string $content_type Type of content |
|---|
| 442 | * |
|---|
| 443 | * @return mixed Requested content |
|---|
| 444 | */ |
|---|
| 445 | public static function getAllContent($content_type = "") { |
|---|
| 446 | |
|---|
| 447 | $db = AbstractDb :: getObject(); |
|---|
| 448 | |
|---|
| 449 | // Init values |
|---|
| 450 | $whereClause = ""; |
|---|
| 451 | $rows = null; |
|---|
| 452 | $objects = array (); |
|---|
| 453 | |
|---|
| 454 | if (!empty ($content_type)) { |
|---|
| 455 | $content_type = $db->escapeString($content_type); |
|---|
| 456 | $whereClause = "WHERE content_type = '$content_type'"; |
|---|
| 457 | } |
|---|
| 458 | |
|---|
| 459 | $db->execSql("SELECT content_id FROM content $whereClause", $rows, false); |
|---|
| 460 | |
|---|
| 461 | if ($rows) { |
|---|
| 462 | foreach ($rows as $row) { |
|---|
| 463 | $objects[] = self :: getObject($row['content_id']); |
|---|
| 464 | } |
|---|
| 465 | } |
|---|
| 466 | |
|---|
| 467 | return $objects; |
|---|
| 468 | } |
|---|
| 469 | |
|---|
| 470 | /** |
|---|
| 471 | * This method contains the interface to add an additional element to a |
|---|
| 472 | * content object. (For example, a new string in a Langstring) |
|---|
| 473 | * It is called when getNewContentUI has only a single possible object type. |
|---|
| 474 | * It may also be called by the object getAdminUI to avoid code duplication. |
|---|
| 475 | * |
|---|
| 476 | * @param string $contentId The id of the (possibly not yet created) content object. |
|---|
| 477 | * |
|---|
| 478 | * @param string $userData=null Array of contextual data optionally sent by displayAdminUI(), |
|---|
| 479 | * and only understood by the class (or subclasses) where getNewUI() is defined. |
|---|
| 480 | * The function must still function if none of it is present. |
|---|
| 481 | * |
|---|
| 482 | * This function understands: |
|---|
| 483 | * $userData['contentTypeFilter'] |
|---|
| 484 | * $userData['calledFromBaseClassNewUI'] |
|---|
| 485 | * @return HTML markup or false. False means that this object does not support this interface. |
|---|
| 486 | */ |
|---|
| 487 | public static function getNewUI($contentId, $userData=null) { |
|---|
| 488 | $db = AbstractDb :: getObject(); |
|---|
| 489 | //echo "Content::getNewUI($contentId,$userData)<br/>\n"; |
|---|
| 490 | |
|---|
| 491 | if(!empty($userData['calledFromBaseClassNewUI'])) { |
|---|
| 492 | //Break recursion if the subclass doesn't overload this method. |
|---|
| 493 | return false; |
|---|
| 494 | } |
|---|
| 495 | |
|---|
| 496 | // Init values |
|---|
| 497 | $html = ""; |
|---|
| 498 | $getNewUIData = null; |
|---|
| 499 | $availableContentTypes = self :: getAvailableContentTypes(); |
|---|
| 500 | |
|---|
| 501 | //echo "Content::getNewUI: userData";pretty_print_r($userData); |
|---|
| 502 | !empty($userData['contentTypeFilter'])?$contentTypeFilter=$userData['contentTypeFilter']:$contentTypeFilter=null; |
|---|
| 503 | //echo "Content::getNewUI: contentTypeFilter";pretty_print_r($contentTypeFilter); |
|---|
| 504 | if (!$contentTypeFilter) { |
|---|
| 505 | //echo "Get an empty filter"; |
|---|
| 506 | $contentTypeFilter = ContentTypeFilter :: getObject(array ()); |
|---|
| 507 | } |
|---|
| 508 | //pretty_print_r($content_type_filter); |
|---|
| 509 | $i = 0; |
|---|
| 510 | $tab = array (); |
|---|
| 511 | foreach ($availableContentTypes as $className) { |
|---|
| 512 | if ($contentTypeFilter->isAcceptableContentClass($className)) { |
|---|
| 513 | $tab[$i][0] = $className; |
|---|
| 514 | $tab[$i][1] = $className; |
|---|
| 515 | $i++; |
|---|
| 516 | } |
|---|
| 517 | } |
|---|
| 518 | $name = "get_new_ui_{$contentId}_content_type"; |
|---|
| 519 | if (count($tab) > 1) { |
|---|
| 520 | $label = _("Add new Content of type") . ": "; |
|---|
| 521 | $html .= "<div class='admin_element_data content_add'>"; |
|---|
| 522 | $html .= $label; |
|---|
| 523 | $html .= FormSelectGenerator :: generateFromArray($tab, 'TrivialLangstring', $name, null, false); |
|---|
| 524 | $html .= "</div>"; |
|---|
| 525 | } else |
|---|
| 526 | if (count($tab) == 1) { |
|---|
| 527 | $html .= '<input type="hidden" name="' . $name . '" value="' . $tab[0][0] . '">'; |
|---|
| 528 | $name = "get_new_ui_{$contentId}_content_type_is_unique"; |
|---|
| 529 | $html .= '<input type="hidden" name="' . $name . '" value="true">'; |
|---|
| 530 | $userData['calledFromBaseClassNewUI']=true; |
|---|
| 531 | $getNewUIData = call_user_func(array ($tab[0][0], 'getNewUI'), $contentId, $userData); |
|---|
| 532 | |
|---|
| 533 | } else { |
|---|
| 534 | throw new Exception(_("No content type matches the filter.")); |
|---|
| 535 | } |
|---|
| 536 | |
|---|
| 537 | if($getNewUIData != null) { |
|---|
| 538 | //If the single possible content type given by the filter defined an interface to directly create a new instance |
|---|
| 539 | $html .= $getNewUIData; |
|---|
| 540 | } |
|---|
| 541 | else { |
|---|
| 542 | if (count($tab) == 1) { |
|---|
| 543 | $value = sprintf(_("Add a %s"), $tab[0][1]); |
|---|
| 544 | } else { |
|---|
| 545 | $value = _("Add"); |
|---|
| 546 | } |
|---|
| 547 | $html .= "<div class='admin_element_tools'>"; |
|---|
| 548 | $name = "get_new_content_{$contentId}_add"; |
|---|
| 549 | $html .= '<input type="submit" class="submit" name="' . $name . '" value="' . $value . '">'; |
|---|
| 550 | $html .= "</div>"; |
|---|
| 551 | } |
|---|
| 552 | return $html; |
|---|
| 553 | } |
|---|
| 554 | |
|---|
| 555 | /** |
|---|
| 556 | * |
|---|
| 557 | * |
|---|
| 558 | * @param string $contentId The id of the (possibly not yet created) content object. |
|---|
| 559 | * |
|---|
| 560 | * @param string $checkOnly If true, only check if there is data to be processed. |
|---|
| 561 | * Will be used to decide if an object is to be created. If there is |
|---|
| 562 | * processNewUI will typically be called again with $chechOnly=false |
|---|
| 563 | * |
|---|
| 564 | * @return true if there was data to be processed, false otherwise |
|---|
| 565 | |
|---|
| 566 | */ |
|---|
| 567 | public static function processNewUI($contentId, $checkOnly=false, $userData=null) { |
|---|
| 568 | //echo "Content::processNewUI($contentId, $checkOnly)"; |
|---|
| 569 | $retval=false; |
|---|
| 570 | if(!empty($userData['calledFromBaseClassNewUI'])) { |
|---|
| 571 | //Break recursion if the subclass doesn't overload this method. |
|---|
| 572 | return false; |
|---|
| 573 | } |
|---|
| 574 | $processNewUIHasData = false; |
|---|
| 575 | $name = "get_new_ui_{$contentId}_content_type"; |
|---|
| 576 | $contentType = FormSelectGenerator :: getResult($name, null); |
|---|
| 577 | |
|---|
| 578 | //Was there data to process |
|---|
| 579 | $name = "get_new_ui_{$contentId}_content_type_is_unique"; |
|---|
| 580 | if(!empty($_REQUEST[$name])){ |
|---|
| 581 | $userData['calledFromBaseClassNewUI']=true; |
|---|
| 582 | $processNewUIHasData = call_user_func(array ($contentType, 'processNewUI'), $contentId, true, $userData); |
|---|
| 583 | } |
|---|
| 584 | //Was add button clicked, or was there data in the new admin UI |
|---|
| 585 | $name = "get_new_content_{$contentId}_add"; |
|---|
| 586 | if ((!empty($_REQUEST[$name]) && $_REQUEST[$name] == true) || $processNewUIHasData) { |
|---|
| 587 | $retval=true; |
|---|
| 588 | if($checkOnly == false) { |
|---|
| 589 | $object = self::getObject($contentId); |
|---|
| 590 | $object->setContentType($contentType); |
|---|
| 591 | if($processNewUIHasData) { |
|---|
| 592 | //If there was data to processs, process it for real |
|---|
| 593 | call_user_func(array ($contentType, 'processNewUI'), $contentId, false); |
|---|
| 594 | } |
|---|
| 595 | } |
|---|
| 596 | } |
|---|
| 597 | |
|---|
| 598 | return $retval; |
|---|
| 599 | } |
|---|
| 600 | |
|---|
| 601 | /** |
|---|
| 602 | * Get a flexible interface to generate new content objects |
|---|
| 603 | * |
|---|
| 604 | * @param string $user_prefix A identifier provided by the programmer |
|---|
| 605 | * to recognise it's generated HTML form |
|---|
| 606 | * @param string $content_type_filter If set, the created content must match the filter. Of only one type matches, |
|---|
| 607 | * the content will be of this type, otherwise, the user will have |
|---|
| 608 | * to choose |
|---|
| 609 | * |
|---|
| 610 | * @return string HTML markup |
|---|
| 611 | */ |
|---|
| 612 | public static function getNewContentUI($user_prefix, $content_type_filter = null, $title = null) { |
|---|
| 613 | //echo "Content::getNewContentUI()"; |
|---|
| 614 | // Init values |
|---|
| 615 | $html = ""; |
|---|
| 616 | $getNewUIData = null; |
|---|
| 617 | $html .= "<fieldset class='admin_container Content'>\n"; |
|---|
| 618 | if (!empty ($title)) { |
|---|
| 619 | $html .= "<legend>$title</legend>\n"; |
|---|
| 620 | } |
|---|
| 621 | $futureContentId = get_guid(); |
|---|
| 622 | $name = "get_new_content_{$user_prefix}_future_id"; |
|---|
| 623 | $html .= '<input type="hidden" name="' . $name . '" value="' . $futureContentId . '">'; |
|---|
| 624 | $userData['contentTypeFilter']=$content_type_filter; |
|---|
| 625 | |
|---|
| 626 | $html .= Content::getNewUI($futureContentId, $userData); |
|---|
| 627 | $html .= "</fieldset>\n"; |
|---|
| 628 | return $html; |
|---|
| 629 | } |
|---|
| 630 | |
|---|
| 631 | /** |
|---|
| 632 | * Get the created content object, IF one was created OR get existing |
|---|
| 633 | * content (depending on what the user clicked) |
|---|
| 634 | * |
|---|
| 635 | * @param string $user_prefix A identifier provided by the |
|---|
| 636 | * programmer to recognise it's |
|---|
| 637 | * generated form |
|---|
| 638 | * @param bool $associate_existing_content If true it allows to get |
|---|
| 639 | * existing object |
|---|
| 640 | * |
|---|
| 641 | * @return object The Content object, or null if the user didn't create one |
|---|
| 642 | |
|---|
| 643 | */ |
|---|
| 644 | public static function processNewContentUI($user_prefix) { |
|---|
| 645 | //echo "Content::processNewContentUI()"; |
|---|
| 646 | // Init values |
|---|
| 647 | $object = null; |
|---|
| 648 | $name = "get_new_content_{$user_prefix}_future_id"; |
|---|
| 649 | $futureContentId = $_REQUEST[$name]; |
|---|
| 650 | |
|---|
| 651 | if(Content::processNewUI($futureContentId, true)) { |
|---|
| 652 | self :: createNewObject('Content', $futureContentId);//The true content type will be set by processNewUI() |
|---|
| 653 | //If there was data to processs, process it for real |
|---|
| 654 | Content::processNewUI($futureContentId, false); |
|---|
| 655 | $object = self :: getObject($futureContentId);//Content type has changed... |
|---|
| 656 | } |
|---|
| 657 | //pretty_print_r($object); |
|---|
| 658 | return $object; |
|---|
| 659 | } |
|---|
| 660 | /** |
|---|
| 661 | * Get the created content object, IF one was created OR get existing |
|---|
| 662 | * content (depending on what the user clicked) |
|---|
| 663 | * |
|---|
| 664 | * @param string $user_prefix A identifier provided by the |
|---|
| 665 | * programmer to recognise it's |
|---|
| 666 | * generated form |
|---|
| 667 | * @return object The Content object, or null if the user didn't create one |
|---|
| 668 | |
|---|
| 669 | */ |
|---|
| 670 | public static function processSelectExistingContentUI($user_prefix) { |
|---|
| 671 | // Init values |
|---|
| 672 | $object = null; |
|---|
| 673 | $name = "{$user_prefix}"; |
|---|
| 674 | /* |
|---|
| 675 | * The result is a content ID |
|---|
| 676 | */ |
|---|
| 677 | $contentUiResult = FormSelectGenerator :: getResult($name, null); |
|---|
| 678 | $name = "{$user_prefix}_add"; |
|---|
| 679 | |
|---|
| 680 | //Was add button clicked, or whare there data in the new admin UI |
|---|
| 681 | if ((!empty($_REQUEST[$name]) && $_REQUEST[$name] == true)) { |
|---|
| 682 | $object = self :: getObject($contentUiResult); |
|---|
| 683 | } |
|---|
| 684 | return $object; |
|---|
| 685 | } |
|---|
| 686 | |
|---|
| 687 | /** |
|---|
| 688 | * Get a flexible interface to manage content linked to a node, a network |
|---|
| 689 | * or anything else |
|---|
| 690 | * |
|---|
| 691 | * @param string $user_prefix A identifier provided by the |
|---|
| 692 | * programmer to recognise it's |
|---|
| 693 | * generated HTML form |
|---|
| 694 | * @param string $link_table Table to link from |
|---|
| 695 | * @param string $link_table_obj_key_col Column in linked table to match |
|---|
| 696 | * @param string $link_table_obj_key Key to be found in linked table |
|---|
| 697 | * @param string $default_display_page |
|---|
| 698 | * @param string $default_display_area |
|---|
| 699 | * @return string HTML markup |
|---|
| 700 | |
|---|
| 701 | */ |
|---|
| 702 | public static function getLinkedContentUI($user_prefix, $link_table, $link_table_obj_key_col, $link_table_obj_key, $default_display_page = 'portal', $default_display_area = 'main_area_middle') { |
|---|
| 703 | |
|---|
| 704 | $db = AbstractDb :: getObject(); |
|---|
| 705 | |
|---|
| 706 | // Init values |
|---|
| 707 | $html = ""; |
|---|
| 708 | |
|---|
| 709 | $link_table = $db->escapeString($link_table); |
|---|
| 710 | $link_table_obj_key_col = $db->escapeString($link_table_obj_key_col); |
|---|
| 711 | $link_table_obj_key = $db->escapeString($link_table_obj_key); |
|---|
| 712 | |
|---|
| 713 | /* Content already linked */ |
|---|
| 714 | $current_content_sql = "SELECT * FROM $link_table WHERE $link_table_obj_key_col='$link_table_obj_key' ORDER BY display_page, display_area, display_order, subscribe_timestamp DESC"; |
|---|
| 715 | $rows = null; |
|---|
| 716 | $db->execSql($current_content_sql, $rows, false); |
|---|
| 717 | |
|---|
| 718 | $html .= "<table class='content_management_tools'>\n"; |
|---|
| 719 | $html .= "<th>" . _('Display page') . '</th><th>' . _('Area') . '</th><th>' . _('Order') . '</th><th>' . _('Content') . '</th><th>' . _('Actions') . '</th>' . "\n"; |
|---|
| 720 | if ($rows) |
|---|
| 721 | foreach ($rows as $row) { |
|---|
| 722 | $content = self :: getObject($row['content_id']); |
|---|
| 723 | $html .= "<tr class='already_linked_content'>\n"; |
|---|
| 724 | /* Display page */ |
|---|
| 725 | $name = "{$user_prefix}_" . $content->GetId() . "_display_page"; |
|---|
| 726 | $html .= "<td>" . FormSelectGenerator :: generateFromTable('content_available_display_pages', 'display_page', 'display_page', $row['display_page'], $name, null) . "</td>\n"; |
|---|
| 727 | $name = "{$user_prefix}_" . $content->GetId() . "_display_area"; |
|---|
| 728 | $html .= "<td>" . FormSelectGenerator :: generateFromTable('content_available_display_areas', 'display_area', 'display_area', $row['display_area'], $name, null) . "</td>\n"; |
|---|
| 729 | $name = "{$user_prefix}_" . $content->GetId() . "_display_order"; |
|---|
| 730 | $html .= "<td><input type='text' name='$name' value='{$row['display_order']}' size=2 class='linked_content_order'></td>\n"; |
|---|
| 731 | $html .= "<td>\n"; |
|---|
| 732 | $html .= $content->getListUI(); |
|---|
| 733 | $html .= "</td>\n"; |
|---|
| 734 | $html .= "<td>\n"; |
|---|
| 735 | $name = "{$user_prefix}_" . $content->GetId() . "_edit"; |
|---|
| 736 | $html .= "<input type='button' class='submit' name='$name' value='" . _("Edit") . "' onClick='window.open(\"" . GENERIC_OBJECT_ADMIN_ABS_HREF . "?object_class=Content&action=edit&object_id=" . $content->GetId() . "\");'>\n"; |
|---|
| 737 | $name = "{$user_prefix}_" . $content->GetId() . "_erase"; |
|---|
| 738 | $html .= "<input type='submit' class='submit' name='$name' value='" . _("Remove") . "'>"; |
|---|
| 739 | $html .= "</td>\n"; |
|---|
| 740 | $html .= "</tr>\n"; |
|---|
| 741 | } |
|---|
| 742 | |
|---|
| 743 | /* Add existing content */ |
|---|
| 744 | $html .= "<tr class='add_existing_content'>\n"; |
|---|
| 745 | $name = "{$user_prefix}_new_existing_display_page"; |
|---|
| 746 | $html .= "<td>" . FormSelectGenerator :: generateFromTable('content_available_display_pages', 'display_page', 'display_page', $default_display_page, $name, null) . "</td>\n"; |
|---|
| 747 | $name = "{$user_prefix}_new_existing_display_area"; |
|---|
| 748 | $html .= "<td>" . FormSelectGenerator :: generateFromTable('content_available_display_areas', 'display_area', 'display_area', $default_display_area, $name, null) . "</td>\n"; |
|---|
| 749 | $name = "{$user_prefix}_new_existing_display_order"; |
|---|
| 750 | $html .= "<td><input type='text' name='$name' value='1' size=2 class='linked_content_order'></td>\n"; |
|---|
| 751 | $html .= "<td colspan=2>\n"; |
|---|
| 752 | $name = "{$user_prefix}_new_existing"; |
|---|
| 753 | $contentSelector = Content :: getSelectExistingContentUI($name, "AND is_persistent=TRUE AND content_id NOT IN (SELECT content_id FROM $link_table WHERE $link_table_obj_key_col='$link_table_obj_key')"); |
|---|
| 754 | $html .= $contentSelector; |
|---|
| 755 | $html .= "</td>\n"; |
|---|
| 756 | $html .= "</tr>\n"; |
|---|
| 757 | |
|---|
| 758 | /* Add new content */ |
|---|
| 759 | $html .= "<tr class='add_new_content'>\n"; |
|---|
| 760 | $name = "{$user_prefix}_new_display_page"; |
|---|
| 761 | $html .= "<td>" . FormSelectGenerator :: generateFromTable('content_available_display_pages', 'display_page', 'display_page', $default_display_page, $name, null) . "</td>\n"; |
|---|
| 762 | $name = "{$user_prefix}_new_display_area"; |
|---|
| 763 | $html .= "<td>" . FormSelectGenerator :: generateFromTable('content_available_display_areas', 'display_area', 'display_area', $default_display_area, $name, null) . "</td>\n"; |
|---|
| 764 | $name = "{$user_prefix}_new_display_order"; |
|---|
| 765 | $html .= "<td><input type='text' name='$name' value='1' size=2 class='linked_content_order'></td>\n"; |
|---|
| 766 | $html .= "<td colspan=2>\n"; |
|---|
| 767 | $name = "{$user_prefix}_new"; |
|---|
| 768 | $html .= self :: getNewContentUI($name, $content_type = null); |
|---|
| 769 | $html .= "</td>\n"; |
|---|
| 770 | $html .= "</table>\n"; |
|---|
| 771 | return $html; |
|---|
| 772 | } |
|---|
| 773 | |
|---|
| 774 | /** Get the created Content object, IF one was created |
|---|
| 775 | * OR Get existing content ( depending on what the user clicked ) |
|---|
| 776 | * @param $user_prefix A identifier provided by the programmer to recognise it's generated form |
|---|
| 777 | * @param $associate_existing_content boolean if true allows to get existing |
|---|
| 778 | * object |
|---|
| 779 | * @return the Content object, or null if the user didn't create one |
|---|
| 780 | */ |
|---|
| 781 | static function processLinkedContentUI($user_prefix, $link_table, $link_table_obj_key_col, $link_table_obj_key) { |
|---|
| 782 | $db = AbstractDb :: getObject(); |
|---|
| 783 | $link_table = $db->escapeString($link_table); |
|---|
| 784 | $link_table_obj_key_col = $db->escapeString($link_table_obj_key_col); |
|---|
| 785 | $link_table_obj_key = $db->escapeString($link_table_obj_key); |
|---|
| 786 | /* Content already linked */ |
|---|
| 787 | $current_content_sql = "SELECT * FROM $link_table WHERE $link_table_obj_key_col='$link_table_obj_key'"; |
|---|
| 788 | $rows = null; |
|---|
| 789 | $db->execSql($current_content_sql, $rows, false); |
|---|
| 790 | |
|---|
| 791 | if ($rows) |
|---|
| 792 | foreach ($rows as $row) { |
|---|
| 793 | $content = Content :: getObject($row['content_id']); |
|---|
| 794 | $content_id = $db->escapeString($content->getId()); |
|---|
| 795 | $sql = null; |
|---|
| 796 | $name = "{$user_prefix}_" . $content->GetId() . "_erase"; |
|---|
| 797 | if (!empty ($_REQUEST[$name])) { |
|---|
| 798 | $sql .= "DELETE FROM $link_table WHERE $link_table_obj_key_col='$link_table_obj_key' AND content_id = '$content_id';\n"; |
|---|
| 799 | |
|---|
| 800 | } else { |
|---|
| 801 | /* Display page */ |
|---|
| 802 | $name = "{$user_prefix}_" . $content->GetId() . "_display_page"; |
|---|
| 803 | $new_display_page = FormSelectGenerator :: getResult($name, null); |
|---|
| 804 | if ($new_display_page != $row['display_page']) { |
|---|
| 805 | $new_display_page = $db->escapeString($new_display_page); |
|---|
| 806 | $sql .= "UPDATE $link_table SET display_page='$new_display_page' WHERE $link_table_obj_key_col='$link_table_obj_key' AND content_id = '$content_id';\n"; |
|---|
| 807 | |
|---|
| 808 | } |
|---|
| 809 | /* Display area */ |
|---|
| 810 | $name = "{$user_prefix}_" . $content->GetId() . "_display_area"; |
|---|
| 811 | $new_display_area = FormSelectGenerator :: getResult($name, null); |
|---|
| 812 | if ($new_display_area != $row['display_area']) { |
|---|
| 813 | $new_display_area = $db->escapeString($new_display_area); |
|---|
| 814 | $sql .= "UPDATE $link_table SET display_area='$new_display_area' WHERE $link_table_obj_key_col='$link_table_obj_key' AND content_id = '$content_id';\n"; |
|---|
| 815 | } |
|---|
| 816 | /* Display order */ |
|---|
| 817 | $name = "{$user_prefix}_" . $content->GetId() . "_display_order"; |
|---|
| 818 | if ($_REQUEST[$name] != $row['display_order']) { |
|---|
| 819 | $new_display_order = $db->escapeString($_REQUEST[$name]); |
|---|
| 820 | $sql .= "UPDATE $link_table SET display_order='$new_display_order' WHERE $link_table_obj_key_col='$link_table_obj_key' AND content_id = '$content_id';\n"; |
|---|
| 821 | } |
|---|
| 822 | } |
|---|
| 823 | if ($sql) { |
|---|
| 824 | $db->execSqlUpdate($sql, false); |
|---|
| 825 | } |
|---|
| 826 | } |
|---|
| 827 | /* Add existing content */ |
|---|
| 828 | $name = "{$user_prefix}_new_existing_add"; |
|---|
| 829 | if (!empty ($_REQUEST[$name])) { |
|---|
| 830 | $name = "{$user_prefix}_new_existing"; |
|---|
| 831 | $content = Content :: processSelectContentUI($name); |
|---|
| 832 | if ($content) { |
|---|
| 833 | /* Display page */ |
|---|
| 834 | $name = "{$user_prefix}_new_existing_display_page"; |
|---|
| 835 | $new_display_page = $db->escapeString(FormSelectGenerator :: getResult($name, null)); |
|---|
| 836 | /* Display area */ |
|---|
| 837 | $name = "{$user_prefix}_new_existing_display_area"; |
|---|
| 838 | $new_display_area = $db->escapeString(FormSelectGenerator :: getResult($name, null)); |
|---|
| 839 | /* Display order */ |
|---|
| 840 | $name = "{$user_prefix}_new_existing_display_order"; |
|---|
| 841 | $new_display_order = $db->escapeString($_REQUEST[$name]); |
|---|
| 842 | $content_id = $db->escapeString($content->getId()); |
|---|
| 843 | $sql = "INSERT INTO $link_table (content_id, $link_table_obj_key_col, display_page, display_area, display_order) VALUES ('$content_id', '$link_table_obj_key', '$new_display_page', '$new_display_area', $new_display_order);\n"; |
|---|
| 844 | $db->execSqlUpdate($sql, false); |
|---|
| 845 | } |
|---|
| 846 | } |
|---|
| 847 | /* Add new content */ |
|---|
| 848 | $name = "{$user_prefix}_new"; |
|---|
| 849 | $content = self :: processNewContentUI($name); |
|---|
| 850 | if ($content) { |
|---|
| 851 | /* Display page */ |
|---|
| 852 | $name = "{$user_prefix}_new_display_page"; |
|---|
| 853 | $new_display_page = $db->escapeString(FormSelectGenerator :: getResult($name, null)); |
|---|
| 854 | /* Display area */ |
|---|
| 855 | $name = "{$user_prefix}_new_display_area"; |
|---|
| 856 | $new_display_area = $db->escapeString(FormSelectGenerator :: getResult($name, null)); |
|---|
| 857 | /* Display order */ |
|---|
| 858 | $name = "{$user_prefix}_new_display_order"; |
|---|
| 859 | $new_display_order = $db->escapeString($_REQUEST[$name]); |
|---|
| 860 | $content_id = $db->escapeString($content->getId()); |
|---|
| 861 | $sql = "INSERT INTO $link_table (content_id, $link_table_obj_key_col, display_page, display_area, display_order) VALUES ('$content_id', '$link_table_obj_key', '$new_display_page', '$new_display_area', $new_display_order);\n"; |
|---|
| 862 | $db->execSqlUpdate($sql, false); |
|---|
| 863 | } |
|---|
| 864 | } |
|---|
| 865 | |
|---|
| 866 | /** |
|---|
| 867 | * Get an interface to pick content from all persistent content |
|---|
| 868 | * |
|---|
| 869 | * It either returns a select box or an extended table |
|---|
| 870 | * |
|---|
| 871 | * @param string $user_prefix An identifier provided by the |
|---|
| 872 | * programmer to recognise it's |
|---|
| 873 | * generated HTML form |
|---|
| 874 | * @param string $sql_additional_where Addidional where conditions to |
|---|
| 875 | * restrict the candidate objects |
|---|
| 876 | * @param string $content_type_filter If set, the created content must match the filter. |
|---|
| 877 | * @param string $order Order of output (default: by |
|---|
| 878 | * creation time) |
|---|
| 879 | * @param string $type_interface Type of interface: |
|---|
| 880 | * - "select": default, shows a |
|---|
| 881 | * select box |
|---|
| 882 | * - "table": showsa table with |
|---|
| 883 | * extended information |
|---|
| 884 | * |
|---|
| 885 | * @return string HTML markup |
|---|
| 886 | |
|---|
| 887 | */ |
|---|
| 888 | public static function getSelectExistingContentUI($user_prefix, $sql_additional_where = null, $content_type_filter = null, $order = "creation_timestamp DESC", $type_interface = "select") { |
|---|
| 889 | |
|---|
| 890 | $db = AbstractDb :: getObject(); |
|---|
| 891 | |
|---|
| 892 | // Init values |
|---|
| 893 | $html = ''; |
|---|
| 894 | $retVal = array (); |
|---|
| 895 | $contentRows = null; |
|---|
| 896 | if ($content_type_filter == null) { |
|---|
| 897 | //Get an empty filter |
|---|
| 898 | $content_type_filter = ContentTypeFilter :: getObject(array ()); |
|---|
| 899 | } |
|---|
| 900 | |
|---|
| 901 | if (!User :: getCurrentUser()) { |
|---|
| 902 | throw new Exception(_('Access denied!')); |
|---|
| 903 | } |
|---|
| 904 | |
|---|
| 905 | if ($type_interface != "table") { |
|---|
| 906 | $html .= "<fieldset class='admin_container Content'>\n"; |
|---|
| 907 | |
|---|
| 908 | if (!empty ($title)) { |
|---|
| 909 | $html .= "<legend>$title</legend>\n"; |
|---|
| 910 | } |
|---|
| 911 | |
|---|
| 912 | $html .= _("Select from reusable content library") . ": "; |
|---|
| 913 | } |
|---|
| 914 | |
|---|
| 915 | $name = "{$user_prefix}"; |
|---|
| 916 | |
|---|
| 917 | $sql = "SELECT * FROM content WHERE 1=1 $sql_additional_where ORDER BY $order"; |
|---|
| 918 | |
|---|
| 919 | $db->execSql($sql, $contentRows, false); |
|---|
| 920 | |
|---|
| 921 | if ($contentRows != null) { |
|---|
| 922 | $i = 0; |
|---|
| 923 | |
|---|
| 924 | if ($type_interface == "table") { |
|---|
| 925 | $html .= "<table class='content_admin'>\n"; |
|---|
| 926 | $html .= "<tr><th>" . _("Title") . "</th><th>" . _("Content type") . "</th><th>" . _("Description") . "</th><th></th></tr>\n"; |
|---|
| 927 | } |
|---|
| 928 | |
|---|
| 929 | foreach ($contentRows as $contentRow) { |
|---|
| 930 | $content = Content :: getObject($contentRow['content_id']); |
|---|
| 931 | //echo get_class($content)." ".$contentRow['content_id']."<br>"; |
|---|
| 932 | if ($content && $content_type_filter->isAcceptableContentClass(get_class($content))) { |
|---|
| 933 | if ($type_interface != "table") { |
|---|
| 934 | $tab[$i][0] = $content->getId(); |
|---|
| 935 | $tab[$i][1] = $content->__toString() . " (" . get_class($content) . ")"; |
|---|
| 936 | $i++; |
|---|
| 937 | } else { |
|---|
| 938 | if (!empty ($contentRow['title'])) { |
|---|
| 939 | $title = Content :: getObject($contentRow['title']); |
|---|
| 940 | $titleUI = $title->__toString(); |
|---|
| 941 | } else { |
|---|
| 942 | $titleUI = ""; |
|---|
| 943 | } |
|---|
| 944 | |
|---|
| 945 | if (!empty ($contentRow['description'])) { |
|---|
| 946 | $description = Content :: getObject($contentRow['description']); |
|---|
| 947 | $descriptionUI = $description->__toString(); |
|---|
| 948 | } else { |
|---|
| 949 | $descriptionUI = ""; |
|---|
| 950 | } |
|---|
| 951 | |
|---|
| 952 | $href = GENERIC_OBJECT_ADMIN_ABS_HREF . "?object_id={$contentRow['content_id']}&object_class=Content&action=edit"; |
|---|
| 953 | $html .= "<tr><td>$titleUI</td><td><a href='$href'>{$contentRow['content_type']}</a></td><td>$descriptionUI</td>\n"; |
|---|
| 954 | |
|---|
| 955 | $href = GENERIC_OBJECT_ADMIN_ABS_HREF . "?object_id={$contentRow['content_id']}&object_class=Content&action=delete"; |
|---|
| 956 | $html .= "<td><a href='$href'>" . _("Delete") . "</a></td>"; |
|---|
| 957 | |
|---|
| 958 | $html .= "</tr>\n"; |
|---|
| 959 | } |
|---|
| 960 | } |
|---|
| 961 | } |
|---|
| 962 | |
|---|
| 963 | if ($type_interface != "table") { |
|---|
| 964 | if (isset ($tab)) { |
|---|
| 965 | $html .= FormSelectGenerator :: generateFromArray($tab, null, $name, null, false, null, null, 40); |
|---|
| 966 | //DEBUG!! get_existing_content_ |
|---|
| 967 | $name = "{$user_prefix}_add"; |
|---|
| 968 | $value = _("Add"); |
|---|
| 969 | $html .= "<div class='admin_element_tools'>"; |
|---|
| 970 | $html .= '<input type="submit" class="submit" name="' . $name . '" value="' . $value . '">'; |
|---|
| 971 | $html .= "</div>"; |
|---|
| 972 | } else { |
|---|
| 973 | $html .= "<div class='warningmsg'>" . _("Sorry, no elligible content available in the database") . "</div>\n"; |
|---|
| 974 | } |
|---|
| 975 | $html .= "</fieldset>\n"; |
|---|
| 976 | } else { |
|---|
| 977 | $html .= "</table>\n"; |
|---|
| 978 | } |
|---|
| 979 | } else { |
|---|
| 980 | $html .= "<div class='warningmsg'>" . _("Sorry, no elligible content available in the database") . "</div>\n"; |
|---|
| 981 | } |
|---|
| 982 | |
|---|
| 983 | return $html; |
|---|
| 984 | } |
|---|
| 985 | |
|---|
| 986 | /** Get the selected Content object. |
|---|
| 987 | * @param $user_prefix A identifier provided by the programmer to recognise it's generated form |
|---|
| 988 | * @return the Content object |
|---|
| 989 | */ |
|---|
| 990 | static function processSelectContentUI($user_prefix) { |
|---|
| 991 | $name = "{$user_prefix}"; |
|---|
| 992 | if (!empty ($_REQUEST[$name])) |
|---|
| 993 | return Content :: getObject($_REQUEST[$name]); |
|---|
| 994 | else |
|---|
| 995 | return null; |
|---|
| 996 | } |
|---|
| 997 | |
|---|
| 998 | /** Get the true object type represented by this isntance |
|---|
| 999 | * @return an array of class names */ |
|---|
| 1000 | public function getObjectType() { |
|---|
| 1001 | return $this->content_type; |
|---|
| 1002 | } |
|---|
| 1003 | |
|---|
| 1004 | /** |
|---|
| 1005 | * Key-value pairs are an easy way to extend Content types |
|---|
| 1006 | * without having to needlessly modify the wifidog schema. |
|---|
| 1007 | * They are appropriate when you content subtype needs to |
|---|
| 1008 | * store simple type that fit the key-value model. (that is |
|---|
| 1009 | * onke key->single value for a given Content instance. |
|---|
| 1010 | * @throws exception if key cannot be found |
|---|
| 1011 | * @param $key The key whose value is to be retrieved.Keys |
|---|
| 1012 | * must also be unique fo the entire object inheritance tree. |
|---|
| 1013 | * Because of this, key naming convention is as follows: |
|---|
| 1014 | * ClassName_key_name |
|---|
| 1015 | * @return The value of the pair. To check if a key exists, |
|---|
| 1016 | * check === null (and not == null) |
|---|
| 1017 | |
|---|
| 1018 | */ |
|---|
| 1019 | protected function getKVP($key) { |
|---|
| 1020 | if (isset ($this->kvps[$key])) { |
|---|
| 1021 | return $this->kvps[$key]; |
|---|
| 1022 | } else { |
|---|
| 1023 | //throw new exception (sprintf(_("Key %s does not exist"), $key)); |
|---|
| 1024 | return null; |
|---|
| 1025 | } |
|---|
| 1026 | } |
|---|
| 1027 | |
|---|
| 1028 | /** |
|---|
| 1029 | * Key-value pairs are an easy way to extend Content types |
|---|
| 1030 | * without having to needlessly modify the wifidog schema. |
|---|
| 1031 | * They are appropriate when you content subtype needs to |
|---|
| 1032 | * store simple type that fit the key-value model. (that is |
|---|
| 1033 | * onke key->single value for a given Content instance. |
|---|
| 1034 | * @throws exception if key cannot be found |
|---|
| 1035 | * @param $key The key whose value is to be retrieved. Keys |
|---|
| 1036 | * must also be unique fo the entire object inheritance tree. |
|---|
| 1037 | * Because of this, key naming convention is as follows: |
|---|
| 1038 | * ClassName_key_name |
|---|
| 1039 | * @param $value The value of the key. Any value representable as a string. Setting it to null will delete the key. |
|---|
| 1040 | * @return The value of the pair |
|---|
| 1041 | */ |
|---|
| 1042 | protected function setKVP($key, $value) { |
|---|
| 1043 | $retval = true; |
|---|
| 1044 | $db = AbstractDb :: getObject(); |
|---|
| 1045 | $value_sql = $db->escapeString($value); |
|---|
| 1046 | $key_sql = $db->escapeString($key); |
|---|
| 1047 | //pretty_print_r($this->kvps); |
|---|
| 1048 | if($key==null) { |
|---|
| 1049 | throw new Exception (_("KVP key cannot be null")); |
|---|
| 1050 | } else if($value===null) { |
|---|
| 1051 | //Delete the KVP |
|---|
| 1052 | $retval = $db->execSqlUpdate("DELETE FROM content_key_value_pairs WHERE content_id='" . $this->getId() . "' AND key='$key_sql'", false); |
|---|
| 1053 | if(isset ($this->kvps[$key])) { |
|---|
| 1054 | unset ($this->kvps[$key]); |
|---|
| 1055 | } |
|---|
| 1056 | } else if (!isset ($this->kvps[$key])) { |
|---|
| 1057 | //This is a new key |
|---|
| 1058 | $retval = $db->execSqlUpdate("INSERT INTO content_key_value_pairs (content_id, key, value) VALUES ('" . $this->getId() . "', '$key_sql', '$value_sql')", false); |
|---|
| 1059 | } else |
|---|
| 1060 | if ($this->kvps[$key] != $value) { |
|---|
| 1061 | //This is an existing key, and it's been modified |
|---|
| 1062 | $retval = $db->execSqlUpdate("UPDATE content_key_value_pairs SET value ='" . $value_sql . "' WHERE content_id='" . $this->getId() . "' AND key='$key_sql'", false); |
|---|
| 1063 | } |
|---|
| 1064 | $this->refresh(); |
|---|
| 1065 | return $retval; |
|---|
| 1066 | } |
|---|
| 1067 | |
|---|
| 1068 | /** |
|---|
| 1069 | * Get content title |
|---|
| 1070 | * @return content a content sub-class |
|---|
| 1071 | */ |
|---|
| 1072 | public function getTitle() { |
|---|
| 1073 | $retval = null; |
|---|
| 1074 | if(!empty($this->content_row['title'])){ |
|---|
| 1075 | $retval = self :: getObject($this->content_row['title']); |
|---|
| 1076 | } |
|---|
| 1077 | return $retval; |
|---|
| 1078 | } |
|---|
| 1079 | |
|---|
| 1080 | /** |
|---|
| 1081 | * Get content description |
|---|
| 1082 | * @return content a content sub-class |
|---|
| 1083 | */ |
|---|
| 1084 | public function getDescription() { |
|---|
| 1085 | $retval = null; |
|---|
| 1086 | if(!empty($this->content_row['description'])){ |
|---|
| 1087 | $retval = self :: getObject($this->content_row['description']); |
|---|
| 1088 | } |
|---|
| 1089 | return $retval; |
|---|
| 1090 | } |
|---|
| 1091 | |
|---|
| 1092 | /** |
|---|
| 1093 | * Get content long description |
|---|
| 1094 | * @return content a content sub-class |
|---|
| 1095 | */ |
|---|
| 1096 | public function getLongDescription() { |
|---|
| 1097 | $retval = null; |
|---|
| 1098 | if(!empty($this->content_row['long_description'])){ |
|---|
| 1099 | $retval = self :: getObject($this->content_row['long_description']); |
|---|
| 1100 | } |
|---|
| 1101 | return $retval; |
|---|
| 1102 | } |
|---|
| 1103 | |
|---|
| 1104 | /** |
|---|
| 1105 | * Get content project info |
|---|
| 1106 | * @return content a content sub-class |
|---|
| 1107 | */ |
|---|
| 1108 | public function getProjectInfo() { |
|---|
| 1109 | $retval = null; |
|---|
| 1110 | if(!empty($this->content_row['project_info'])){ |
|---|
| 1111 | $retval = self :: getObject($this->content_row['project_info']); |
|---|
| 1112 | } |
|---|
| 1113 | return $retval; |
|---|
| 1114 | } |
|---|
| 1115 | |
|---|
| 1116 | /** Set the object type of this object |
|---|
| 1117 | * Note that after using this, the object must be re-instanciated to have the right type |
|---|
| 1118 | * */ |
|---|
| 1119 | private function setContentType($content_type) { |
|---|
| 1120 | $db = AbstractDb :: getObject(); |
|---|
| 1121 | $content_type = $db->escapeString($content_type); |
|---|
| 1122 | if (!self :: isContentTypeAvailable($content_type)) { |
|---|
| 1123 | throw new Exception(_("The following content type isn't valid: ") . $content_type); |
|---|
| 1124 | } |
|---|
| 1125 | $sql = "UPDATE content SET content_type = '$content_type' WHERE content_id='$this->id'"; |
|---|
| 1126 | |
|---|
| 1127 | if (!$db->execSqlUpdate($sql, false)) { |
|---|
| 1128 | throw new Exception(_("Update was unsuccessfull (database error)")); |
|---|
| 1129 | } |
|---|
| 1130 | unset(self :: $instanceArray[$this->id]);//Clear the cache or we will have problems even if we re-instanciate. |
|---|
| 1131 | } |
|---|
| 1132 | |
|---|
| 1133 | /** Check if a user is one of the owners of the object |
|---|
| 1134 | * @param $user The user to be added to the owners list |
|---|
| 1135 | * @param $is_author Optionnal, true or false. Set to true if the user is one of the actual authors of the Content |
|---|
| 1136 | * @return true on success, false on failure */ |
|---|
| 1137 | public function addOwner(User $user, $is_author = false) { |
|---|
| 1138 | $db = AbstractDb :: getObject(); |
|---|
| 1139 | $content_id = "'" . $this->id . "'"; |
|---|
| 1140 | $user_id = "'" . $db->escapeString($user->getId()) . "'"; |
|---|
| 1141 | $is_author ? $is_author = 'TRUE' : $is_author = 'FALSE'; |
|---|
| 1142 | $sql = "INSERT INTO content_has_owners (content_id, user_id, is_author) VALUES ($content_id, $user_id, $is_author)"; |
|---|
| 1143 | |
|---|
| 1144 | if (!$db->execSqlUpdate($sql, false)) { |
|---|
| 1145 | throw new Exception(_('Unable to insert the new Owner into database.')); |
|---|
| 1146 | } |
|---|
| 1147 | |
|---|
| 1148 | return true; |
|---|
| 1149 | } |
|---|
| 1150 | |
|---|
| 1151 | /** Remove an owner of the content |
|---|
| 1152 | * @param $user The user to be removed from the owners list |
|---|
| 1153 | */ |
|---|
| 1154 | public function deleteOwner(User $user, $is_author = false) { |
|---|
| 1155 | $db = AbstractDb :: getObject(); |
|---|
| 1156 | $content_id = "'" . $this->id . "'"; |
|---|
| 1157 | $user_id = "'" . $db->escapeString($user->getId()) . "'"; |
|---|
| 1158 | |
|---|
| 1159 | $sql = "DELETE FROM content_has_owners WHERE content_id=$content_id AND user_id=$user_id"; |
|---|
| 1160 | |
|---|
| 1161 | if (!$db->execSqlUpdate($sql, false)) { |
|---|
| 1162 | throw new Exception(_('Unable to remove the owner from the database.')); |
|---|
| 1163 | } |
|---|
| 1164 | |
|---|
| 1165 | return true; |
|---|
| 1166 | } |
|---|
| 1167 | |
|---|
| 1168 | /** |
|---|
| 1169 | * Indicates display logging status |
|---|
| 1170 | */ |
|---|
| 1171 | public function getLoggingStatus() { |
|---|
| 1172 | return $this->is_logging_enabled; |
|---|
| 1173 | } |
|---|
| 1174 | |
|---|
| 1175 | /** |
|---|
| 1176 | * Sets display logging status |
|---|
| 1177 | */ |
|---|
| 1178 | public function setLoggingStatus($status) { |
|---|
| 1179 | if (is_bool($status)) |
|---|
| 1180 | $this->is_logging_enabled = $status; |
|---|
| 1181 | } |
|---|
| 1182 | |
|---|
| 1183 | /** Get the PHP timestamp of the last time this content was displayed |
|---|
| 1184 | * @param $user User, Optional, if present, restrict to the selected user |
|---|
| 1185 | * @param $node Node, Optional, if present, restrict to the selected node |
|---|
| 1186 | * @return PHP timestamp (seconds since UNIX epoch) if the content has been |
|---|
| 1187 | * displayed before, an empty string otherwise. |
|---|
| 1188 | */ |
|---|
| 1189 | public function getLastDisplayTimestamp($user = null, $node = null) { |
|---|
| 1190 | $db = AbstractDb :: getObject(); |
|---|
| 1191 | $retval = ''; |
|---|
| 1192 | $sql = "SELECT EXTRACT(EPOCH FROM last_display_timestamp) as last_display_unix_timestamp FROM content_display_log WHERE content_id='{$this->id}' \n"; |
|---|
| 1193 | |
|---|
| 1194 | if ($user) { |
|---|
| 1195 | $user_id = $db->escapeString($user->getId()); |
|---|
| 1196 | $sql .= " AND user_id = '{$user_id}' \n"; |
|---|
| 1197 | } |
|---|
| 1198 | if ($node) { |
|---|
| 1199 | $node_id = $db->escapeString($node->getId()); |
|---|
| 1200 | $sql .= " AND node_id = '{$node_id}' \n"; |
|---|
| 1201 | } |
|---|
| 1202 | $sql .= " ORDER BY last_display_timestamp DESC "; |
|---|
| 1203 | $db->execSql($sql, $log_rows, false); |
|---|
| 1204 | if ($log_rows) { |
|---|
| 1205 | $retval = $log_rows[0]['last_display_unix_timestamp']; |
|---|
| 1206 | } |
|---|
| 1207 | |
|---|
| 1208 | return $retval; |
|---|
| 1209 | } |
|---|
| 1210 | |
|---|
| 1211 | /** Is this Content element displayable at this hotspot, many classes override this |
|---|
| 1212 | * @param $node Node, optionnal |
|---|
| 1213 | * @return true or false */ |
|---|
| 1214 | public function isDisplayableAt($node) { |
|---|
| 1215 | return true; |
|---|
| 1216 | } |
|---|
| 1217 | |
|---|
| 1218 | /** Check if a user is one of the owners of the object |
|---|
| 1219 | * @param $user User object: the user to be tested. |
|---|
| 1220 | * @return true if the user is a owner, false if he isn't of the user is null */ |
|---|
| 1221 | public function DEPRECATEDisOwner($user) { |
|---|
| 1222 | $db = AbstractDb :: getObject(); |
|---|
| 1223 | $retval = false; |
|---|
| 1224 | if ($user != null) { |
|---|
| 1225 | $user_id = $db->escapeString($user->GetId()); |
|---|
| 1226 | $sql = "SELECT * FROM content_has_owners WHERE content_id='$this->id' AND user_id='$user_id'"; |
|---|
| 1227 | $db->execSqlUniqueRes($sql, $content_owner_row, false); |
|---|
| 1228 | if ($content_owner_row != null) { |
|---|
| 1229 | $retval = true; |
|---|
| 1230 | } |
|---|
| 1231 | } |
|---|
| 1232 | |
|---|
| 1233 | return $retval; |
|---|
| 1234 | } |
|---|
| 1235 | |
|---|
| 1236 | /** Get the authors of the Content |
|---|
| 1237 | * @return null or array of User objects */ |
|---|
| 1238 | public function getAuthors() { |
|---|
| 1239 | $db = AbstractDb :: getObject(); |
|---|
| 1240 | $retval = array (); |
|---|
| 1241 | $content_owner_row = null; |
|---|
| 1242 | $sql = "SELECT user_id FROM content_has_owners WHERE content_id='$this->id' AND is_author=TRUE"; |
|---|
| 1243 | $db->execSqlUniqueRes($sql, $content_owner_row, false); |
|---|
| 1244 | if ($content_owner_row != null) { |
|---|
| 1245 | $user = User :: getObject($content_owner_row['user_id']); |
|---|
| 1246 | $retval[] = $user; |
|---|
| 1247 | } |
|---|
| 1248 | |
|---|
| 1249 | return $retval; |
|---|
| 1250 | } |
|---|
| 1251 | |
|---|
| 1252 | /** Get the owners of the Content |
|---|
| 1253 | * @return null or array of User objects */ |
|---|
| 1254 | public function getOwners() { |
|---|
| 1255 | $db = AbstractDb :: getObject(); |
|---|
| 1256 | $retval = array (); |
|---|
| 1257 | $content_owner_row = null; |
|---|
| 1258 | $sql = "SELECT user_id FROM content_has_owners WHERE content_id='$this->id'"; |
|---|
| 1259 | $db->execSqlUniqueRes($sql, $content_owner_row, false); |
|---|
| 1260 | if ($content_owner_row != null) { |
|---|
| 1261 | $user = User :: getObject($content_owner_row['user_id']); |
|---|
| 1262 | $retval[] = $user; |
|---|
| 1263 | } |
|---|
| 1264 | |
|---|
| 1265 | return $retval; |
|---|
| 1266 | } |
|---|
| 1267 | |
|---|
| 1268 | /** @see GenricObject |
|---|
| 1269 | * @return The id */ |
|---|
| 1270 | public function getId() { |
|---|
| 1271 | return $this->id; |
|---|
| 1272 | } |
|---|
| 1273 | |
|---|
| 1274 | /** When a content object is set as Simple, it means that is is used merely to contain it's own data. No title, description or other metadata will be set or displayed, during display or administration |
|---|
| 1275 | * @return true or false */ |
|---|
| 1276 | public function isSimpleContent() { |
|---|
| 1277 | return false; |
|---|
| 1278 | } |
|---|
| 1279 | |
|---|
| 1280 | /** Indicate that the content is suitable to store plain text. |
|---|
| 1281 | * @return true or false */ |
|---|
| 1282 | public function isTextualContent() { |
|---|
| 1283 | return false; |
|---|
| 1284 | } |
|---|
| 1285 | |
|---|
| 1286 | /** This function will be called by MainUI for each Content BEFORE any getUserUI function is called to allow two pass Content display. |
|---|
| 1287 | * Two pass Content display allows such things as modyfying headers, title, creating content type that accumulate content from other pieces (like RSS feeds) |
|---|
| 1288 | * @return null |
|---|
| 1289 | */ |
|---|
| 1290 | public function prepareGetUserUI() { |
|---|
| 1291 | return null; |
|---|
| 1292 | } |
|---|
| 1293 | |
|---|
| 1294 | /** Does the content have any displayable metadata? |
|---|
| 1295 | * @return true or false */ |
|---|
| 1296 | protected function hasDisplayableMetadata() { |
|---|
| 1297 | $retval = false; |
|---|
| 1298 | $metadata = $this->getTitle(); |
|---|
| 1299 | if ($metadata && $this->titleShouldDisplay()){ |
|---|
| 1300 | $retval = true; |
|---|
| 1301 | } |
|---|
| 1302 | elseif ($this->getDescription()){ |
|---|
| 1303 | $retval = true; |
|---|
| 1304 | } |
|---|
| 1305 | elseif ($this->getLongDescription()){ |
|---|
| 1306 | $retval = true; |
|---|
| 1307 | } |
|---|
| 1308 | elseif ($this->getProjectInfo()){ |
|---|
| 1309 | $retval = true; |
|---|
| 1310 | } |
|---|
| 1311 | elseif($this->getAuthors()) { |
|---|
| 1312 | $retval = true; |
|---|
| 1313 | } |
|---|
| 1314 | return $retval; |
|---|
| 1315 | } |
|---|
| 1316 | |
|---|
| 1317 | /** Set the content to be displayed in the main display area. Needs to be set by subclasses |
|---|
| 1318 | * @param $html: Html markup for the displayed content */ |
|---|
| 1319 | protected function setUserUIMainDisplayContent($html) { |
|---|
| 1320 | $this->user_ui_main_content = $html; |
|---|
| 1321 | } |
|---|
| 1322 | |
|---|
| 1323 | /** Set the content to be displayed in the interactive display area. Needs to be set by subclasses |
|---|
| 1324 | * @param $html: Html markup for the displayed content */ |
|---|
| 1325 | protected function setUserUIMainInteractionArea($html) { |
|---|
| 1326 | $this->user_ui_interaction_area = $html; |
|---|
| 1327 | } |
|---|
| 1328 | /** Retreives the user interface of this object. Anything that overrides this method should use |
|---|
| 1329 | * setUserUIMainDisplayContent() and/or setUserUIMainInteractionArea before returning it's parent's |
|---|
| 1330 | * getUserUI() return value at the end of processing. |
|---|
| 1331 | |
|---|
| 1332 | * * @return The HTML fragment for this interface */ |
|---|
| 1333 | public function getUserUI($subclass_user_interface = null) { |
|---|
| 1334 | $html = ''; |
|---|
| 1335 | $hasDisplayableMetadata = $this->hasDisplayableMetadata(); |
|---|
| 1336 | $hasDisplayableMetadata ? $hasDisplayableMetadataClass = 'hasDisplayableMetadata' : $hasDisplayableMetadataClass = null; |
|---|
| 1337 | $html .= "<div class='user_ui_main_outer " . get_class($this) . " $hasDisplayableMetadataClass'>\n"; |
|---|
| 1338 | $html .= "<div class='user_ui_main_inner'>\n"; |
|---|
| 1339 | if (!empty ($this->content_row['title']) && $this->titleShouldDisplay()) { |
|---|
| 1340 | $html .= "<div class='user_ui_title'>\n"; |
|---|
| 1341 | $title = self :: getObject($this->content_row['title']); |
|---|
| 1342 | $title->setLogAsContent($this); |
|---|
| 1343 | // If the content logging is disabled, all the children will inherit this property temporarly |
|---|
| 1344 | if ($this->getLoggingStatus() == false) |
|---|
| 1345 | $title->setLoggingStatus(false); |
|---|
| 1346 | $html .= $title->getUserUI(); |
|---|
| 1347 | $html .= "</div>\n"; |
|---|
| 1348 | } |
|---|
| 1349 | if($this->user_ui_main_content) { |
|---|
| 1350 | if (!$hasDisplayableMetadata) { |
|---|
| 1351 | $html .= "\n<div class='user_ui_main_content'>$this->user_ui_main_content</div>\n"; |
|---|
| 1352 | } else { |
|---|
| 1353 | $html .= "<table><tr>\n"; |
|---|
| 1354 | $html .= "<td class='user_ui_main_content'>\n$this->user_ui_main_content</td>\n"; |
|---|
| 1355 | $html .= "<td>\n"; |
|---|
| 1356 | } |
|---|
| 1357 | } |
|---|
| 1358 | $authors = $this->getAuthors(); |
|---|
| 1359 | if (count($authors) > 0) { |
|---|
| 1360 | $html .= "<div class='user_ui_authors'>\n"; |
|---|
| 1361 | $html .= _("Author(s):"); |
|---|
| 1362 | foreach ($authors as $user) { |
|---|
| 1363 | $html .= $user->getListUI() . " "; |
|---|
| 1364 | } |
|---|
| 1365 | $html .= "</div>\n"; |
|---|
| 1366 | } |
|---|
| 1367 | |
|---|
| 1368 | if (!empty ($this->content_row['description'])) { |
|---|
| 1369 | $html .= "<div class='user_ui_description'>\n"; |
|---|
| 1370 | $description = self :: getObject($this->content_row['description']); |
|---|
| 1371 | $description->setLogAsContent($this); |
|---|
| 1372 | // If the content logging is disabled, all the children will inherit this property temporarly |
|---|
| 1373 | if ($this->getLoggingStatus() == false) |
|---|
| 1374 | $description->setLoggingStatus(false); |
|---|
| 1375 | $html .= $description->getUserUI(); |
|---|
| 1376 | $html .= "</div>\n"; |
|---|
| 1377 | } |
|---|
| 1378 | |
|---|
| 1379 | if (!empty ($this->content_row['project_info'])) { |
|---|
| 1380 | if (!empty ($this->content_row['project_info'])) { |
|---|
| 1381 | $html .= "<div class='user_ui_projet_info'>\n"; |
|---|
| 1382 | $html .= "<b>" . _("Project information:") . "</b>"; |
|---|
| 1383 | $project_info = self :: getObject($this->content_row['project_info']); |
|---|
| 1384 | $project_info->setLogAsContent($this); |
|---|
| 1385 | // If the content logging is disabled, all the children will inherit this property temporarly |
|---|
| 1386 | if ($this->getLoggingStatus() == false) |
|---|
| 1387 | $project_info->setLoggingStatus(false); |
|---|
| 1388 | $html .= $project_info->getUserUI(); |
|---|
| 1389 | $html .= "</div>\n"; |
|---|
| 1390 | } |
|---|
| 1391 | } |
|---|
| 1392 | if ($hasDisplayableMetadata) { |
|---|
| 1393 | $html .= "</td>\n"; |
|---|
| 1394 | $html .= "</tr>\n"; |
|---|
| 1395 | } |
|---|
| 1396 | if($this->user_ui_interaction_area) { |
|---|
| 1397 | if (!$hasDisplayableMetadata) { |
|---|
| 1398 | $html .= "\n<div class='user_ui_interaction_area'>$this->user_ui_interaction_area</div>\n"; |
|---|
| 1399 | } else { |
|---|
| 1400 | $html .= "<tr>\n"; |
|---|
| 1401 | $html .= "<td colspan=2 class='user_ui_interaction_area'>\n$this->user_ui_interaction_area</td>\n"; |
|---|
| 1402 | $html .= "</tr>\n"; |
|---|
| 1403 | } |
|---|
| 1404 | } |
|---|
| 1405 | |
|---|
| 1406 | if ($hasDisplayableMetadata) { |
|---|
| 1407 | $html .= "</table>\n"; |
|---|
| 1408 | } |
|---|
| 1409 | $html .= "</div>\n"; |
|---|
| 1410 | $html .= "</div>\n"; |
|---|
| 1411 | |
|---|
| 1412 | |
|---|
| 1413 | $this->logContentDisplay(); |
|---|
| 1414 | return $html; |
|---|
| 1415 | } |
|---|
| 1416 | |
|---|
| 1417 | /** Allow logging as part of another content (usually the parent for metadata). |
|---|
| 1418 | * Redirects clickthrough logging to the parent's content id, and does not log |
|---|
| 1419 | * display */ |
|---|
| 1420 | protected function setLogAsContent(Content $content) { |
|---|
| 1421 | $this->log_as_content = $content; |
|---|
| 1422 | } |
|---|
| 1423 | |
|---|
| 1424 | /** Get the last time this content was displayed |
|---|
| 1425 | * @param $user User, optionnal. If present, the date is the last time the |
|---|
| 1426 | * content was displayed for this user |
|---|
| 1427 | * @param $node Node, optionnal. If present, the date is the last time the |
|---|
| 1428 | * content was displayed at this node |
|---|
| 1429 | @return PHP timestamp or null */ |
|---|
| 1430 | public function getLastDisplayedTimestamp($user = null, $node = null) { |
|---|
| 1431 | $retval = null; |
|---|
| 1432 | $log_row = null; |
|---|
| 1433 | $user ? $user_sql = " AND user_id='{$user->getId()}' " : $user_sql = ''; |
|---|
| 1434 | $node ? $node_sql = " AND node_id='{$node->getId()}' " : $node_sql = ''; |
|---|
| 1435 | $db = AbstractDb :: getObject(); |
|---|
| 1436 | |
|---|
| 1437 | $sql = "SELECT EXTRACT('epoch' FROM MAX(last_display_timestamp)) as last_display_timestamp FROM content_display_log WHERE content_id='$this->id' $user_sql $node_sql"; |
|---|
| 1438 | $db->execSqlUniqueRes($sql, $log_row, false); |
|---|
| 1439 | if ($log_row != null) { |
|---|
| 1440 | $retval = $log_row['last_display_timestamp']; |
|---|
| 1441 | } |
|---|
| 1442 | return $retval; |
|---|
| 1443 | } |
|---|
| 1444 | |
|---|
| 1445 | /** Log that this content has just been displayed to the user. Will only log if the user is logged in */ |
|---|
| 1446 | private function logContentDisplay() { |
|---|
| 1447 | if ($this->getLoggingStatus() == true && $this->log_as_content->getId() == $this->getId()) { |
|---|
| 1448 | // DEBUG:: |
|---|
| 1449 | //echo "Logging ".get_class($this)." :: ".$this->__toString()."<br>"; |
|---|
| 1450 | $user = User :: getCurrentUser(); |
|---|
| 1451 | $node = Node :: getCurrentNode(); |
|---|
| 1452 | if ($user != null && $node != null) { |
|---|
| 1453 | $user_id = $user->getId(); |
|---|
| 1454 | $node_id = $node->getId(); |
|---|
| 1455 | $db = AbstractDb :: getObject(); |
|---|
| 1456 | |
|---|
| 1457 | $sql = "SELECT * FROM content_display_log WHERE content_id='$this->id' AND user_id='$user_id' AND node_id='$node_id'"; |
|---|
| 1458 | $db->execSql($sql, $log_rows, false); |
|---|
| 1459 | if ($log_rows != null) { |
|---|
| 1460 | $sql = "UPDATE content_display_log SET num_display = num_display +1, last_display_timestamp = CURRENT_TIMESTAMP WHERE content_id='$this->id' AND user_id='$user_id' AND node_id='$node_id'"; |
|---|
| 1461 | } else { |
|---|
| 1462 | $sql = "INSERT INTO content_display_log (user_id, content_id, node_id) VALUES ('$user_id', '$this->id', '$node_id')"; |
|---|
| 1463 | } |
|---|
| 1464 | $db->execSqlUpdate($sql, false); |
|---|
| 1465 | } |
|---|
| 1466 | } |
|---|
| 1467 | } |
|---|
| 1468 | /** Handle replacements of hyperlinks for clickthrough tracking (if appropriate) */ |
|---|
| 1469 | protected function replaceHyperLinks(& $html) { |
|---|
| 1470 | /* Handle hyperlink clicktrough logging */ |
|---|
| 1471 | if ($this->getLoggingStatus() == true) { |
|---|
| 1472 | $html = HyperLinkUtils :: replaceHyperLinks($html, $this->log_as_content); |
|---|
| 1473 | } |
|---|
| 1474 | return $html; |
|---|
| 1475 | } |
|---|
| 1476 | |
|---|
| 1477 | /** 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. |
|---|
| 1478 | * @param $subclass_admin_interface Html content of the interface element of a children |
|---|
| 1479 | * @return The HTML fragment for this interface */ |
|---|
| 1480 | public function getListUI($subclass_list_interface = null) { |
|---|
| 1481 | $html = ''; |
|---|
| 1482 | $html .= "<div class='list_ui_container'>\n"; |
|---|
| 1483 | $html .= $this->__toString()."\n"; |
|---|
| 1484 | $html .= $subclass_list_interface; |
|---|
| 1485 | $html .= "</div>\n"; |
|---|
| 1486 | return $html; |
|---|
| 1487 | } |
|---|
| 1488 | |
|---|
| 1489 | /** |
|---|
| 1490 | * Retreives the admin interface of this object. Anything that overrides |
|---|
| 1491 | * this method should call the parent method with it's output at the END of |
|---|
| 1492 | * processing. |
|---|
| 1493 | * @param string $subclass_admin_interface HTML content of the interface |
|---|
| 1494 | * element of a children. |
|---|
| 1495 | * @return string The HTML fragment for this interface. |
|---|
| 1496 | */ |
|---|
| 1497 | public function getAdminUI($subclass_admin_interface = null, $title = null) { |
|---|
| 1498 | $db = AbstractDb :: getObject(); |
|---|
| 1499 | |
|---|
| 1500 | $html = ''; |
|---|
| 1501 | if (!(User :: getCurrentUser()->DEPRECATEDisSuperAdmin() || $this->DEPRECATEDisOwner(User :: getCurrentUser()))) { |
|---|
| 1502 | $html .= $this->getListUI(); |
|---|
| 1503 | $html .= ' ' . _("(You do not have access to edit this piece of content)"); |
|---|
| 1504 | } else { |
|---|
| 1505 | $html .= "<fieldset class='admin_container " . get_class($this) . "'>\n"; |
|---|
| 1506 | if (!empty ($title)) { |
|---|
| 1507 | $html .= "<legend>$title</legend>\n"; |
|---|
| 1508 | } |
|---|
| 1509 | $html .= "<ul class='admin_element_list'>\n"; |
|---|
| 1510 | if ($this->getObjectType() == 'Content') { |
|---|
| 1511 | // The object hasn't yet been typed. |
|---|
| 1512 | $html .= _("You must select a content type: "); |
|---|
| 1513 | $i = 0; |
|---|
| 1514 | |
|---|
| 1515 | foreach (self :: getAvailableContentTypes() as $classname) { |
|---|
| 1516 | $tab[$i][0] = $classname; |
|---|
| 1517 | $tab[$i][1] = $classname; |
|---|
| 1518 | $i++; |
|---|
| 1519 | } |
|---|
| 1520 | |
|---|
| 1521 | $html .= FormSelectGenerator :: generateFromArray($tab, null, "content_" . $this->id . "_content_type", "Content", false); |
|---|
| 1522 | } else { |
|---|
| 1523 | $criteria_array = array ( |
|---|
| 1524 | array ( |
|---|
| 1525 | 'isSimpleContent' |
|---|
| 1526 | ) |
|---|
| 1527 | ); |
|---|
| 1528 | $metadada_allowed_content_types = ContentTypeFilter :: getObject($criteria_array); |
|---|
| 1529 | |
|---|
| 1530 | // Content metadata |
|---|
| 1531 | if ($this->isSimpleContent() == false || $this->isPersistent()) { |
|---|
| 1532 | $html .= "<fieldset class='admin_element_group'>\n"; |
|---|
| 1533 | $html .= "<legend>" . sprintf(_("%s MetaData"), get_class($this)) . "</legend>\n"; |
|---|
| 1534 | |
|---|
| 1535 | /* title_is_displayed */ |
|---|
| 1536 | $html_title_is_displayed = _("Display the title?") . ": \n"; |
|---|
| 1537 | $name = "content_" . $this->id . "_title_is_displayed"; |
|---|
| 1538 | $this->titleShouldDisplay() ? $checked = 'CHECKED' : $checked = ''; |
|---|
| 1539 | $html_title_is_displayed .= "<input type='checkbox' name='$name' $checked>\n"; |
|---|
| 1540 | |
|---|
| 1541 | /* title */ |
|---|
| 1542 | $html .= "<li class='admin_element_item_container admin_section_edit_title'>\n"; |
|---|
| 1543 | $html .= "<div class='admin_element_data'>\n"; |
|---|
| 1544 | if (empty ($this->content_row['title'])) { |
|---|
| 1545 | $html .= self :: getNewContentUI("title_{$this->id}_new", $metadada_allowed_content_types, _("Title:")); |
|---|
| 1546 | $html .= "</div>\n"; |
|---|
| 1547 | } else { |
|---|
| 1548 | $html .= $html_title_is_displayed; |
|---|
| 1549 | $title = self :: getObject($this->content_row['title']); |
|---|
| 1550 | $html .= $title->getAdminUI(null, _("Title:")); |
|---|
| 1551 | $html .= "</div>\n"; |
|---|
| 1552 | $html .= "<div class='admin_element_tools admin_section_delete_title'>\n"; |
|---|
| 1553 | $name = "content_" . $this->id . "_title_erase"; |
|---|
| 1554 | $html .= "<input type='submit' class='submit' name='$name' value='" . sprintf(_("Delete %s (%s)"), _("title"), get_class($title)) . "'>"; |
|---|
| 1555 | $html .= "</div>\n"; |
|---|
| 1556 | } |
|---|
| 1557 | $html .= "</li>\n"; |
|---|
| 1558 | } |
|---|
| 1559 | |
|---|
| 1560 | if ($this->isSimpleContent() == false) { |
|---|
| 1561 | /* description */ |
|---|
| 1562 | $html .= "<li class='admin_element_item_container admin_section_edit_description'>\n"; |
|---|
| 1563 | $html .= "<div class='admin_element_data'>\n"; |
|---|
| 1564 | if (empty ($this->content_row['description'])) { |
|---|
| 1565 | $html .= self :: getNewContentUI("description_{$this->id}_new", $metadada_allowed_content_types, _("Description:")); |
|---|
| 1566 | $html .= "</div>\n"; |
|---|
| 1567 | } else { |
|---|
| 1568 | $description = self :: getObject($this->content_row['description']); |
|---|
| 1569 | $html .= $description->getAdminUI(null, _("Description:")); |
|---|
| 1570 | $html .= "</div>\n"; |
|---|
| 1571 | $html .= "<div class='admin_element_tools'>\n"; |
|---|
| 1572 | $name = "content_" . $this->id . "_description_erase"; |
|---|
| 1573 | $html .= "<input type='submit' class='submit' name='$name' value='" . sprintf(_("Delete %s (%s)"), _("description"), get_class($description)) . "'>"; |
|---|
| 1574 | $html .= "</div>\n"; |
|---|
| 1575 | } |
|---|
| 1576 | $html .= "</li>\n"; |
|---|
| 1577 | |
|---|
| 1578 | /* long description */ |
|---|
| 1579 | $html .= "<li class='admin_element_item_container admin_section_edit_long_description'>\n"; |
|---|
| 1580 | $html .= "<div class='admin_element_data'>\n"; |
|---|
| 1581 | if (empty ($this->content_row['long_description'])) { |
|---|
| 1582 | $html .= self :: getNewContentUI("long_description_{$this->id}_new", $metadada_allowed_content_types, _("Long description:")); |
|---|
| 1583 | $html .= "</div>\n"; |
|---|
| 1584 | } else { |
|---|
| 1585 | $description = self :: getObject($this->content_row['long_description']); |
|---|
| 1586 | $html .= $description->getAdminUI(null, _("Long description:")); |
|---|
| 1587 | $html .= "</div>\n"; |
|---|
| 1588 | $html .= "<div class='admin_element_tools'>\n"; |
|---|
| 1589 | $name = "content_" . $this->id . "_long_description_erase"; |
|---|
| 1590 | $html .= "<input type='submit' class='submit' name='$name' value='" . sprintf(_("Delete %s (%s)"), _("long description"), get_class($description)) . "'>"; |
|---|
| 1591 | $html .= "</div>\n"; |
|---|
| 1592 | } |
|---|
| 1593 | $html .= "</li>\n"; |
|---|
| 1594 | |
|---|
| 1595 | /* project_info */ |
|---|
| 1596 | $html .= "<li class='admin_element_item_container admin_section_edit_project'>\n"; |
|---|
| 1597 | $html .= "<div class='admin_element_data'>\n"; |
|---|
| 1598 | if (empty ($this->content_row['project_info'])) { |
|---|
| 1599 | $html .= self :: getNewContentUI("project_info_{$this->id}_new", $metadada_allowed_content_types, _("Information on this project:")); |
|---|
| 1600 | $html .= "</div>\n"; |
|---|
| 1601 | } else { |
|---|
| 1602 | $project_info = self :: getObject($this->content_row['project_info']); |
|---|
| 1603 | $html .= $project_info->getAdminUI(null, _("Information on this project:")); |
|---|
| 1604 | $html .= "</div>\n"; |
|---|
| 1605 | $html .= "<div class='admin_element_tools'>\n"; |
|---|
| 1606 | $name = "content_" . $this->id . "_project_info_erase"; |
|---|
| 1607 | $html .= "<input type='submit' class='submit' name='$name' value='" . sprintf(_("Delete %s (%s)"), _("project information"), get_class($project_info)) . "'>"; |
|---|
| 1608 | $html .= "</div>\n"; |
|---|
| 1609 | } |
|---|
| 1610 | $html .= "</li>\n"; |
|---|
| 1611 | } |
|---|
| 1612 | |
|---|
| 1613 | //End content medatada |
|---|
| 1614 | if ($this->isSimpleContent() == false || $this->isPersistent()) { |
|---|
| 1615 | $html .= "</fieldset>\n"; |
|---|
| 1616 | } |
|---|
| 1617 | |
|---|
| 1618 | if ($this->isSimpleContent() == false || $this->isPersistent()) { |
|---|
| 1619 | |
|---|
| 1620 | $html .= "<fieldset class='admin_element_group'>\n"; |
|---|
| 1621 | $html .= "<legend>" . sprintf(_("%s access control"), get_class($this)) . "</legend>\n"; |
|---|
| 1622 | |
|---|
| 1623 | /* is_persistent */ |
|---|
| 1624 | $html .= "<li class='admin_element_item_container admin_section_edit_persistant'>\n"; |
|---|
| 1625 | $html .= "<div class='admin_element_label'>" . _("Is part of reusable content library (protected from deletion)?") . ": </div>\n"; |
|---|
| 1626 | $html .= "<div class='admin_element_data'>\n"; |
|---|
| 1627 | $name = "content_" . $this->id . "_is_persistent"; |
|---|
| 1628 | $this->isPersistent() ? $checked = 'CHECKED' : $checked = ''; |
|---|
| 1629 | $html .= "<input type='checkbox' name='$name' $checked onChange='submit();'>\n"; |
|---|
| 1630 | $html .= "</div>\n"; |
|---|
| 1631 | $html .= "</li>\n"; |
|---|
| 1632 | |
|---|
| 1633 | /* content_has_owners */ |
|---|
| 1634 | $html .= "<li class='admin_element_item_container content_has_owners'>\n"; |
|---|
| 1635 | $html .= "<div class='admin_element_label'>" . _("Content owner list") . "</div>\n"; |
|---|
| 1636 | $html .= "<ul class='admin_element_list'>\n"; |
|---|
| 1637 | |
|---|
| 1638 | $db = AbstractDb :: getObject(); |
|---|
| 1639 | $sql = "SELECT * FROM content_has_owners WHERE content_id='$this->id'"; |
|---|
| 1640 | $db->execSql($sql, $content_owner_rows, false); |
|---|
| 1641 | if ($content_owner_rows != null) { |
|---|
| 1642 | foreach ($content_owner_rows as $content_owner_row) { |
|---|
| 1643 | $html .= "<li class='admin_element_item_container'>\n"; |
|---|
| 1644 | $html .= "<div class='admin_element_data'>\n"; |
|---|
| 1645 | $user = User :: getObject($content_owner_row['user_id']); |
|---|
| 1646 | |
|---|
| 1647 | $html .= $user->getListUI(); |
|---|
| 1648 | $name = "content_" . $this->id . "_owner_" . $user->GetId() . "_is_author"; |
|---|
| 1649 | $html .= " Is content author? "; |
|---|
| 1650 | |
|---|
| 1651 | $content_owner_row['is_author'] == 't' ? $checked = 'CHECKED' : $checked = ''; |
|---|
| 1652 | $html .= "<input type='checkbox' name='$name' $checked>\n"; |
|---|
| 1653 | $html .= "</div>\n"; |
|---|
| 1654 | $html .= "<div class='admin_element_tools'>\n"; |
|---|
| 1655 | $name = "content_" . $this->id . "_owner_" . $user->GetId() . "_remove"; |
|---|
| 1656 | $html .= "<input type='submit' class='submit' name='$name' value='" . _("Remove owner") . "'>"; |
|---|
| 1657 | $html .= "</div>\n"; |
|---|
| 1658 | $html .= "</li>\n"; |
|---|
| 1659 | } |
|---|
| 1660 | } |
|---|
| 1661 | |
|---|
| 1662 | $html .= "<li class='admin_element_item_container'>\n"; |
|---|
| 1663 | $html .= "<div class='admin_element_data'>\n"; |
|---|
| 1664 | $add_button_name = "content_{$this->id}_add_owner_submit"; |
|---|
| 1665 | $add_button_value = _("Add owner"); |
|---|
| 1666 | $html .= User :: getSelectUserUI("content_{$this->id}_new_owner", $add_button_name, $add_button_value); |
|---|
| 1667 | $html .= "</div>\n"; |
|---|
| 1668 | $html .= "</li>\n"; |
|---|
| 1669 | $html .= "</ul>\n"; |
|---|
| 1670 | $html .= "</li>\n"; |
|---|
| 1671 | $html .= "</fieldset>\n"; |
|---|
| 1672 | |
|---|
| 1673 | } |
|---|
| 1674 | } |
|---|
| 1675 | $html .= $subclass_admin_interface; |
|---|
| 1676 | $html .= "</ul>\n"; |
|---|
| 1677 | $html .= "</fieldset>\n"; |
|---|
| 1678 | } |
|---|
| 1679 | return $html; |
|---|
| 1680 | } |
|---|
| 1681 | /** Process admin interface of this object. When an object overrides this method, they should call the parent processAdminUI at the BEGINING of processing. |
|---|
| 1682 | |
|---|
| 1683 | */ |
|---|
| 1684 | public function processAdminUI() { |
|---|
| 1685 | if ($this->DEPRECATEDisOwner(User :: getCurrentUser()) || User :: getCurrentUser()->DEPRECATEDisSuperAdmin()) { |
|---|
| 1686 | $db = AbstractDb :: getObject(); |
|---|
| 1687 | if ($this->getObjectType() == 'Content') /* The object hasn't yet been typed */ { |
|---|
| 1688 | $content_type = FormSelectGenerator :: getResult("content_" . $this->id . "_content_type", "Content"); |
|---|
| 1689 | $this->setContentType($content_type); |
|---|
| 1690 | } else { |
|---|
| 1691 | //Content medatada |
|---|
| 1692 | |
|---|
| 1693 | if ($this->isSimpleContent() == false || $this->isPersistent()) { |
|---|
| 1694 | /* title_is_displayed */ |
|---|
| 1695 | if (!empty ($this->content_row['title'])) { |
|---|
| 1696 | $name = "content_" . $this->id . "_title_is_displayed"; |
|---|
| 1697 | !empty ($_REQUEST[$name]) ? $this->setTitleIsDisplayed(true) : $this->setTitleIsDisplayed(false); |
|---|
| 1698 | } |
|---|
| 1699 | /* title */ |
|---|
| 1700 | if (empty ($this->content_row['title'])) { |
|---|
| 1701 | $title = self :: processNewContentUI("title_{$this->id}_new"); |
|---|
| 1702 | if ($title != null) { |
|---|
| 1703 | $title_id = $title->GetId(); |
|---|
| 1704 | $db->execSqlUpdate("UPDATE content SET title = '$title_id' WHERE content_id = '$this->id'", FALSE); |
|---|
| 1705 | } |
|---|
| 1706 | } else { |
|---|
| 1707 | $title = self :: getObject($this->content_row['title']); |
|---|
| 1708 | $name = "content_" . $this->id . "_title_erase"; |
|---|
| 1709 | if (!empty ($_REQUEST[$name]) && $_REQUEST[$name] == true) { |
|---|
| 1710 | $db->execSqlUpdate("UPDATE content SET title = NULL WHERE content_id = '$this->id'", FALSE); |
|---|
| 1711 | $title->delete($errmsg); |
|---|
| 1712 | } else { |
|---|
| 1713 | $title->processAdminUI(); |
|---|
| 1714 | } |
|---|
| 1715 | } |
|---|
| 1716 | } |
|---|
| 1717 | if ($this->isSimpleContent() == false) { |
|---|
| 1718 | /* description */ |
|---|
| 1719 | if (empty ($this->content_row['description'])) { |
|---|
| 1720 | $description = self :: processNewContentUI("description_{$this->id}_new"); |
|---|
| 1721 | if ($description != null) { |
|---|
| 1722 | $description_id = $description->GetId(); |
|---|
| 1723 | $db->execSqlUpdate("UPDATE content SET description = '$description_id' WHERE content_id = '$this->id'", FALSE); |
|---|
| 1724 | } |
|---|
| 1725 | } else { |
|---|
| 1726 | $description = self :: getObject($this->content_row['description']); |
|---|
| 1727 | $name = "content_" . $this->id . "_description_erase"; |
|---|
| 1728 | if (!empty ($_REQUEST[$name]) && $_REQUEST[$name] == true) { |
|---|
| 1729 | $db->execSqlUpdate("UPDATE content SET description = NULL WHERE content_id = '$this->id'", FALSE); |
|---|
| 1730 | $description->delete($errmsg); |
|---|
| 1731 | } else { |
|---|
| 1732 | $description->processAdminUI(); |
|---|
| 1733 | } |
|---|
| 1734 | } |
|---|
| 1735 | |
|---|
| 1736 | /* long description */ |
|---|
| 1737 | if (empty ($this->content_row['long_description'])) { |
|---|
| 1738 | $long_description = self :: processNewContentUI("long_description_{$this->id}_new"); |
|---|
| 1739 | if ($long_description != null) { |
|---|
| 1740 | $long_description_id = $long_description->GetId(); |
|---|
| 1741 | $db->execSqlUpdate("UPDATE content SET long_description = '$long_description_id' WHERE content_id = '$this->id'", FALSE); |
|---|
| 1742 | } |
|---|
| 1743 | } else { |
|---|
| 1744 | $long_description = self :: getObject($this->content_row['long_description']); |
|---|
| 1745 | $name = "content_" . $this->id . "_long_description_erase"; |
|---|
| 1746 | if (!empty ($_REQUEST[$name]) && $_REQUEST[$name] == true) { |
|---|
| 1747 | $db->execSqlUpdate("UPDATE content SET long_description = NULL WHERE content_id = '$this->id'", FALSE); |
|---|
| 1748 | $long_description->delete($errmsg); |
|---|
| 1749 | } else { |
|---|
| 1750 | $long_description->processAdminUI(); |
|---|
| 1751 | } |
|---|
| 1752 | } |
|---|
| 1753 | |
|---|
| 1754 | /* project_info */ |
|---|
| 1755 | if (empty ($this->content_row['project_info'])) { |
|---|
| 1756 | $project_info = self :: processNewContentUI("project_info_{$this->id}_new"); |
|---|
| 1757 | if ($project_info != null) { |
|---|
| 1758 | $project_info_id = $project_info->GetId(); |
|---|
| 1759 | $db->execSqlUpdate("UPDATE content SET project_info = '$project_info_id' WHERE content_id = '$this->id'", FALSE); |
|---|
| 1760 | } |
|---|
| 1761 | } else { |
|---|
| 1762 | $project_info = self :: getObject($this->content_row['project_info']); |
|---|
| 1763 | $name = "content_" . $this->id . "_project_info_erase"; |
|---|
| 1764 | if (!empty ($_REQUEST[$name]) && $_REQUEST[$name] == true) { |
|---|
| 1765 | $db->execSqlUpdate("UPDATE content SET project_info = NULL WHERE content_id = '$this->id'", FALSE); |
|---|
| 1766 | $project_info->delete($errmsg); |
|---|
| 1767 | } else { |
|---|
| 1768 | $project_info->processAdminUI(); |
|---|
| 1769 | } |
|---|
| 1770 | } |
|---|
| 1771 | } //End content metadata |
|---|
| 1772 | |
|---|
| 1773 | if ($this->isSimpleContent() == false || $this->isPersistent()) { |
|---|
| 1774 | /* is_persistent */ |
|---|
| 1775 | $name = "content_" . $this->id . "_is_persistent"; |
|---|
| 1776 | !empty ($_REQUEST[$name]) ? $this->setIsPersistent(true) : $this->setIsPersistent(false); |
|---|
| 1777 | |
|---|
| 1778 | /* content_has_owners */ |
|---|
| 1779 | $sql = "SELECT * FROM content_has_owners WHERE content_id='$this->id'"; |
|---|
| 1780 | $db->execSql($sql, $content_owner_rows, false); |
|---|
| 1781 | if ($content_owner_rows != null) { |
|---|
| 1782 | foreach ($content_owner_rows as $content_owner_row) { |
|---|
| 1783 | $user = User :: getObject($content_owner_row['user_id']); |
|---|
| 1784 | $user_id = $user->getId(); |
|---|
| 1785 | $name = "content_" . $this->id . "_owner_" . $user->GetId() . "_remove"; |
|---|
| 1786 | if (!empty ($_REQUEST[$name])) { |
|---|
| 1787 | $this->deleteOwner($user); |
|---|
| 1788 | } else { |
|---|
| 1789 | $name = "content_" . $this->id . "_owner_" . $user->GetId() . "_is_author"; |
|---|
| 1790 | $content_owner_row['is_author'] == 't' ? $is_author = true : $is_author = false; |
|---|
| 1791 | !empty ($_REQUEST[$name]) ? $should_be_author = true : $should_be_author = false; |
|---|
| 1792 | if ($is_author != $should_be_author) { |
|---|
| 1793 | $should_be_author ? $is_author_sql = 'TRUE' : $is_author_sql = 'FALSE'; |
|---|
| 1794 | $sql = "UPDATE content_has_owners SET is_author=$is_author_sql WHERE content_id='$this->id' AND user_id='$user_id'"; |
|---|
| 1795 | |
|---|
| 1796 | if (!$db->execSqlUpdate($sql, false)) { |
|---|
| 1797 | throw new Exception(_('Unable to set as author in the database.')); |
|---|
| 1798 | } |
|---|
| 1799 | |
|---|
| 1800 | } |
|---|
| 1801 | |
|---|
| 1802 | } |
|---|
| 1803 | } |
|---|
| 1804 | } |
|---|
| 1805 | $errMsg=null; |
|---|
| 1806 | $user = User :: processSelectUserUI("content_{$this->id}_new_owner", $errMsg); |
|---|
| 1807 | $name = "content_{$this->id}_add_owner_submit"; |
|---|
| 1808 | if (!empty ($_REQUEST[$name]) && $user != null) { |
|---|
| 1809 | $this->addOwner($user); |
|---|
| 1810 | } |
|---|
| 1811 | } |
|---|
| 1812 | } |
|---|
| 1813 | $this->refresh(); |
|---|
| 1814 | } |
|---|
| 1815 | } |
|---|
| 1816 | |
|---|
| 1817 | /** |
|---|
| 1818 | * Tell if a given user is already subscribed to this content |
|---|
| 1819 | * @param User the given user |
|---|
| 1820 | * @return boolean |
|---|
| 1821 | */ |
|---|
| 1822 | public function isUserSubscribed(User $user) { |
|---|
| 1823 | $db = AbstractDb :: getObject(); |
|---|
| 1824 | $sql = "SELECT content_id FROM user_has_content WHERE user_id = '{$user->getId()}' AND content_id = '{$this->getId()}';"; |
|---|
| 1825 | $db->execSqlUniqueRes($sql, $row, false); |
|---|
| 1826 | |
|---|
| 1827 | if ($row) |
|---|
| 1828 | return true; |
|---|
| 1829 | else |
|---|
| 1830 | return false; |
|---|
| 1831 | } |
|---|
| 1832 | |
|---|
| 1833 | /** Subscribe to the project |
|---|
| 1834 | * @return true on success, false on failure */ |
|---|
| 1835 | public function subscribe(User $user) { |
|---|
| 1836 | return $user->addContent($this); |
|---|
| 1837 | } |
|---|
| 1838 | /** Unsubscribe to the project |
|---|
| 1839 | * @return true on success, false on failure */ |
|---|
| 1840 | public function unsubscribe(User $user) { |
|---|
| 1841 | return $user->removeContent($this); |
|---|
| 1842 | } |
|---|
| 1843 | |
|---|
| 1844 | /** If the title is not empty, should it be displayed? |
|---|
| 1845 | * @return true or false */ |
|---|
| 1846 | public function titleShouldDisplay() { |
|---|
| 1847 | if ($this->content_row['title_is_displayed'] == 't') { |
|---|
| 1848 | $retval = true; |
|---|
| 1849 | } else { |
|---|
| 1850 | $retval = false; |
|---|
| 1851 | } |
|---|
| 1852 | return $retval; |
|---|
| 1853 | } |
|---|
| 1854 | |
|---|
| 1855 | /** If the title is not empty, should it be displayed? |
|---|
| 1856 | * @param $should_display true or false |
|---|
| 1857 | * */ |
|---|
| 1858 | public function setTitleIsDisplayed($should_display) { |
|---|
| 1859 | if ($should_display != $this->titleShouldDisplay()) /* Only update database if there is an actual change */ { |
|---|
| 1860 | $should_display ? $should_display_sql = 'TRUE' : $should_display_sql = 'FALSE'; |
|---|
| 1861 | $db = AbstractDb :: getObject(); |
|---|
| 1862 | $db->execSqlUpdate("UPDATE content SET title_is_displayed = $should_display_sql WHERE content_id = '$this->id'", false); |
|---|
| 1863 | $this->refresh(); |
|---|
| 1864 | } |
|---|
| 1865 | |
|---|
| 1866 | } |
|---|
| 1867 | |
|---|
| 1868 | /** 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. |
|---|
| 1869 | * @return true or false */ |
|---|
| 1870 | public function isPersistent() { |
|---|
| 1871 | if ($this->content_row['is_persistent'] == 't') { |
|---|
| 1872 | $retval = true; |
|---|
| 1873 | } else { |
|---|
| 1874 | $retval = false; |
|---|
| 1875 | } |
|---|
| 1876 | return $retval; |
|---|
| 1877 | } |
|---|
| 1878 | |
|---|
| 1879 | /** Set if the content group is persistent |
|---|
| 1880 | * @param $is_persistent true or false |
|---|
| 1881 | * */ |
|---|
| 1882 | public function setIsPersistent($is_persistent) { |
|---|
| 1883 | if ($is_persistent != $this->isPersistent()) /* Only update database if there is an actual change */ { |
|---|
| 1884 | $is_persistent ? $is_persistent_sql = 'TRUE' : $is_persistent_sql = 'FALSE'; |
|---|
| 1885 | |
|---|
| 1886 | $db = AbstractDb :: getObject(); |
|---|
| 1887 | $db->execSqlUpdate("UPDATE content SET is_persistent = $is_persistent_sql WHERE content_id = '$this->id'", false); |
|---|
| 1888 | $this->refresh(); |
|---|
| 1889 | } |
|---|
| 1890 | |
|---|
| 1891 | } |
|---|
| 1892 | |
|---|
| 1893 | /** |
|---|
| 1894 | * Return update date |
|---|
| 1895 | * |
|---|
| 1896 | * @return string ISO-8601-2000 timestamp |
|---|
| 1897 | */ |
|---|
| 1898 | public function getLastUpdateTimestamp() { |
|---|
| 1899 | return $this->content_row['last_update_timestamp']; |
|---|
| 1900 | } |
|---|
| 1901 | /** |
|---|
| 1902 | * Touch countent: set last_update_timestamp to now |
|---|
| 1903 | * Note that this is meant to be called when there is substantial |
|---|
| 1904 | * change to the actual content (the file changed, the main text changed, |
|---|
| 1905 | * etc.) |
|---|
| 1906 | */ |
|---|
| 1907 | public function touch() { |
|---|
| 1908 | $this->mBd->execSqlUpdate("UPDATE content SET last_update_timestamp = CURRENT_TIMESTAMP WHERE content_id='" . $this->getId() . "'", false); |
|---|
| 1909 | $this->refresh(); |
|---|
| 1910 | } |
|---|
| 1911 | /** Reloads the object from the database. Should normally be called after a set operation. |
|---|
| 1912 | * This function is private because calling it from a subclass will call the |
|---|
| 1913 | * constructor from the wrong scope */ |
|---|
| 1914 | private function refresh() { |
|---|
| 1915 | $this->__construct($this->id); |
|---|
| 1916 | } |
|---|
| 1917 | |
|---|
| 1918 | /** |
|---|
| 1919 | * @see GenericObject |
|---|
| 1920 | * @internal Persistent content will not be deleted |
|---|
| 1921 | */ |
|---|
| 1922 | public function delete(& $errmsg) { |
|---|
| 1923 | $retval = false; |
|---|
| 1924 | if ($this->isPersistent()) { |
|---|
| 1925 | $errmsg = _("Content is persistent (you must make it non persistent before you can delete it)"); |
|---|
| 1926 | } else { |
|---|
| 1927 | $db = AbstractDb :: getObject(); |
|---|
| 1928 | if ($this->DEPRECATEDisOwner(User :: getCurrentUser()) || User :: getCurrentUser()->DEPRECATEDisSuperAdmin()) { |
|---|
| 1929 | |
|---|
| 1930 | $sql = "DELETE FROM content WHERE content_id='$this->id'"; |
|---|
| 1931 | $db->execSqlUpdate($sql, false); |
|---|
| 1932 | //Metadata mmust be deleted AFTER the main content. |
|---|
| 1933 | $errmsgTmp = null; |
|---|
| 1934 | $metadata = $this->getTitle(); |
|---|
| 1935 | if ($metadata){ |
|---|
| 1936 | $metadata->delete($errmsgTmp); |
|---|
| 1937 | } |
|---|
| 1938 | $errmsg .= $errmsgTmp; |
|---|
| 1939 | $errmsgTmp = null; |
|---|
| 1940 | $metadata = $this->getDescription(); |
|---|
| 1941 | if ($metadata){ |
|---|
| 1942 | $metadata->delete($errmsgTmp); |
|---|
| 1943 | } |
|---|
| 1944 | $errmsg .= $errmsgTmp; |
|---|
| 1945 | $errmsgTmp = null; |
|---|
| 1946 | $metadata = $this->getLongDescription(); |
|---|
| 1947 | if ($metadata){ |
|---|
| 1948 | $metadata->delete($errmsgTmp); |
|---|
| 1949 | } |
|---|
| 1950 | $errmsg .= $errmsgTmp; |
|---|
| 1951 | $errmsgTmp = null; |
|---|
| 1952 | $metadata = $this->getProjectInfo(); |
|---|
| 1953 | if ($metadata){ |
|---|
| 1954 | $metadata->delete($errmsgTmp); |
|---|
| 1955 | } |
|---|
| 1956 | $errmsg .= $errmsgTmp; |
|---|
| 1957 | $retval = true; |
|---|
| 1958 | } else { |
|---|
| 1959 | $errmsg = _("Access denied (not owner of content)"); |
|---|
| 1960 | } |
|---|
| 1961 | } |
|---|
| 1962 | return $retval; |
|---|
| 1963 | } |
|---|
| 1964 | /** Menu hook function */ |
|---|
| 1965 | static public function hookMenu() { |
|---|
| 1966 | $items = array(); |
|---|
| 1967 | $server = Server::getServer(); |
|---|
| 1968 | if(Security::hasAnyPermission(array(array(Permission::P('SERVER_PERM_EDIT_CONTENT_LIBRARY'), $server)))) |
|---|
| 1969 | { |
|---|
| 1970 | $items[] = array('path' => 'server/content_library', |
|---|
| 1971 | 'title' => _("Reusable content library"), |
|---|
| 1972 | 'url' => BASE_URL_PATH.htmlspecialchars("admin/generic_object_admin.php?object_class=Content&action=list") |
|---|
| 1973 | ); |
|---|
| 1974 | } |
|---|
| 1975 | |
|---|
| 1976 | return $items; |
|---|
| 1977 | } |
|---|
| 1978 | |
|---|
| 1979 | |
|---|
| 1980 | } // End class |
|---|
| 1981 | |
|---|
| 1982 | /* This allows the class to enumerate it's children properly */ |
|---|
| 1983 | $class_names = Content :: getAvailableContentTypes(); |
|---|
| 1984 | |
|---|
| 1985 | foreach ($class_names as $class_name) { |
|---|
| 1986 | /** |
|---|
| 1987 | * Load requested content class |
|---|
| 1988 | */ |
|---|
| 1989 | require_once ('classes/Content/' . $class_name . '/' . $class_name . '.php'); |
|---|
| 1990 | } |
|---|
| 1991 | |
|---|
| 1992 | /* |
|---|
| 1993 | * Local variables: |
|---|
| 1994 | * tab-width: 4 |
|---|
| 1995 | * c-basic-offset: 4 |
|---|
| 1996 | * c-hanging-comment-ender-p: nil |
|---|
| 1997 | * End: |
|---|
| 1998 | */ |
|---|