| [ Index ] |
|
Code source de Plume CMS 1.2.2 |
1 <?php 2 /* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 3 /* 4 # ***** BEGIN LICENSE BLOCK ***** 5 # This file is part of Plume CMS, a website management application. 6 # Copyright (C) 2001-2005 Loic d'Anterroches and contributors. 7 # 8 # Plume CMS is free software; you can redistribute it and/or modify 9 # it under the terms of the GNU General Public License as published by 10 # the Free Software Foundation; either version 2 of the License, or 11 # (at your option) any later version. 12 # 13 # Plume CMS is distributed in the hope that it will be useful, 14 # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 # GNU General Public License for more details. 17 # 18 # You should have received a copy of the GNU General Public License 19 # along with this program; if not, write to the Free Software 20 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 21 # 22 # ***** END LICENSE BLOCK ***** */ 23 24 require_once dirname(__FILE__).'/class.resource.php'; 25 require_once dirname(__FILE__).'/class.page.php'; 26 27 define('PX_RESOURCE_MANAGER_ARTICLE','articles'); 28 29 /** 30 * Article class. This is the data storage of an article. 31 */ 32 class Article extends Resource 33 { 34 var $pages = null; /**< Recordset of the pages. */ 35 36 37 /** 38 * Constructor. 39 */ 40 function Article($data='') 41 { 42 parent::Resource($data); 43 $this->pages = new Page(); 44 } 45 46 47 /** 48 * Load the article. 49 * 50 * @param mixed Identifier or resource id ('') 51 * @return bool Success 52 */ 53 function load($id='') 54 { 55 if (false === parent::load($id)) { //categories and authors 56 return false; 57 } 58 if (PX_RESOURCE_MANAGER_ARTICLE != $this->f('type_id')) 59 return false; 60 61 if (false === $this->loadPages()) 62 return false; 63 64 $this->isModified = False; 65 $this->runPostLoadHook(); 66 return true; 67 } 68 69 70 /** 71 * Load the pages of an articles. 72 * The pages are stored in $this->pages for later reuse. 73 * 74 * @return bool Success or error 75 */ 76 function loadPages() 77 { 78 $this->getConnection(); 79 $r = 'SELECT * FROM '.$this->con->pfx.'articles WHERE resource_id=\''. 80 $this->f('resource_id').'\' ORDER BY page_number ASC'; 81 if (($rs = $this->con->select($r, 'Page')) !== false) { 82 $this->pages = $rs; 83 return true; 84 } else { 85 $this->con->setError(); 86 return false; 87 } 88 } 89 90 /** 91 * Return the content of the article as a string ready for indexation. 92 * 93 * @param string Format of the string (html, wiki, text) 94 * @return string The content of the news as a string 95 */ 96 function getAsString($format='html') 97 { 98 $idx = $this->pages->getIndex(); 99 $this->pages->moveStart(); 100 101 $string = str_repeat($this->f('title').' ', 5); 102 $string .= ' '.str_repeat($this->f('subject').' ', 3); 103 $string .= ' '.str_repeat($this->f('path').' ', 3); 104 $string .= ' '.$this->f('description'); 105 while (!$this->pages->EOF()) { 106 $string .= ' '.str_repeat($this->pages->f('page_title').' ', 3); 107 $string .= ' '.$this->pages->f('page_content'); 108 $this->pages->moveNext(); 109 } 110 $this->pages->move($idx); 111 return $string; 112 } 113 114 /** 115 * Set the default values for the article. 116 * 117 * @param object User object to have the preferences 118 * @return bool True 119 */ 120 function setDefaults($user) 121 { 122 parent::setDefaults($user); 123 if ($user->getPref('articles_status')) { 124 $this->setField('status', $user->getPref('articles_status')); 125 } else { 126 $this->setField('status', PX_RESOURCE_STATUS_INEDITION); 127 } 128 $this->setField('category_id', $user->getPref('articles_category_id')); 129 $this->setField('subtype_id', $user->getPref('articles_subtype')); 130 131 $this->isModified = true; 132 return true; 133 } 134 135 /** 136 * Set the basic data of an article. 137 * The basic data are the one saved in the table `resources`. 138 * There is only a check of the data, use the commit() method 139 * to save in the database. 140 * 141 * @param string Title of the article 142 * @param string Subject or keywords 143 * @param string Description of the article 144 * @param string Format of the description 145 * @param int Status 146 * @param string Path 147 * @param timestamp Date of publication 148 * @param timestamp Date of end of publication 149 * @param bool Use a date of end of publication 150 * @param int Comment support 151 * @param int Subtype of the article 152 */ 153 function set($title, $subject, $content, $format, $status, $path, 154 $datestart, $dateend, $useenddate, $comment_support, $subtype) 155 { 156 // Some cleaning 157 $datestart = date::clean($datestart); 158 if (!empty($useenddate)) { 159 $dateend = date::EOT(); 160 } 161 $dateend = date::clean($dateend); 162 163 // Set the values 164 $this->setField('subtype_id', $subtype); 165 $this->setField('subject', $subject); 166 $this->setField('title', $title); 167 $this->setField('description', '='.$format."\n".$content); 168 $this->setField('path', $path); 169 $this->setField('publicationdate', $datestart); 170 $this->setField('enddate', $dateend); 171 $this->setField('status', $status); 172 $this->setField('comment_support', (int) $comment_support); 173 174 $this->isModified = true; 175 176 return true; 177 } 178 179 /** 180 * Set a page. 181 * If the page id is empty, a new page is added. 182 * 183 * @param int Id of the page 184 * @param string Title of the page 185 * @param string Content 186 * @param string Format 187 * @param int Number 188 * @return bool Success 189 */ 190 function setPage($id, $title, $content, $format, $number) 191 { 192 if (!empty($id)) { 193 if (false === $this->goToPage($id)) { 194 $this->setError(__('Error: Try to update a non existing page.'), 400); 195 return false; 196 } 197 } 198 199 $this->pages->setField('old_number', $this->pages->f('page_number')); 200 $this->pages->setField('page_number', $number); 201 $this->pages->setField('page_title', $title); 202 $this->pages->setField('page_content', '='.$format."\n".$content); 203 204 $this->isModified = true; 205 206 return true; 207 } 208 209 210 211 /** 212 * Check the consistency of the data of the article. 213 * 214 * Simply goes through the object and check that the values are not 215 * possibly conflicting. The check is only with respect to the type 216 * of the data, no integrity check like existence of a matching 217 * author in the base is done. 218 * 219 * @return bool Success, if false the error is set. 220 */ 221 function check() 222 { 223 if (strlen($this->f('title')) == 0) { 224 $this->setError(__('You need to give a title.'), 400); 225 } 226 if (false === date::clean($this->f('publicationdate'))) { 227 $this->setError(__('The publication date is wrong.'), 400); 228 } 229 if (false === date::clean($this->f('enddate'))) { 230 $this->setError(__('The off-line date is wrong.'), 400); 231 } 232 if (strlen($this->f('subtype_id')) == 0) { 233 $this->setError(__('A type of resource is needed.'), 400); 234 } 235 236 // Path validation 237 if (strlen($this->f('path')) == 0) { 238 $this->setError(__('A path for the article must be provided.'), 239 400); 240 } 241 if (strlen($this->f('path')) > 0 242 && !preg_match('/^([A-Za-z]|[A-Za-z][A-Za-z0-9\_\-]*[A-Za-z])$/', 243 $this->f('path'))) { 244 $this->setError(__('Illegal characters in the path. Please read the help to know how to choose the right path for your article.'), 400); 245 } 246 $id = $this->isPathInUse($this->f('path')); 247 if ($id !== false && $id != $this->f('resource_id')) { 248 $format = __('An article is already using the path: <em>%s</em>. Please use another one.'); 249 $this->setError(sprintf($format, $this->f('path')), 400); 250 } 251 252 if (false !== $this->error()) { 253 return false; 254 } 255 return true; 256 } 257 258 259 /** 260 * Go to the page with a specific id. 261 * In case of success the $this->pages recordset is set to the page. 262 * 263 * @param int id of the page 264 * @return bool success to go to the page 265 */ 266 function goToPage($id) 267 { 268 $this->pages->moveStart(); 269 $page_id = $this->pages->f('page_id'); 270 $found = true; 271 // get the requested page from the list of pages 272 while ($id != $page_id) { 273 if (false != $this->pages->moveNext()) { 274 $page_id = $this->pages->f('page_id'); 275 } else { 276 $found = false; //went through all the pages without finding it 277 break; 278 } 279 } 280 return $found; 281 } 282 283 284 285 /** 286 * Get path to the current article page. 287 * It uses the current page in $this->pages 288 * 289 * @return string The path to the current page 290 */ 291 function getPathToPage() 292 { 293 $base = $this->getPath(); 294 if ($this->pages->f('page_number') != 1) { 295 $base = $base.$this->pages->f('page_number'); 296 } 297 return $base; 298 } 299 300 301 /** 302 * Get an array with the list of the pages. 303 * 304 * @param bool Auto 'at the end' (true) 305 * @return array Ready to use in combo box 306 */ 307 function getArrayPageList($auto=true) 308 { 309 $list = array(); 310 $np = $this->pages->nbRowTotal(); // at init, the maybe newly added 311 // is not taken into account 312 if ($auto == true && $this->pages->f('page_id') == '') { 313 $list[__('At the end')] = $np + 1; 314 } 315 for ($i=1; $i<=$np; $i++) { 316 $list[(string) $i] = (string) $i; 317 } 318 return $list; 319 } 320 321 322 323 /** 324 * Check that the data for the page to be added or updated are 325 * correct. 326 * 327 * @return bool Success 328 */ 329 function checkPage() 330 { 331 if (strlen($this->pages->f('page_title')) == 0) { 332 $this->setError(__('The page must have a title.'), 400); 333 } 334 if (!preg_match('/^\d+$/', $this->pages->f('page_number'))) { 335 $this->setError(__('Error: Invalid page number.'), 400); 336 } 337 if (strlen($this->getUnformattedContent('page_content', 'pages')) == 0) { 338 $this->setError(__('The page must have a content.'), 400); 339 } 340 //Check only if not empty. 341 if (strlen($this->pages->f('page_id')) 342 && !preg_match('/^\d+$/', $this->pages->f('page_id'))) { 343 $this->setError(__('Error: Invalid page id.'), 400); 344 } 345 if (false !== $this->error()) { 346 return false; 347 } 348 return true; 349 } 350 351 /* ===================================================================== * 352 * * 353 * Methods for rendering the pages. * 354 * * 355 * Note: All standalone methods. * 356 * ===================================================================== */ 357 358 /** 359 * Action to display a category. 360 * 361 * @param string Server query string 362 * @return int Success code 363 */ 364 function action($query) 365 { 366 Hook::register('onInitTemplate', 'Article', 'hookOnInitTemplate'); 367 368 // Easy access 369 $GLOBALS['_PX_render']['last'] = ''; 370 $last =& $GLOBALS['_PX_render']['last']; 371 $GLOBALS['_PX_render']['website'] = ''; 372 $website =& $GLOBALS['_PX_render']['website']; 373 $GLOBALS['_PX_render']['cat'] = ''; 374 $cat =& $GLOBALS['_PX_render']['cat']; 375 $GLOBALS['_PX_render']['art'] = ''; 376 $art =& $GLOBALS['_PX_render']['art']; 377 $GLOBALS['_PX_render']['res'] = ''; 378 $res =& $GLOBALS['_PX_render']['res']; 379 $GLOBALS['_PX_render']['ct'] = ''; 380 $ct =& $GLOBALS['_PX_render']['ct']; 381 382 // Parse query string to find the matching article 383 list($path, $page, $category_path) = Article::parseQueryString($query); 384 385 $sql = SQL::getOnlineResourceInCat($path, $category_path, 386 config::f('website_id')); 387 $con =& pxDBConnect(); 388 if (($art = $con->select($sql, 'Article')) !== false) { 389 if (!$art->isEmpty()) { 390 $art->load(); 391 } else { 392 return 404; 393 } 394 } else { 395 $GLOBALS['_PX_render']['error']->setError('MySQL: ' 396 .$con->error(), 500); 397 return 404; 398 } 399 include_once dirname(__FILE__).'/class.cache.php'; 400 $cache = new Cache(urlencode('articles%%'.$path.'%%'.$page.'%%'.$category_path)); 401 $cache->setCacheDirectory(config::getCacheDir()); 402 $cache->debug = config::f('debug'); 403 404 $art->pages->move($page - 1); 405 $GLOBALS['_PX_render']['ct'] = $art->comments; 406 $GLOBALS['_PX_render']['res_id'] = $art->f('resource_id'); 407 header(FrontEnd::getHeader($art->f('subtype_template'))); 408 // Load the template 409 include config::f('manager_path').'/templates/' 410 .config::f('theme_id').'/'.$art->f('subtype_template'); 411 return 200; 412 } 413 414 /** 415 * Hook on the initialization of the templates. 416 * 417 * @param string Name of the calling hook 418 * @param array Default parameters (not used) 419 * @return bool Success 420 */ 421 function hookOnInitTemplate($hook, $param) 422 { 423 if (config::f('action') == 'Article') { 424 $GLOBALS['_PX_render']['cat'] = FrontEnd::getCategory($GLOBALS['_PX_render']['art']->f('category_id'));; 425 $GLOBALS['_PX_render']['website'] = FrontEnd::getWebsite(); 426 if (config::f('order_res_manual')) { 427 $order = 'ORDER BY %sresources.title ASC'; 428 } else { 429 $order = 'ORDER BY %sresources.publicationdate DESC'; 430 } 431 $GLOBALS['_PX_render']['res'] = FrontEnd::getResources($GLOBALS['_PX_render']['art']->f('category_id'), 432 '', '', 1, $order); 433 $GLOBALS['_PX_render']['ct_enabled'] = false; 434 if ((config::f('comment_support') == 1) 435 or (config::f('comment_support') == 2 && 436 $GLOBALS['_PX_render']['art']->f('comment_support') == 1)) { 437 $GLOBALS['_PX_render']['ct_enabled'] = true; 438 } 439 } 440 return true; 441 } 442 443 444 /** 445 * Parse query string. 446 * 447 * @param string Query string 448 * @return array (article path, page number, category path) 449 */ 450 function parseQueryString($query) 451 { 452 $category = ''; 453 $path = ''; 454 $page = 1; 455 if (preg_match('#^(.*/)([a-z]|[a-z][a-z0-9\_\-]*[a-z])(\d*)$#i', 456 $query, $match)) { 457 $category = $match[1]; 458 $path = $match[2]; 459 $page = ($match[3]) ? (int)$match[3] : 1; 460 } 461 return array($path, $page, $category); 462 } 463 464 465 /* ===================================================================== * 466 * * 467 * Methods modifying data in the database. * 468 * * 469 * ===================================================================== */ 470 471 472 /** 473 * Save the article in the database. 474 * 475 * Only the basic data of the article are saved. The pages are not 476 * saved. See commitPage() to commit a page into the database. 477 * 478 * @return bool Success 479 */ 480 function commit() 481 { 482 if (false === $this->isModified) { 483 return true; 484 } 485 486 if (false === $this->check()) { 487 return false; 488 } 489 490 //Real INSERT/UPDATE into the tables 491 $this->getConnection(); 492 $update = (0 < (int) $this->f('resource_id')) ? true : false; 493 494 if ($update) { 495 $req = 'UPDATE '.$this->con->pfx.'resources SET 496 subject = \''.$this->con->esc($this->f('subject')).'\', 497 subtype_id = \''.$this->con->esc($this->f('subtype_id')).'\', 498 title = \''.$this->con->esc($this->f('title')).'\', 499 path = \''.$this->con->esc($this->f('path')).'\', 500 description = \''.$this->con->esc($this->f('description')).'\', 501 publicationdate = \''.$this->con->esc($this->f('publicationdate')).'\', 502 comment_support = \''.$this->con->esc($this->f('comment_support')).'\', 503 modifdate = \''.date::stamp().'\', 504 enddate = \''.$this->con->esc($this->f('enddate')).'\', 505 status = \''.$this->con->esc($this->f('status')).'\' 506 WHERE 507 resource_id = \''.$this->con->esc($this->f('resource_id')).'\''; 508 } else { 509 $req = 'INSERT INTO '.$this->con->pfx.'resources SET 510 website_id = \''.$this->con->esc($this->f('website_id')).'\', 511 type_id = \''.PX_RESOURCE_MANAGER_ARTICLE.'\', 512 subtype_id = \''.$this->con->esc($this->f('subtype_id')).'\', 513 comment_support = \''.$this->con->esc($this->f('comment_support')).'\', 514 user_id = \''.$this->con->esc($this->f('user_id')).'\', 515 subject = \''.$this->con->esc($this->f('subject')).'\', 516 creatorname = \'\', 517 creatoremail = \'\', 518 creatorwebsite = \'\', 519 publisher = \'\', 520 lang_id = \''.config::f('lang').'\', 521 title = \''.$this->con->esc($this->f('title')).'\', 522 description = \''.$this->con->esc($this->f('description')).'\', 523 path = \''.$this->con->esc($this->f('path')).'\', 524 creationdate = \''.date::stamp().'\', 525 publicationdate = \''.date::stamp().'\', 526 modifdate = \''.date::stamp().'\', 527 enddate = \''.date::EOT().'\', 528 status = \''.$this->con->esc($this->f('status')).'\', 529 size = \'\', 530 version = 1, 531 comment = \'\', 532 misc = \'\', 533 format = \'text/html\', 534 dctype = \'Text\', 535 dccoverage = \'\', 536 rights = \'\''; 537 } 538 539 if (!$this->con->execute($req)) { 540 $this->setError('MySQL: '.$this->con->error(), 500); 541 return false; 542 } 543 if (!$update) { 544 //Insert, need to get the id of the article as 545 //the identifier is based on it. Sadly, it is not possible to get 546 //the value directly in the insert statement: 547 // <http://dev.mysql.com/doc/mysql/en/INSERT.html> 548 if (false == ($id = $this->con->getLastID())) { 549 $this->setError('MySQL: '.$this->con->error(), 500); 550 return false; 551 } 552 $this->setField('resource_id', $id); 553 $this->setField('identifier', 'art-'.$id); 554 $req = 'UPDATE '.$this->con->pfx.'resources SET 555 identifier = \''.$this->f('identifier').'\' 556 WHERE resource_id = \''.$this->con->esc($id).'\''; 557 if (!$this->con->execute($req)) { 558 $this->setError('MySQL: '.$this->con->error(), 500); 559 return false; 560 } 561 } 562 563 if (empty($id)) $id = $this->f('resource_id'); 564 565 if ($this->addAuthor($this->f('user_id')) 566 && $this->addToCategory($this->f('category_id')) 567 && $this->load($id)) { 568 $this->runPostCommitHook(); 569 return true; 570 } else { 571 return false; 572 } 573 } 574 575 /** 576 * Remove the article from the database. 577 * 578 * @return bool Success 579 */ 580 function remove() 581 { 582 $id = $this->f('resource_id'); 583 if (empty($id)) { 584 return true; 585 } 586 587 $req = 'DELETE FROM '.$this->con->pfx.'resources WHERE 588 resource_id = \''.$this->con->esc($id).'\''; 589 if (!$this->con->execute($req)) { 590 $this->setError('MySQL: '.$this->con->error(), 500); 591 return false; 592 } 593 594 $req = 'DELETE FROM '.$this->con->pfx.'categoryasso WHERE 595 identifier = \'art-'.$this->con->esc($id).'\''; 596 if (!$this->con->execute($req)) { 597 $this->setError('MySQL: '.$this->con->error(), 500); 598 return false; 599 } 600 601 $req = 'DELETE FROM '.$this->con->pfx.'authorasso WHERE 602 resource_id = \''.$this->con->esc($id).'\''; 603 if (!$this->con->execute($req)) { 604 $this->setError('MySQL: '.$this->con->error(), 500); 605 return false; 606 } 607 608 $req = 'DELETE FROM '.$this->con->pfx.'articles WHERE 609 resource_id = \''.$this->con->esc($id).'\''; 610 if (!$this->con->execute($req)) { 611 $this->setError('MySQL: '.$this->con->error(), 500); 612 return false; 613 } 614 615 return true; 616 } 617 618 /** 619 * Save the current page in the database. 620 * 621 * The page currently pointed in $this->pages is saved in the 622 * database. It means that you need to be carefull between the 623 * call to setPage() and commitPage() not to "move" the cursor. 624 * 625 * @return mixed Id of the page if success, false if error 626 */ 627 function commitPage() 628 { 629 if (false === $this->checkPage()) { 630 return false; 631 } 632 $number = $this->pages->f('page_number'); 633 $oldnumber = $this->pages->f('old_number'); 634 if (empty($oldnumber)) { 635 $oldnumber = $this->pages->nbRow(); 636 } 637 638 $this->getConnection(); 639 640 // Update the numbers of the pages if needed 641 if ($oldnumber != $number) { 642 $insReq = 'UPDATE '.$this->con->pfx.'articles SET 643 page_number=page_number+1 644 WHERE page_number < '.$this->con->esc($oldnumber).' 645 AND page_number >= '.$this->con->esc($number).' 646 AND resource_id=\''.$this->con->esc($this->f('resource_id')).'\''; 647 if (!$this->con->execute($insReq)) { 648 $this->setError('MySQL: '.$this->con->error(), 500); 649 return false; 650 } 651 $insReq = 'UPDATE '.$this->con->pfx.'articles SET 652 page_number=page_number-1 653 WHERE page_number > '.$this->con->esc($oldnumber).' 654 AND page_number <= '.$this->con->esc($number).' 655 AND resource_id=\''.$this->con->esc($this->f('resource_id')).'\''; 656 if (!$this->con->execute($insReq)) { 657 $this->setError('MySQL: '.$this->con->error(), 500); 658 return false; 659 } 660 } 661 662 //Really add/update the content of the page 663 if (0 == strlen($this->pages->f('page_id'))) { 664 $insReq = 'INSERT INTO '.$this->con->pfx.'articles SET 665 page_number = \''.$this->con->esc($this->pages->f('page_number')).'\', 666 page_title = \''.$this->con->esc($this->pages->f('page_title')).'\', 667 page_content = \''.$this->con->esc($this->pages->f('page_content')).'\', 668 page_creationdate = \''.date::stamp().'\', 669 page_modifdate = \''.date::stamp().'\', 670 resource_id = \''.$this->con->esc($this->f('resource_id')).'\''; 671 } else { 672 $insReq = 'UPDATE '.$this->con->pfx.'articles SET 673 page_number = \''.$this->con->esc($this->pages->f('page_number')).'\', 674 page_title = \''.$this->con->esc($this->pages->f('page_title')).'\', 675 page_content = \''.$this->con->esc($this->pages->f('page_content')).'\', 676 page_modifdate = \''.date::stamp().'\' 677 WHERE 678 page_id = \''.$this->con->esc($this->pages->f('page_id')).'\''; 679 } 680 if (!$this->con->execute($insReq)) { 681 $this->setError('MySQL: '.$this->con->error(), 500); 682 return false; 683 } 684 $number = $this->pages->f('page_number'); 685 $this->loadPages(); //Synchro 686 $this->pages->move($number-1); //Move to the just added page 687 return $this->pages->f('page_id'); 688 } 689 690 /** 691 * Remove a page of the article. 692 * Remove the current page. 693 * 694 * @return bool Success 695 */ 696 function removePage() 697 { 698 $this->getConnection(); 699 700 $delReq = 'DELETE FROM '.$this->con->pfx.'articles WHERE 701 resource_id = \''.$this->con->esc($this->f('resource_id')).'\' 702 AND page_id=\''.$this->con->esc($this->pages->f('page_id')).'\''; 703 704 if (!$this->con->execute($delReq)) { 705 $this->setError('MySQL: '.$this->con->error(), 500); 706 return false; 707 } 708 $this->loadPages(); //Synchro 709 return true; 710 } 711 712 } 713 714 ?>
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
| Généré le : Mon Nov 26 11:57:01 2007 | par Balluche grâce à PHPXref 0.7 |
|