Overview

Packages

  • CONTENIDO
  • Core
    • Authentication
    • Backend
    • Cache
    • CEC
    • Chain
    • ContentType
    • Database
    • Debug
    • Exception
    • Frontend
      • Search
      • URI
      • Util
    • GenericDB
      • Model
    • GUI
      • HTML
    • I18N
    • LayoutHandler
    • Log
    • Security
    • Session
    • Util
    • Validation
    • Versioning
    • XML
  • Module
    • ContentRssCreator
    • ContentSitemapHtml
    • ContentSitemapXml
    • ContentUserForum
    • NavigationTop
    • ScriptCookieDirective
  • mpAutoloaderClassMap
  • None
  • Plugin
    • ContentAllocation
    • CronjobOverview
    • FormAssistant
    • FrontendLogic
    • FrontendUsers
    • Linkchecker
    • ModRewrite
    • Newsletter
    • Repository
      • FrontendNavigation
      • KeywordDensity
    • SearchSolr
    • SmartyWrapper
    • UrlShortener
    • UserForum
    • Workflow
  • PluginManager
  • Setup
    • Form
    • GUI
    • Helper
      • Environment
      • Filesystem
      • MySQL
      • PHP
    • UpgradeJob

Classes

  • ArticleForum
  • cGenericDb
  • cGenericDbDriver
  • cGenericDbDriverMysql
  • cItemBaseAbstract
  • cItemCache
  • Item
  • ItemCollection
  • Overview
  • Package
  • Class
  • Tree
  • Deprecated
  • Todo
  1: <?php
  2: 
  3: /**
  4:  * This file contains the generic db item class.
  5:  *
  6:  * @package Core
  7:  * @subpackage GenericDB
  8:  * @version SVN Revision $Rev:$
  9:  *
 10:  * @author Timo Hummel
 11:  * @author Murat Purc <murat@purc.de>
 12:  * @copyright four for business AG <www.4fb.de>
 13:  * @license http://www.contenido.org/license/LIZENZ.txt
 14:  * @link http://www.4fb.de
 15:  * @link http://www.contenido.org
 16:  */
 17: 
 18: defined('CON_FRAMEWORK') || die('Illegal call: Missing framework initialization - request aborted.');
 19: 
 20: /**
 21:  * Class Item
 22:  * Abstract class for database based items.
 23:  *
 24:  * @package Core
 25:  * @subpackage GenericDB
 26:  */
 27: abstract class Item extends cItemBaseAbstract {
 28: 
 29:     /**
 30:      * Storage of the source table to use for the user informations
 31:      *
 32:      * @var array
 33:      */
 34:     public $values;
 35: 
 36:     /**
 37:      * Storage of the fields which were modified, where the keys are the
 38:      * fieldnames and the values just simple bools.
 39:      *
 40:      * @var array
 41:      */
 42:     protected $modifiedValues;
 43: 
 44:     /**
 45:      * Stores the old primary key, just in case somebody wants to change it
 46:      *
 47:      * @var string
 48:      */
 49:     protected $oldPrimaryKey;
 50: 
 51:     /**
 52:      * List of funcion names of the filters used when data is stored to the db.
 53:      *
 54:      * @var array
 55:      */
 56:     protected $_arrInFilters = array(
 57:         'htmlspecialchars',
 58:         'addslashes'
 59:     );
 60: 
 61:     /**
 62:      * List of funcion names of the filters used when data is retrieved from the
 63:      * db
 64:      *
 65:      * @var array
 66:      */
 67:     protected $_arrOutFilters = array(
 68:         'stripslashes',
 69:         'htmldecode'
 70:     );
 71: 
 72:     /**
 73:      * Class name of meta object
 74:      *
 75:      * @var string
 76:      */
 77:     protected $_metaObject;
 78: 
 79:     /**
 80:      * Last executed SQL statement
 81:      *
 82:      * @var string
 83:      */
 84:     protected $_lastSQL;
 85: 
 86:     /**
 87:      * Constructor function
 88:      *
 89:      * @param string $sTable
 90:      *         The table to use as information source
 91:      * @param string $sPrimaryKey
 92:      *         The primary key to use
 93:      */
 94:     public function __construct($sTable, $sPrimaryKey) {
 95:         parent::__construct($sTable, $sPrimaryKey, get_parent_class($this));
 96:     }
 97: 
 98:     /**
 99:      * Resets class variables back to default
100:      * This is handy in case a new item is tried to be loaded into this class instance.
101:      */
102:     protected function _resetItem() {
103:         parent::_resetItem();
104: 
105:         // make sure not to reset filters because then default filters would always be used for loading
106:         $this->values = null;
107:         $this->modifiedValues = null;
108:         $this->_metaObject = null;
109:         $this->_lastSQL = null;
110:     }
111: 
112:     /**
113:      * Loads an item by colum/field from the database.
114:      *
115:      * @param string $sField
116:      *         Specifies the field
117:      * @param mixed $mValue
118:      *         Specifies the value
119:      * @param bool $bSafe [optional]
120:      *         Use inFilter or not
121:      * @throws cException
122:      *         if more than one item has been found matching the given arguments
123:      * @return bool
124:      *         True if the load was successful
125:      */
126:     public function loadBy($sField, $mValue, $bSafe = true) {
127:         // reset class variables back to default before loading
128:         $this->_resetItem();
129: 
130:         if ($bSafe) {
131:             $mValue = $this->_inFilter($mValue);
132:         }
133: 
134:         // check, if cache contains a matching entry
135:         $aRecordSet = NULL;
136:         if ($sField === $this->_primaryKeyName) {
137:             $aRecordSet = $this->_oCache->getItem($mValue);
138:         } else {
139:             $aRecordSet = $this->_oCache->getItemByProperty($sField, $mValue);
140:         }
141: 
142:         if ($aRecordSet) {
143:             // entry in cache found, load entry from cache
144:             $this->loadByRecordSet($aRecordSet);
145:             return true;
146:         }
147: 
148:         // SQL-Statement to select by field
149:         $sql = "SELECT * FROM `%s` WHERE %s = '%s'";
150:         $sql = $this->db->prepare($sql, $this->table, $sField, $mValue);
151: 
152:         // Query the database
153:         $this->db->query($sql);
154: 
155:         $this->_lastSQL = $sql;
156: 
157:         if ($this->db->numRows() > 1) {
158:             $msg = "Tried to load a single line with field $sField and value $mValue from " . $this->table . " but found more than one row";
159:             throw new cException($msg);
160:         }
161: 
162:         // Advance to the next record, return false if nothing found
163:         if (!$this->db->nextRecord()) {
164:             return false;
165:         }
166: 
167:         $this->loadByRecordSet($this->db->toArray());
168:         $this->_setLoaded(true);
169:         return true;
170:     }
171: 
172:     /**
173:      * Loads an item by colums/fields from the database.
174:      *
175:      * @param array $aAttributes
176:      *         associative array with field / value pairs
177:      * @param bool $bSafe [optional]
178:      *         Use inFilter or not
179:      * @throws cException
180:      *         if more than one item could be found matching the given arguments
181:      * @return bool
182:      *         True if the load was successful
183:      */
184:     public function loadByMany(array $aAttributes, $bSafe = true) {
185:         // reset class variables back to default before loading
186:         $this->_resetItem();
187: 
188:         if ($bSafe) {
189:             $aAttributes = $this->_inFilter($aAttributes);
190:         }
191: 
192:         // check, if cache contains a matching entry
193:         $aRecordSet = NULL;
194:         if (count($aAttributes) == 1 && isset($aAttributes[$this->getPrimaryKeyName()])) {
195:             $aRecordSet = $this->_oCache->getItem($aAttributes[$this->getPrimaryKeyName()]);
196:         } else {
197:             $aRecordSet = $this->_oCache->getItemByProperties($aAttributes);
198:         }
199: 
200:         if ($aRecordSet) {
201:             // entry in cache found, load entry from cache
202:             $this->loadByRecordSet($aRecordSet);
203:             return true;
204:         }
205: 
206:         // SQL-Statement to select by fields
207:         $sql = 'SELECT * FROM `:mytab` WHERE';
208:         foreach (array_keys($aAttributes) as $sKey) {
209:             // add quotes if key is a string
210:             if (is_string($sKey)) {
211:                 $sql .= " $sKey = ':$sKey' AND";
212:             } else {
213:                 $sql .= " $sKey = :$sKey AND";
214:             }
215:         }
216:         // strip the last " AND" token
217:         $sql = substr($sql, 0, strlen($sql) - 4);
218:         $sql = $this->db->prepare($sql, array_merge(array(
219:             'mytab' => $this->table
220:         ), $aAttributes));
221: 
222:         // Query the database
223:         $this->db->query($sql);
224: 
225:         $this->_lastSQL = $sql;
226: 
227:         if ($this->db->numRows() > 1) {
228:             $msg = 'Tried to load a single line with fields ' . print_r(array_keys($aAttributes), true) . ' and values ' . print_r(array_values($aAttributes), true) . ' from ' . $this->table . ' but found more than one row';
229:             throw new cException($msg);
230:         }
231: 
232:         // Advance to the next record, return false if nothing found
233:         if (!$this->db->nextRecord()) {
234:             return false;
235:         }
236: 
237:         $this->loadByRecordSet($this->db->toArray());
238:         $this->_setLoaded(true);
239:         return true;
240:     }
241: 
242:     /**
243:      * Loads an item by passed where clause from the database.
244:      * This function is expensive, since it executes allways a query to the
245:      * database
246:      * to retrieve the primary key, even if the record set is aleady cached.
247:      * NOTE: Passed value has to be escaped before. This will not be done by
248:      * this function.
249:      *
250:      * @param string $sWhere
251:      *         The where clause like 'idart = 123 AND idlang = 1'
252:      * @throws cException
253:      *         if more than one item could be found matching the given where clause
254:      * @return bool
255:      *         True if the load was successful
256:      */
257:     protected function _loadByWhereClause($sWhere) {
258:         // SQL-Statement to select by whee clause
259:         $sql = "SELECT %s AS pk FROM `%s` WHERE " . (string) $sWhere;
260:         $sql = $this->db->prepare($sql, $this->getPrimaryKeyName(), $this->table);
261: 
262:         // Query the database
263:         $this->db->query($sql);
264: 
265:         $this->_lastSQL = $sql;
266: 
267:         if ($this->db->numRows() > 1) {
268:             $msg = "Tried to load a single line with where clause '" . $sWhere . "' from " . $this->table . " but found more than one row";
269:             throw new cException($msg);
270:         }
271: 
272:         // Advance to the next record, return false if nothing found
273:         if (!$this->db->nextRecord()) {
274:             return false;
275:         }
276: 
277:         $id = $this->db->f('pk');
278:         return $this->loadByPrimaryKey($id);
279:     }
280: 
281:     /**
282:      * Loads an item by ID from the database.
283:      *
284:      * @param string $mValue
285:      *         Specifies the primary key value
286:      * @return bool
287:      *         True if the load was successful
288:      */
289:     public function loadByPrimaryKey($mValue) {
290:         $bSuccess = $this->loadBy($this->_primaryKeyName, $mValue);
291: 
292:         if ($bSuccess == true && method_exists($this, '_onLoad')) {
293:             $this->_onLoad();
294:         }
295: 
296:         return $bSuccess;
297:     }
298: 
299:     /**
300:      * Loads an item by it's recordset.
301:      *
302:      * @param array $aRecordSet
303:      *         The recordset of the item
304:      */
305:     public function loadByRecordSet(array $aRecordSet) {
306:         $this->values = $aRecordSet;
307:         $this->oldPrimaryKey = $this->values[$this->getPrimaryKeyName()];
308:         $this->_setLoaded(true);
309:         $this->_oCache->addItem($this->oldPrimaryKey, $this->values);
310: 
311:         if (method_exists($this, '_onLoad')) {
312:             $this->_onLoad();
313:         }
314:     }
315: 
316:     /**
317:      * Function which is called whenever an item is loaded.
318:      * Inherited classes should override this function if desired.
319:      */
320:     protected function _onLoad() {
321:     }
322: 
323:     /**
324:      * Gets the value of a specific field.
325:      *
326:      * @param string $sField
327:      *         Specifies the field to retrieve
328:      * @param bool $bSafe [optional]
329:      *         Flag to run defined outFilter on passed value
330:      * @return mixed
331:      *         Value of the field
332:      */
333:     public function getField($sField, $bSafe = true) {
334:         if (true !== $this->isLoaded()) {
335:             $this->lasterror = 'No item loaded';
336:             return false;
337:         }
338: 
339:         if (true == $bSafe) {
340:             return $this->outFilter($this->values[$sField]);
341:         } else {
342:             return $this->values[$sField];
343:         }
344:     }
345: 
346:     /**
347:      * Wrapper for getField (less to type).
348:      *
349:      * @param string $sField
350:      *         Specifies the field to retrieve
351:      * @param bool $bSafe [optional]
352:      *         Flag to run defined outFilter on passed value
353:      * @return mixed
354:      *         Value of the field
355:      */
356:     public function get($sField, $bSafe = true) {
357:         return $this->getField($sField, $bSafe);
358:     }
359: 
360:     /**
361:      * Sets the value of a specific field.
362:      *
363:      * @param string $sField
364:      *         Field name
365:      * @param mixed $mValue
366:      *         Value to set
367:      * @param bool $bSafe [optional]
368:      *         Flag to run defined inFilter on passed value
369:      * @return bool
370:      */
371:     public function setField($sField, $mValue, $bSafe = true) {
372:         if (true !== $this->isLoaded()) {
373:             $this->lasterror = 'No item loaded';
374:             return false;
375:         }
376: 
377:         if ($sField == $this->getPrimaryKeyName()) {
378:             $this->oldPrimaryKey = $this->values[$sField];
379:         }
380: 
381:         // apply filter on value
382:         if (true == $bSafe) {
383:             $mValue = $this->_inFilter($mValue);
384:         }
385: 
386:         // flag as modified
387:         if ($this->values[$sField] != $mValue || strlen($this->values[$sField]) != strlen($mValue)) {
388:             $this->modifiedValues[$sField] = true;
389:         }
390: 
391:         // set new value
392:         $this->values[$sField] = $mValue;
393: 
394:         return true;
395:     }
396: 
397:     /**
398:      * Shortcut to setField.
399:      *
400:      * @param string $sField
401:      *         Field name
402:      * @param mixed $mValue
403:      *         Value to set
404:      * @param bool $bSafe [optional]
405:      *         Flag to run defined inFilter on passed value
406:      * @return bool
407:      */
408:     public function set($sField, $mValue, $bSafe = true) {
409:         return $this->setField($sField, $mValue, $bSafe);
410:     }
411: 
412:     /**
413:      * Stores the loaded and modified item to the database.
414:      *
415:      * @return bool
416:      */
417:     public function store() {
418:         $this->_executeCallbacks(self::STORE_BEFORE, get_class($this), array(
419:             $this
420:         ));
421: 
422:         if (true !== $this->isLoaded()) {
423:             $this->lasterror = 'No item loaded';
424:             $this->_executeCallbacks(self::STORE_FAILURE, get_class($this), array(
425:                 $this
426:             ));
427:             return false;
428:         }
429: 
430:         $sql = 'UPDATE `' . $this->table . '` SET ';
431:         $first = true;
432: 
433:         if (!is_array($this->modifiedValues)) {
434:             $this->_executeCallbacks(self::STORE_SUCCESS, get_class($this), array(
435:                 $this
436:             ));
437:             return true;
438:         }
439: 
440:         foreach ($this->modifiedValues as $key => $bValue) {
441:             $value = $this->values[$key];
442:             if (is_string($value)) {
443:                 $value = $this->db->escape($value);
444:             }
445: 
446:             if ($first == true) {
447:                 $sql .= "`$key` = '" . $value . "'";
448:                 $first = false;
449:             } else {
450:                 $sql .= ", `$key` = '" . $value . "'";
451:             }
452:         }
453: 
454:         $sql .= " WHERE " . $this->getPrimaryKeyName() . " = '" . $this->oldPrimaryKey . "'";
455: 
456:         $this->db->query($sql);
457: 
458:         $this->_lastSQL = $sql;
459: 
460:         if ($this->db->affectedRows() > 0) {
461:             $this->_oCache->addItem($this->oldPrimaryKey, $this->values);
462:             $this->_executeCallbacks(self::STORE_SUCCESS, get_class($this), array(
463:                 $this
464:             ));
465:             return true;
466:         }
467: 
468:         $this->_executeCallbacks(self::STORE_FAILURE, get_class($this), array(
469:             $this
470:         ));
471:         return false;
472:     }
473: 
474:     /**
475:      * Returns current item data as an assoziative array.
476:      *
477:      * @return array|false
478:      */
479:     public function toArray() {
480:         if (true !== $this->isLoaded()) {
481:             $this->lasterror = 'No item loaded';
482:             return false;
483:         }
484: 
485:         $aReturn = array();
486:         foreach ($this->values as $field => $value) {
487:             $aReturn[$field] = $this->getField($field);
488:         }
489:         return $aReturn;
490:     }
491: 
492:     /**
493:      * Returns current item data as an object.
494:      *
495:      * @return stdClass|false
496:      */
497:     public function toObject() {
498:         $return = $this->toArray();
499:         return (false !== $return) ? (object) $return : $return;
500:     }
501: 
502:     /**
503:      * Sets a custom property.
504:      *
505:      * @param string $sType
506:      *         Specifies the type
507:      * @param string $sName
508:      *         Specifies the name
509:      * @param mixed $mValue
510:      *         Specifies the value
511:      * @param int $iClient [optional]
512:      *         Id of client to set property for
513:      * @return bool
514:      */
515:     public function setProperty($sType, $sName, $mValue, $iClient = 0) {
516:         // If this object wasn't loaded before, return false
517:         if (true !== $this->isLoaded()) {
518:             $this->lasterror = 'No item loaded';
519:             return false;
520:         }
521: 
522:         // Set the value
523:         $oProperties = $this->_getPropertiesCollectionInstance($iClient);
524:         $bResult = $oProperties->setValue($this->getPrimaryKeyName(), $this->get($this->getPrimaryKeyName()), $sType, $sName, $mValue);
525:         return $bResult;
526:     }
527: 
528:     /**
529:      * Returns a custom property.
530:      *
531:      * @param string $sType
532:      *         Specifies the type
533:      * @param string $sName
534:      *         Specifies the name
535:      * @param int $iClient [optional]
536:      *         Id of client to set property for
537:      * @return mixed
538:      *         Value of the given property or false
539:      */
540:     public function getProperty($sType, $sName, $iClient = 0) {
541:         // If this object wasn't loaded before, return false
542:         if (true !== $this->isLoaded()) {
543:             $this->lasterror = 'No item loaded';
544:             return false;
545:         }
546: 
547:         // Return the value
548:         $oProperties = $this->_getPropertiesCollectionInstance($iClient);
549:         $mValue = $oProperties->getValue($this->getPrimaryKeyName(), $this->get($this->getPrimaryKeyName()), $sType, $sName);
550:         return $mValue;
551:     }
552: 
553:     /**
554:      * Deletes a custom property.
555:      *
556:      * @param string $sType
557:      *         Specifies the type
558:      * @param string $sName
559:      *         Specifies the name
560:      * @param int $iClient [optional]
561:      *         Id of client to delete properties
562:      * @return bool
563:      */
564:     public function deleteProperty($sType, $sName, $iClient = 0) {
565:         // If this object wasn't loaded before, return false
566:         if (true !== $this->isLoaded()) {
567:             $this->lasterror = 'No item loaded';
568:             return false;
569:         }
570: 
571:         // Delete the value
572:         $oProperties = $this->_getPropertiesCollectionInstance($iClient);
573:         $bResult = $oProperties->deleteValue($this->getPrimaryKeyName(), $this->get($this->getPrimaryKeyName()), $sType, $sName);
574:         return $bResult;
575:     }
576: 
577:     /**
578:      * Deletes a custom property by its id.
579:      *
580:      * @param int $idprop
581:      *         Id of property
582:      * @return bool
583:      */
584:     public function deletePropertyById($idprop) {
585:         $oProperties = $this->_getPropertiesCollectionInstance();
586:         return $oProperties->delete($idprop);
587:     }
588: 
589:     ///**
590:     // * Deletes the current item
591:     // * Method doesn't work, remove in future versions.
592:     // */
593:     // function delete() {
594:     // $this->_collectionInstance->delete($item->get($this->getPrimaryKeyName()));
595:     // }
596: 
597:     /**
598:      * Define the filter functions used when data is being stored or retrieved
599:      * from the database.
600:      *
601:      * Examples:
602:      * <pre>
603:      * $obj->setFilters(array('addslashes'), array('stripslashes'));
604:      * $obj->setFilters(array('htmlencode', 'addslashes'), array('stripslashes',
605:      * 'htmlencode'));
606:      * </pre>
607:      *
608:      * @param array $aInFilters [optional]
609:      *         Array with function names
610:      * @param array $aOutFilters [optional]
611:      *         Array with function names
612:      */
613:     public function setFilters($aInFilters = array(), $aOutFilters = array()) {
614:         $this->_arrInFilters = $aInFilters;
615:         $this->_arrOutFilters = $aOutFilters;
616:     }
617: 
618:     /**
619:      * Filters the passed data using the functions defines in the _arrInFilters
620:      * array.
621:      *
622:      * @todo This method is used from public scope, but it should be protected
623:      * @see Item::setFilters()
624:      * @param mixed $mData
625:      *         Data to filter
626:      * @return mixed
627:      *         Filtered data
628:      */
629:     public function _inFilter($mData) {
630:         foreach ($this->_arrInFilters as $_function) {
631:             if (function_exists($_function)) {
632:                 if (is_array($mData)) {
633:                     foreach ($mData as $key => $value) {
634:                         $mData[$key] = $_function($value);
635:                     }
636:                 } else {
637:                     $mData = $_function($mData);
638:                 }
639:             }
640:         }
641:         return $mData;
642:     }
643: 
644:     /**
645:      * Filters the passed data using the functions defines in the _arrOutFilters
646:      * array.
647:      *
648:      * @see Item::setFilters()
649:      * @param mixed $mData
650:      *         Data to filter
651:      * @return mixed
652:      *         Filtered data
653:      */
654:     public function outFilter($mData) {
655:         foreach ($this->_arrOutFilters as $_function) {
656:             if (function_exists($_function)) {
657:                 if (is_array($mData)) {
658:                     foreach ($mData as $key => $value) {
659:                         $mData[$key] = $_function($value);
660:                     }
661:                 } else {
662:                     $mData = $_function($mData);
663:                 }
664:             }
665:         }
666:         return $mData;
667:     }
668: 
669:     /**
670:      * Set meta object class name.
671:      *
672:      * @param string $metaObject
673:      */
674:     protected function _setMetaObject($metaObject) {
675:         $this->_metaObject = $metaObject;
676:     }
677: 
678:     /**
679:      * Return meta object instance.
680:      * This object might be retrieved from a global cache ($_metaObjectCache).
681:      *
682:      * @return object
683:      */
684:     public function getMetaObject() {
685:         global $_metaObjectCache;
686: 
687:         if (!is_array($_metaObjectCache)) {
688:             $_metaObjectCache = array();
689:         }
690: 
691:         $sClassName = $this->_metaObject;
692:         $qclassname = strtolower($sClassName);
693: 
694:         if (array_key_exists($qclassname, $_metaObjectCache)) {
695:             if (is_object($_metaObjectCache[$qclassname])) {
696:                 if (strtolower(get_class($_metaObjectCache[$qclassname])) == $qclassname) {
697:                     $_metaObjectCache[$qclassname]->setPayloadObject($this);
698:                     return $_metaObjectCache[$qclassname];
699:                 }
700:             }
701:         }
702: 
703:         if (class_exists($sClassName)) {
704:             $_metaObjectCache[$qclassname] = new $sClassName($this);
705:             return $_metaObjectCache[$qclassname];
706:         }
707:     }
708: }
709: 
CMS CONTENIDO 4.9.8 API documentation generated by ApiGen 2.8.0