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