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