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 collection 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 ItemCollection
  22:  * Abstract class for database based item collections.
  23:  *
  24:  * @package Core
  25:  * @subpackage GenericDB
  26:  */
  27: abstract class ItemCollection extends cItemBaseAbstract {
  28: 
  29:     /**
  30:      * Storage of all result items.
  31:      * Contains all result items.
  32:      *
  33:      * @var string
  34:      */
  35:     protected $objects;
  36: 
  37:     /**
  38:      * GenericDB driver object
  39:      *
  40:      * @var cGenericDbDriver
  41:      */
  42:     protected $_driver;
  43: 
  44:     /**
  45:      * List of instances of ItemCollection implementations
  46:      *
  47:      * @var array
  48:      */
  49:     protected $_collectionCache = array();
  50: 
  51:     /**
  52:      * Single item class
  53:      *
  54:      * @var string
  55:      */
  56:     protected $_itemClass;
  57: 
  58:     /**
  59:      * Iterator object for the next() method
  60:      *
  61:      * @var object
  62:      */
  63:     protected $_iteratorItem;
  64: 
  65:     /**
  66:      * Reverse join partners for this data object
  67:      *
  68:      * @var array
  69:      */
  70:     protected $_JoinPartners = array();
  71: 
  72:     /**
  73:      * Forward join partners for this data object
  74:      *
  75:      * @var array
  76:      */
  77:     protected $_forwardJoinPartners;
  78: 
  79:     /**
  80:      * Where restrictions for the query
  81:      *
  82:      * @var array
  83:      */
  84:     protected $_whereRestriction;
  85: 
  86:     /**
  87:      * Inner group conditions
  88:      *
  89:      * @var array
  90:      */
  91:     protected $_innerGroupConditions = array();
  92: 
  93:     /**
  94:      * Group conditions
  95:      *
  96:      * @var array
  97:      */
  98:     protected $_groupConditions;
  99: 
 100:     /**
 101:      * Result fields for the query
 102:      *
 103:      * @var array
 104:      */
 105:     protected $_resultFields = array();
 106: 
 107:     /**
 108:      * Encoding
 109:      *
 110:      * @var string
 111:      */
 112:     protected $_encoding;
 113: 
 114:     /**
 115:      * Item class instance
 116:      *
 117:      * @var object
 118:      */
 119:     protected $_itemClassInstance;
 120: 
 121:     /**
 122:      * Stores all operators which are supported by GenericDB
 123:      * Unsupported operators are passed trough as-is.
 124:      *
 125:      * @var array
 126:      */
 127:     protected $_aOperators;
 128: 
 129:     /**
 130:      * Flag to select all fields in a query.
 131:      * Reduces the number of queries send to the database.
 132:      *
 133:      * @var bool
 134:      */
 135:     protected $_bAllMode = false;
 136: 
 137:     /**
 138:      * Array with where conditions
 139:      *
 140:      * @var array
 141:      */
 142:     protected $_where;
 143: 
 144:     /**
 145:      * Order mode with direction
 146:      *
 147:      * @var string
 148:      */
 149:     protected $_order;
 150: 
 151:     /**
 152:      * Starting limit
 153:      *
 154:      * @var int
 155:      */
 156:     protected $_limitStart;
 157: 
 158:     /**
 159:      * Amount of items for limit
 160:      *
 161:      * @var int
 162:      */
 163:     protected $_limitCount;
 164: 
 165:     /**
 166:      * Last SQL statement
 167:      *
 168:      * @var string
 169:      */
 170:     protected $_lastSQL;
 171: 
 172:     /**
 173:      * Array with linked tables
 174:      *
 175:      * @var array
 176:      */
 177:     protected $_links;
 178: 
 179:     /**
 180:      * Constructor Function
 181:      *
 182:      * @param string $sTable
 183:      *         The table to use as information source
 184:      * @param string $sPrimaryKey
 185:      *         The primary key to use
 186:      */
 187:     public function __construct($sTable, $sPrimaryKey) {
 188:         parent::__construct($sTable, $sPrimaryKey, get_parent_class($this));
 189: 
 190:         $this->resetQuery();
 191: 
 192:         // Try to load driver
 193:         $this->_initializeDriver();
 194: 
 195:         // Try to find out the current encoding
 196:         if (isset($GLOBALS['lang']) && isset($GLOBALS['aLanguageEncodings'])) {
 197:             $this->setEncoding($GLOBALS['aLanguageEncodings'][$GLOBALS['lang']]);
 198:         }
 199: 
 200:         $this->_aOperators = array(
 201:             '=',
 202:             '!=',
 203:             '<>',
 204:             '<',
 205:             '>',
 206:             '<=',
 207:             '>=',
 208:             'LIKE',
 209:             'DIACRITICS'
 210:         );
 211:     }
 212: 
 213:     /**
 214:      * Defines the reverse links for this table.
 215:      *
 216:      * Important: The class specified by $sForeignCollectionClass needs to be a
 217:      * collection class and has to exist.
 218:      * Define all links in the constructor of your object.
 219:      *
 220:      * @param string $sForeignCollectionClass
 221:      *         Specifies the foreign class to use
 222:      * @throws cInvalidArgumentException
 223:      *         if the given foreign class can not be instantiated
 224:      */
 225:     protected function _setJoinPartner($sForeignCollectionClass) {
 226:         if (class_exists($sForeignCollectionClass)) {
 227:             // Add class
 228:             if (!in_array($sForeignCollectionClass, $this->_JoinPartners)) {
 229:                 $this->_JoinPartners[] = strtolower($sForeignCollectionClass);
 230:             }
 231:         } else {
 232:             $msg = "Could not instantiate class [$sForeignCollectionClass] for use " . "with _setJoinPartner in class " . get_class($this);
 233:             throw new cInvalidArgumentException($msg);
 234:         }
 235:     }
 236: 
 237:     /**
 238:      * Method to set the accompanying item object.
 239:      *
 240:      * @param string $sClassName
 241:      *         Specifies the classname of item
 242:      * @throws cInvalidArgumentException
 243:      *         if the given class can not be instantiated
 244:      */
 245:     protected function _setItemClass($sClassName) {
 246:         if (class_exists($sClassName)) {
 247:             $this->_itemClass = $sClassName;
 248:             $this->_itemClassInstance = new $sClassName();
 249: 
 250:             // Initialize driver in case the developer does a setItemClass-Call
 251:             // before calling the parent constructor
 252:             $this->_initializeDriver();
 253:             $this->_driver->setItemClassInstance($this->_itemClassInstance);
 254:         } else {
 255:             $msg = "Could not instantiate class [$sClassName] for use with " . "_setItemClass in class " . get_class($this);
 256:             throw new cInvalidArgumentException($msg);
 257:         }
 258:     }
 259: 
 260:     /**
 261:      * Initializes the driver to use with GenericDB.
 262:      *
 263:      * @param bool $bForceInit [optional]
 264:      *         If true, forces the driver to initialize, even if it already exists.
 265:      */
 266:     protected function _initializeDriver($bForceInit = false) {
 267:         if (!is_object($this->_driver) || $bForceInit == true) {
 268:             $this->_driver = new cGenericDbDriverMysql();
 269:         }
 270:     }
 271: 
 272:     /**
 273:      * Sets the encoding.
 274:      *
 275:      * @param string $sEncoding
 276:      */
 277:     public function setEncoding($sEncoding) {
 278:         $this->_encoding = $sEncoding;
 279:         $this->_driver->setEncoding($sEncoding);
 280:     }
 281: 
 282:     /**
 283:      * Sets the query to use foreign tables in the resultset
 284:      *
 285:      * @param string $sForeignClass
 286:      *         The class of foreign table to use
 287:      * @throws cInvalidArgumentException
 288:      *         if the given foreign class does not exist
 289:      */
 290:     public function link($sForeignClass) {
 291:         if (class_exists($sForeignClass)) {
 292:             $this->_links[$sForeignClass] = new $sForeignClass();
 293:         } else {
 294:             $msg = "Could not find class [$sForeignClass] for use with link in class " . get_class($this);
 295:             throw new cInvalidArgumentException($msg);
 296:         }
 297:     }
 298: 
 299:     /**
 300:      * Sets the limit for results
 301:      *
 302:      * @param int $iRowStart
 303:      * @param int $iRowCount
 304:      */
 305:     public function setLimit($iRowStart, $iRowCount) {
 306:         $this->_limitStart = $iRowStart;
 307:         $this->_limitCount = $iRowCount;
 308:     }
 309: 
 310:     /**
 311:      * Restricts a query with a where clause
 312:      *
 313:      * @param string $sField
 314:      * @param mixed $mRestriction
 315:      * @param string $sOperator [optional]
 316:      */
 317:     public function setWhere($sField, $mRestriction, $sOperator = '=') {
 318:         $sField = strtolower($sField);
 319:         $this->_where['global'][$sField]['operator'] = $sOperator;
 320:         $this->_where['global'][$sField]['restriction'] = $mRestriction;
 321:     }
 322: 
 323:     /**
 324:      * Removes a previous set where clause (@see ItemCollection::setWhere).
 325:      *
 326:      * @param string $sField
 327:      * @param mixed $mRestriction
 328:      * @param string $sOperator [optional]
 329:      */
 330:     public function deleteWhere($sField, $mRestriction, $sOperator = '=') {
 331:         $sField = strtolower($sField);
 332:         if (isset($this->_where['global'][$sField]) && is_array($this->_where['global'][$sField])) {
 333:             if ($this->_where['global'][$sField]['operator'] == $sOperator && $this->_where['global'][$sField]['restriction'] == $mRestriction) {
 334:                 unset($this->_where['global'][$sField]);
 335:             }
 336:         }
 337:     }
 338: 
 339:     /**
 340:      * Restricts a query with a where clause, groupable
 341:      *
 342:      * @param string $sGroup
 343:      * @param string $sField
 344:      * @param mixed $mRestriction
 345:      * @param string $sOperator [optional]
 346:      */
 347:     public function setWhereGroup($sGroup, $sField, $mRestriction, $sOperator = '=') {
 348:         $sField = strtolower($sField);
 349:         $this->_where['groups'][$sGroup][$sField]['operator'] = $sOperator;
 350:         $this->_where['groups'][$sGroup][$sField]['restriction'] = $mRestriction;
 351:     }
 352: 
 353:     /**
 354:      * Removes a previous set groupable where clause (@see
 355:      * ItemCollection::setWhereGroup).
 356:      *
 357:      * @param string $sGroup
 358:      * @param string $sField
 359:      * @param mixed $mRestriction
 360:      * @param string $sOperator [optional]
 361:      */
 362:     public function deleteWhereGroup($sGroup, $sField, $mRestriction, $sOperator = '=') {
 363:         $sField = strtolower($sField);
 364:         if (is_array($this->_where['groups'][$sGroup]) && isset($this->_where['groups'][$sGroup][$sField]) && is_array($this->_where['groups'][$sGroup][$sField])) {
 365:             if ($this->_where['groups'][$sGroup][$sField]['operator'] == $sOperator && $this->_where['groups'][$sGroup][$sField]['restriction'] == $mRestriction) {
 366:                 unset($this->_where['groups'][$sGroup][$sField]);
 367:             }
 368:         }
 369:     }
 370: 
 371:     /**
 372:      * Defines how relations in one group are linked each together
 373:      *
 374:      * @param string $sGroup
 375:      * @param string $sCondition [optional]
 376:      */
 377:     public function setInnerGroupCondition($sGroup, $sCondition = 'AND') {
 378:         $this->_innerGroupConditions[$sGroup] = $sCondition;
 379:     }
 380: 
 381:     /**
 382:      * Defines how groups are linked to each other
 383:      *
 384:      * @param string $sGroup1
 385:      * @param string $sGroup2
 386:      * @param string $sCondition [optional]
 387:      */
 388:     public function setGroupCondition($sGroup1, $sGroup2, $sCondition = 'AND') {
 389:         $this->_groupConditions[$sGroup1][$sGroup2] = $sCondition;
 390:     }
 391: 
 392:     /**
 393:      * Builds a where statement out of the setGroupWhere calls
 394:      *
 395:      * @return array
 396:      *         With all where statements
 397:      */
 398:     protected function _buildGroupWhereStatements() {
 399:         $aWheres = array();
 400:         $aGroupWhere = array();
 401: 
 402:         $mLastGroup = false;
 403:         $sGroupWhereStatement = '';
 404: 
 405:         // Find out if there are any defined groups
 406:         if (count($this->_where['groups']) > 0) {
 407:             // Step trough all groups
 408:             foreach ($this->_where['groups'] as $groupname => $group) {
 409:                 $aWheres = array();
 410: 
 411:                 // Fetch restriction, fields and operators and build single
 412:                 // group
 413:                 // where statements
 414:                 foreach ($group as $field => $item) {
 415:                     $aWheres[] = $this->_driver->buildOperator($field, $item['operator'], $item['restriction']);
 416:                 }
 417: 
 418:                 // Add completed substatements
 419:                 $sOperator = 'AND';
 420:                 if (isset($this->_innerGroupConditions[$groupname])) {
 421:                     $sOperator = $this->_innerGroupConditions[$groupname];
 422:                 }
 423: 
 424:                 $aGroupWhere[$groupname] = implode(' ' . $sOperator . ' ', $aWheres);
 425:             }
 426:         }
 427: 
 428:         // Combine groups
 429:         foreach ($aGroupWhere as $groupname => $group) {
 430:             if ($mLastGroup != false) {
 431:                 $sOperator = 'AND';
 432:                 // Check if there's a group condition
 433:                 if (isset($this->_groupConditions[$groupname])) {
 434:                     if (isset($this->_groupConditions[$groupname][$mLastGroup])) {
 435:                         $sOperator = $this->_groupConditions[$groupname][$mLastGroup];
 436:                     }
 437:                 }
 438: 
 439:                 // Reverse check
 440:                 if (isset($this->_groupConditions[$mLastGroup])) {
 441:                     if (isset($this->_groupConditions[$mLastGroup][$groupname])) {
 442:                         $sOperator = $this->_groupConditions[$mLastGroup][$groupname];
 443:                     }
 444:                 }
 445: 
 446:                 $sGroupWhereStatement .= ' ' . $sOperator . ' (' . $group . ')';
 447:             } else {
 448:                 $sGroupWhereStatement .= '(' . $group . ')';
 449:             }
 450: 
 451:             $mLastGroup = $groupname;
 452:         }
 453: 
 454:         return $sGroupWhereStatement;
 455:     }
 456: 
 457:     /**
 458:      * Builds a where statement out of the setWhere calls
 459:      *
 460:      * @return array
 461:      *         With all where statements
 462:      */
 463:     protected function _buildWhereStatements() {
 464:         $aWheres = array();
 465: 
 466:         // Build global where condition
 467:         foreach ($this->_where['global'] as $field => $item) {
 468:             $aWheres[] = $this->_driver->buildOperator($field, $item['operator'], $item['restriction']);
 469:         }
 470: 
 471:         return implode(' AND ', $aWheres);
 472:     }
 473: 
 474:     /**
 475:      * Fetches all tables which will be joined later on.
 476:      *
 477:      * The returned array has the following format:
 478:      * <pre>
 479:      * array(
 480:      * array(fields),
 481:      * array(tables),
 482:      * array(joins),
 483:      * array(wheres)
 484:      * );
 485:      * </pre>
 486:      *
 487:      * Notes:
 488:      * The table is the table name which needs to be added to the FROM clause
 489:      * The join statement which is inserted after the master table
 490:      * The where statement is combined with all other where statements
 491:      * The fields to select from
 492:      *
 493:      * @throws cException
 494:      *         if no join partner could be found
 495:      * @return array
 496:      *         Array structure, see above
 497:      */
 498:     protected function _fetchJoinTables() {
 499:         $aParameters = array();
 500:         $aFields = array();
 501:         $aTables = array();
 502:         $aJoins = array();
 503:         $aWheres = array();
 504: 
 505:         // Fetch linked tables
 506:         foreach ($this->_links as $link => $object) {
 507:             $matches = $this->_findReverseJoinPartner(strtolower(get_class($this)), $link);
 508:             if ($matches !== false) {
 509:                 if (isset($matches['desttable'])) {
 510:                     // Driver function: Build query parts
 511:                     $aParameters[] = $this->_driver->buildJoinQuery($matches['desttable'], strtolower($matches['destclass']), $matches['key'], strtolower($matches['sourceclass']), $matches['key']);
 512:                 } else {
 513:                     foreach ($matches as $match) {
 514:                         $aParameters[] = $this->_driver->buildJoinQuery($match['desttable'], strtolower($match['destclass']), $match['key'], strtolower($match['sourceclass']), $match['key']);
 515:                     }
 516:                 }
 517:             } else {
 518:                 throw new cUnexpectedValueException("The join partner '" . get_class($this) . "' is not registered and can not be used with link().");
 519:             }
 520:         }
 521: 
 522:         // Add this class
 523:         $aFields[] = strtolower(strtolower(get_class($this))) . '.' . $this->getPrimaryKeyName();
 524: 
 525:         // Make the parameters unique
 526:         foreach ($aParameters as $parameter) {
 527:             array_unshift($aFields, $parameter['field']);
 528:             array_unshift($aTables, $parameter['table']);
 529:             array_unshift($aJoins, $parameter['join']);
 530:             array_unshift($aWheres, $parameter['where']);
 531:         }
 532: 
 533:         $aFields = array_filter(array_unique($aFields));
 534:         $aTables = array_filter(array_unique($aTables));
 535:         $aJoins = array_filter(array_unique($aJoins));
 536:         $aWheres = array_filter(array_unique($aWheres));
 537: 
 538:         return array(
 539:             'fields' => $aFields,
 540:             'tables' => $aTables,
 541:             'joins' => $aJoins,
 542:             'wheres' => $aWheres
 543:         );
 544:     }
 545: 
 546:     /**
 547:      * Resolves links (class names of joined partners)
 548:      *
 549:      * @return array
 550:      */
 551:     protected function _resolveLinks() {
 552:         $aResolvedLinks = array();
 553:         $aResolvedLinks[] = strtolower(get_class($this));
 554: 
 555:         foreach ($this->_JoinPartners as $link) {
 556:             $class = new $link();
 557:             $aResolvedLinks = array_merge($class->_resolveLinks(), $aResolvedLinks);
 558:         }
 559:         return $aResolvedLinks;
 560:     }
 561: 
 562:     /**
 563:      * Resets the properties
 564:      */
 565:     public function resetQuery() {
 566:         $this->setLimit(0, 0);
 567:         $this->_forwardJoinPartners = array();
 568:         $this->_links = array();
 569:         $this->_where['global'] = array();
 570:         $this->_where['groups'] = array();
 571:         $this->_groupConditions = array();
 572:         $this->_resultFields = array();
 573:     }
 574: 
 575:     /**
 576:      * Builds and runs the query
 577:      *
 578:      * @throws cException
 579:      *         if no item class has been set
 580:      * @return bool
 581:      */
 582:     public function query() {
 583:         if (!isset($this->_itemClassInstance)) {
 584:             throw new cException('GenericDB can\'t use query() if no item class is set via setItemClass');
 585:         }
 586: 
 587:         $aGroupWhereStatements = $this->_buildGroupWhereStatements();
 588:         $sWhereStatements = $this->_buildWhereStatements();
 589:         $aParameters = $this->_fetchJoinTables();
 590: 
 591:         $aStatement = array(
 592:             'SELECT',
 593:             implode(', ', (array_merge($aParameters['fields'], $this->_resultFields))),
 594:             'FROM',
 595:             '`' . $this->table . '` AS ' . strtolower(get_class($this))
 596:         );
 597: 
 598:         if (count($aParameters['tables']) > 0) {
 599:             $aStatement[] = implode(', ', $aParameters['tables']);
 600:         }
 601: 
 602:         if (count($aParameters['joins']) > 0) {
 603:             $aStatement[] = implode(' ', $aParameters['joins']);
 604:         }
 605: 
 606:         $aWheres = array();
 607: 
 608:         if (count($aParameters['wheres']) > 0) {
 609:             $aWheres[] = implode(', ', $aParameters['wheres']);
 610:         }
 611: 
 612:         if ($aGroupWhereStatements != '') {
 613:             $aWheres[] = $aGroupWhereStatements;
 614:         }
 615: 
 616:         if ($sWhereStatements != '') {
 617:             $aWheres[] = $sWhereStatements;
 618:         }
 619: 
 620:         if (count($aWheres) > 0) {
 621:             $aStatement[] = 'WHERE ' . implode(' AND ', $aWheres);
 622:         }
 623: 
 624:         if ($this->_order != '') {
 625:             $aStatement[] = 'ORDER BY ' . $this->_order;
 626:         }
 627: 
 628:         if ($this->_limitStart > 0 || $this->_limitCount > 0) {
 629:             $iRowStart = intval($this->_limitStart);
 630:             $iRowCount = intval($this->_limitCount);
 631:             $aStatement[] = "LIMIT $iRowStart, $iRowCount";
 632:         }
 633: 
 634:         $sql = implode(' ', $aStatement);
 635: 
 636:         $result = $this->db->query($sql);
 637:         $this->_lastSQL = $sql;
 638:         // @todo disable all mode in this method for the moment. It has to be
 639:         // verified,
 640:         // if enabling will result in negative side effects.
 641:         $this->_bAllMode = false;
 642:         return ($result) ? true : false;
 643:     }
 644: 
 645:     /**
 646:      * Sets the result order part of the query
 647:      * (e.
 648:      * g. "fieldname", "fieldname DESC", "fieldname DESC, field2name ASC")
 649:      *
 650:      * @param string $order
 651:      */
 652:     public function setOrder($order) {
 653:         $this->_order = strtolower($order);
 654:     }
 655: 
 656:     /**
 657:      * Adds a result field
 658:      *
 659:      * @param string $sField
 660:      */
 661:     public function addResultField($sField) {
 662:         $sField = strtolower($sField);
 663:         if (!in_array($sField, $this->_resultFields)) {
 664:             $this->_resultFields[] = $sField;
 665:         }
 666:     }
 667: 
 668:     /**
 669:      * Removes existing result field
 670:      *
 671:      * @param string $sField
 672:      */
 673:     public function removeResultField($sField) {
 674:         $sField = strtolower($sField);
 675:         $key = array_search($sField, $this->_resultFields);
 676:         if ($key !== false) {
 677:             unset($this->_resultFields[$key]);
 678:         }
 679:     }
 680: 
 681:     /**
 682:      * Returns reverse join partner.
 683:      *
 684:      * @param string $sParentClass
 685:      * @param string $sClassName
 686:      * @return array|bool
 687:      */
 688:     protected function _findReverseJoinPartner($sParentClass, $sClassName) {
 689:         // Make the parameters lowercase, as get_class is buggy
 690:         $sClassName = strtolower($sClassName);
 691:         $sParentClass = strtolower($sParentClass);
 692: 
 693:         // Check if we found a direct link
 694:         if (in_array($sClassName, $this->_JoinPartners)) {
 695:             $obj = new $sClassName();
 696:             return array(
 697:                 'desttable' => $obj->table,
 698:                 'destclass' => $sClassName,
 699:                 'sourceclass' => $sParentClass,
 700:                 'key' => $obj->getPrimaryKeyName()
 701:             );
 702:         } else {
 703:             // Recurse all items
 704:             foreach ($this->_JoinPartners as $join => $tmpClassname) {
 705:                 $obj = new $tmpClassname();
 706:                 $status = $obj->_findReverseJoinPartner($tmpClassname, $sClassName);
 707: 
 708:                 if (is_array($status)) {
 709:                     $returns = array();
 710: 
 711:                     if (!isset($status['desttable'])) {
 712:                         foreach ($status as $subitem) {
 713:                             $returns[] = $subitem;
 714:                         }
 715:                     } else {
 716:                         $returns[] = $status;
 717:                     }
 718: 
 719:                     $returns[] = array(
 720:                         'desttable' => $obj->table,
 721:                         'destclass' => $tmpClassname,
 722:                         'sourceclass' => $sParentClass,
 723:                         'key' => $obj->getPrimaryKeyName()
 724:                     );
 725:                     return $returns;
 726:                 }
 727:             }
 728:         }
 729:         return false;
 730:     }
 731: 
 732:     /**
 733:      * Selects all entries from the database.
 734:      * Objects are loaded using their primary key.
 735:      *
 736:      * @param string $sWhere [optional]
 737:      *         Specifies the where clause.
 738:      * @param string $sGroupBy [optional]
 739:      *         Specifies the group by clause.
 740:      * @param string $sOrderBy [optional]
 741:      *         Specifies the order by clause.
 742:      * @param string $sLimit [optional]
 743:      *         Specifies the limit by clause.
 744:      * @return bool
 745:      *         True on success, otherwise false
 746:      */
 747:     public function select($sWhere = '', $sGroupBy = '', $sOrderBy = '', $sLimit = '') {
 748:         unset($this->objects);
 749: 
 750:         if ($sWhere == '') {
 751:             $sWhere = '';
 752:         } else {
 753:             $sWhere = ' WHERE ' . $sWhere;
 754:         }
 755: 
 756:         if ($sGroupBy != '') {
 757:             $sGroupBy = ' GROUP BY ' . $sGroupBy;
 758:         }
 759: 
 760:         if ($sOrderBy != '') {
 761:             $sOrderBy = ' ORDER BY ' . $sOrderBy;
 762:         }
 763: 
 764:         if ($sLimit != '') {
 765:             $sLimit = ' LIMIT ' . $sLimit;
 766:         }
 767: 
 768:         $sFields = ($this->_settings['select_all_mode']) ? '*' : $this->getPrimaryKeyName();
 769:         $sql = 'SELECT ' . $sFields . ' FROM `' . $this->table . '`' . $sWhere . $sGroupBy . $sOrderBy . $sLimit;
 770:         $this->db->query($sql);
 771:         $this->_lastSQL = $sql;
 772:         $this->_bAllMode = $this->_settings['select_all_mode'];
 773: 
 774:         if ($this->db->numRows() == 0) {
 775:             return false;
 776:         } else {
 777:             return true;
 778:         }
 779:     }
 780: 
 781:     /**
 782:      * Selects all entries from the database.
 783:      * Objects are loaded using their primary key.
 784:      *
 785:      * @param string $sDistinct [optional]
 786:      *         Specifies if distinct will be added to the SQL statement
 787:      *         ($sDistinct !== '' -> DISTINCT)
 788:      * @param string $sFrom [optional]
 789:      *         Specifies the additional from clause (e.g.
 790:      *         'con_news_groups AS groups, con_news_groupmembers AS groupmembers').
 791:      * @param string $sWhere [optional]
 792:      *         Specifies the where clause.
 793:      * @param string $sGroupBy [optional]
 794:      *         Specifies the group by clause.
 795:      * @param string $sOrderBy [optional]
 796:      *         Specifies the order by clause.
 797:      * @param string $sLimit [optional]
 798:      *         Specifies the limit by clause.
 799:      * @return bool
 800:      *         True on success, otherwise false
 801:      */
 802:     public function flexSelect($sDistinct = '', $sFrom = '', $sWhere = '', $sGroupBy = '', $sOrderBy = '', $sLimit = '') {
 803:         unset($this->objects);
 804: 
 805:         if ($sDistinct != '') {
 806:             $sDistinct = 'DISTINCT ';
 807:         }
 808: 
 809:         if ($sFrom != '') {
 810:             $sFrom = ', ' . $sFrom;
 811:         }
 812: 
 813:         if ($sWhere != '') {
 814:             $sWhere = ' WHERE ' . $sWhere;
 815:         }
 816: 
 817:         if ($sGroupBy != '') {
 818:             $sGroupBy = ' GROUP BY ' . $sGroupBy;
 819:         }
 820: 
 821:         if ($sOrderBy != '') {
 822:             $sOrderBy = ' ORDER BY ' . $sOrderBy;
 823:         }
 824: 
 825:         if ($sLimit != '') {
 826:             $sLimit = ' LIMIT ' . $sLimit;
 827:         }
 828: 
 829:         $sql = 'SELECT ' . $sDistinct . strtolower(get_class($this)) . '.' . $this->getPrimaryKeyName() . ' AS ' . $this->getPrimaryKeyName() . ' FROM `' . $this->table . '` AS ' . strtolower(get_class($this)) . $sFrom . $sWhere . $sGroupBy . $sOrderBy . $sLimit;
 830: 
 831:         $this->db->query($sql);
 832:         $this->_lastSQL = $sql;
 833:         // @todo disable all mode in this method
 834:         $this->_bAllMode = false;
 835: 
 836:         if ($this->db->numRows() == 0) {
 837:             return false;
 838:         } else {
 839:             return true;
 840:         }
 841:     }
 842: 
 843:     /**
 844:      * Checks if a specific entry exists.
 845:      *
 846:      * @param mixed $mId
 847:      *         The id to check for (could be numeric or string)
 848:      * @return bool
 849:      *         True if object exists, false if not
 850:      */
 851:     public function exists($mId) {
 852:         $oDb = $this->_getSecondDBInstance();
 853:         $sql = "SELECT `%s` FROM %s WHERE %s='%s'";
 854:         $oDb->query($sql, $this->getPrimaryKeyName(), $this->table, $this->getPrimaryKeyName(), $mId);
 855:         return ($oDb->nextRecord()) ? true : false;
 856:     }
 857: 
 858:     /**
 859:      * Advances to the next item in the database.
 860:      *
 861:      * @return Item|bool
 862:      *         next object, or false if no more objects
 863:      */
 864:     public function next() {
 865:         $ret = false;
 866:         while ($this->db->nextRecord()) {
 867:             if ($this->_bAllMode) {
 868:                 $aRs = $this->db->toArray(cDb::FETCH_BOTH);
 869:                 $ret = $this->loadItem($aRs);
 870:             } else {
 871:                 $ret = $this->loadItem($this->db->f($this->getPrimaryKeyName()));
 872:             }
 873: 
 874:             if ($ret->get($this->getPrimaryKeyName()) == "") {
 875:                 continue;
 876:             } else {
 877:                 break;
 878:             }
 879:         }
 880:         return $ret;
 881:     }
 882: 
 883:     /**
 884:      * Fetches the resultset related to current loaded primary key as an object.
 885:      *
 886:      * @param string $sClassName
 887:      * @return Item
 888:      */
 889:     public function fetchObject($sClassName) {
 890:         $sKey = strtolower($sClassName);
 891: 
 892:         if (!is_object($this->_collectionCache[$sKey])) {
 893:             $this->_collectionCache[$sKey] = new $sClassName();
 894:         }
 895:         /* @var $obj ItemCollection */
 896:         $obj = $this->_collectionCache[$sKey];
 897:         return $obj->loadItem($this->db->f($obj->getPrimaryKeyName()));
 898:     }
 899: 
 900:     /**
 901:      * Notes:
 902:      * If the array contains keys, the key will be used as alias for the field.
 903:      * Example: array('id' => 'idcat') will put 'idcat' into field 'id'
 904:      * $aObjects = array with the objects to fetch. Notes: If the array contains
 905:      * keys, the key will be used as alias for the object. If you specify more
 906:      * than one object with the same key, the array will be multi-dimensional.
 907:      *
 908:      * @param array $aFields [optional]
 909:      *         array with the fields to fetch
 910:      * @param array $aObjects [optional]
 911:      * @return array
 912:      */
 913:     public function fetchTable(array $aFields = array(), array $aObjects = array()) {
 914:         $row = 1;
 915:         $aTable = array();
 916: 
 917:         if ($this->count() > 0) {
 918: 
 919:             $this->db->seek(0);
 920: 
 921:             while ($this->db->nextRecord()) {
 922:                 foreach ($aFields as $alias => $field) {
 923:                     if ($alias != '') {
 924:                         $aTable[$row][$alias] = $this->db->f($field);
 925:                     } else {
 926:                         $aTable[$row][$field] = $this->db->f($field);
 927:                     }
 928:                 }
 929: 
 930:                 // Fetch objects
 931:                 foreach ($aObjects as $alias => $object) {
 932:                     if ($alias != '') {
 933:                         if (isset($aTable[$row][$alias])) {
 934:                             // Is set, check for array. If no array, create one
 935:                             if (is_array($aTable[$row][$alias])) {
 936:                                 $aTable[$row][$alias][] = $this->fetchObject($object);
 937:                             } else {
 938:                                 // $tmpObj = $aTable[$row][$alias];
 939:                                 $aTable[$row][$alias] = array();
 940:                                 $aTable[$row][$alias][] = $this->fetchObject($object);
 941:                             }
 942:                         } else {
 943:                             $aTable[$row][$alias] = $this->fetchObject($object);
 944:                         }
 945:                     } else {
 946:                         $aTable[$row][$object] = $this->fetchObject($object);
 947:                     }
 948:                 }
 949:                 $row++;
 950:             }
 951: 
 952:             $this->db->seek(0);
 953: 
 954:         }
 955: 
 956:         return $aTable;
 957:     }
 958: 
 959:     /**
 960:      * Returns an array of arrays
 961:      *
 962:      * @param array $aObjects
 963:      *         With the correct order of the objects
 964:      * @return array
 965:      *         Result
 966:      */
 967:     public function queryAndFetchStructured(array $aObjects) {
 968:         $aOrder = array();
 969:         $aFetchObjects = array();
 970:         $aResult = array();
 971: 
 972:         foreach ($aObjects as $object) {
 973:             $x = new $object();
 974:             $object = strtolower($object);
 975:             $aOrder[] = $object . '.' . $x->getPrimaryKeyName() . ' ASC';
 976:             $aFetchObjects[] = $x;
 977:         }
 978: 
 979:         $this->setOrder(implode(', ', $aOrder));
 980:         $this->query();
 981: 
 982:         $this->db->seek(0);
 983: 
 984:         while ($this->db->nextRecord()) {
 985:             $aResult = $this->_recursiveStructuredFetch($aFetchObjects, $aResult);
 986:         }
 987: 
 988:         return $aResult;
 989:     }
 990: 
 991:     /**
 992:      *
 993:      * @param array $aObjects
 994:      * @param array $aResult
 995:      * @return array
 996:      */
 997:     protected function _recursiveStructuredFetch(array $aObjects, array $aResult) {
 998:         $i = array_shift($aObjects);
 999: 
1000:         $value = $this->db->f($i->getPrimaryKeyName());
1001: 
1002:         if (!is_null($value)) {
1003:             $aResult[$value]['class'] = strtolower(get_class($i));
1004:             $aResult[$value]['object'] = $i->loadItem($value);
1005: 
1006:             if (count($aObjects) > 0) {
1007:                 $aResult[$value]['items'] = $this->_recursiveStructuredFetch($aObjects, $aResult[$value]['items']);
1008:             }
1009:         }
1010: 
1011:         return $aResult;
1012:     }
1013: 
1014:     /**
1015:      * Returns the amount of returned items
1016:      *
1017:      * @return int
1018:      *         Number of rows
1019:      */
1020:     public function count() {
1021:         return $this->db->numRows();
1022:     }
1023: 
1024:     /**
1025:      * Loads a single entry by it's id.
1026:      *
1027:      * @param string|int $id
1028:      *         The primary key of the item to load.
1029:      * @return Item
1030:      *         The loaded item
1031:      */
1032:     public function fetchById($id) {
1033:         if (is_numeric($id)) {
1034:             $id = (int) $id;
1035:         } elseif (is_string($id)) {
1036:             $id = $this->escape($id);
1037:         }
1038:         return $this->loadItem($id);
1039:     }
1040: 
1041:     /**
1042:      * Loads a single object from the database.
1043:      *
1044:      * @param mixed $mItem
1045:      *         The primary key of the item to load or a recordset with itemdata
1046:      *         (array) to inject to the item object.
1047:      * @throws cException
1048:      *         If item class is not set
1049:      * @return Item
1050:      *         The newly created object
1051:      */
1052:     public function loadItem($mItem) {
1053:         if (empty($this->_itemClass)) {
1054:             $sMsg = "ItemClass has to be set in the constructor of class " . get_class($this) . ")";
1055:             throw new cException($sMsg);
1056:         }
1057: 
1058:         if (!is_object($this->_iteratorItem)) {
1059:             $this->_iteratorItem = new $this->_itemClass();
1060:         }
1061:         $obj = clone $this->_iteratorItem;
1062: 
1063:         if (is_array($mItem)) {
1064:             $obj->loadByRecordSet($mItem);
1065:         } else {
1066:             $obj->loadByPrimaryKey($mItem);
1067:         }
1068: 
1069:         return $obj;
1070:     }
1071: 
1072:     /**
1073:      * Creates a new item in the table and loads it afterwards.
1074:      *
1075:      * @param string|array $data [optional]
1076:      *         optional parameter for direct input of primary key value
1077:      *         (string) or multiple column name - value pairs
1078:      * @return Item
1079:      *         The newly created object
1080:      */
1081:     public function createNewItem($data = NULL) {
1082:         $this->_executeCallbacks(self::CREATE_BEFORE, get_class($this), array());
1083: 
1084:         $db = $this->_getSecondDBInstance();
1085: 
1086:         $primaryKeyValue = NULL;
1087:         // prepare the primary key value and the data depending on the type of
1088:         // $data
1089:         if (is_array($data)) {
1090:             if (array_key_exists($this->getPrimaryKeyName(), $data)) {
1091:                 $primaryKeyValue = $data[$this->getPrimaryKeyName()];
1092:             }
1093:         } else {
1094:             // data is the primary key
1095:             $primaryKeyValue = $data;
1096:             $data = array(
1097:                 $this->getPrimaryKeyName() => $data
1098:             );
1099:         }
1100: 
1101:         // build the insert statement and execute it
1102:         $sql = $db->buildInsert($this->table, $data);
1103: 
1104:         $db->query($sql);
1105: 
1106:         if ($primaryKeyValue === NULL) {
1107:             $primaryKeyValue = $db->getLastInsertedId();
1108:         }
1109: 
1110:         if ($db->affectedRows() == 0) {
1111:             $this->_executeCallbacks(self::CREATE_FAILURE, $this->_itemClass, array());
1112:         } else {
1113:             $this->_executeCallbacks(self::CREATE_SUCCESS, $this->_itemClass, array(
1114:                 $primaryKeyValue
1115:             ));
1116:         }
1117: 
1118:         return $this->loadItem($primaryKeyValue);
1119:     }
1120: 
1121:     /**
1122:      * Inserts a new item entry by using a existing item entry.
1123:      *
1124:      * @param object $srcItem
1125:      *         Source Item instance to copy
1126:      * @param array $fieldsToOverwrite [optional]
1127:      *         Assoziative list of fields to overwrite.
1128:      * @throws cInvalidArgumentException
1129:      *         If Item class doesn't match the defined _itemClass property
1130:      *         or passed Item instance has no loaded recordset
1131:      * @return Item|NULL
1132:      */
1133:     public function copyItem($srcItem, array $fieldsToOverwrite = array()) {
1134:         if (get_class($srcItem) !== $this->_itemClass) {
1135:             throw new cInvalidArgumentException("Item class doesn't match");
1136:         } elseif (!$srcItem->isLoaded()) {
1137:             throw new cInvalidArgumentException("Item instance has no loaded recordset");
1138:         }
1139: 
1140:         $destItem = self::createNewItem();
1141:         if (!is_object($destItem)) {
1142:             return NULL;
1143:         }
1144: 
1145:         $rs = $srcItem->toArray();
1146: 
1147:         foreach ($rs as $field => $value) {
1148:             if (is_numeric($field)) {
1149:                 // Skip index based field
1150:                 continue;
1151:             } elseif ($field == $this->getPrimaryKeyName()) {
1152:                 // Skip primary key
1153:                 continue;
1154:             }
1155: 
1156:             if (isset($fieldsToOverwrite[$field])) {
1157:                 $value = $fieldsToOverwrite[$field];
1158:             }
1159: 
1160:             $destItem->set($field, $value);
1161:         }
1162: 
1163:         $destItem->store();
1164:         return $destItem;
1165:     }
1166: 
1167:     /**
1168:      * Returns all ids of recordsets in the table matching the rules in the
1169:      * passed where clause.
1170:      *
1171:      * @param string $sWhere
1172:      *         The where clause of the SQL statement
1173:      * @return array
1174:      *         List of ids
1175:      */
1176:     public function getIdsByWhereClause($sWhere) {
1177:         $oDb = $this->_getSecondDBInstance();
1178: 
1179:         $aIds = array();
1180: 
1181:         // Get all ids
1182:         $sql = 'SELECT ' . $this->getPrimaryKeyName() . ' AS pk FROM `' . $this->table . '` WHERE ' . $sWhere;
1183:         $oDb->query($sql);
1184:         while ($oDb->nextRecord()) {
1185:             $aIds[] = $oDb->f('pk');
1186:         }
1187: 
1188:         return $aIds;
1189:     }
1190: 
1191:     /**
1192:      * Returns all specified fields of recordsets in the table matching the
1193:      * rules in the passed where clause.
1194:      *
1195:      * @param array $aFields
1196:      *         List of fields to get
1197:      * @param string $sWhere
1198:      *         The where clause of the SQL statement
1199:      * @return array
1200:      *         List of entries with specified fields
1201:      */
1202:     public function getFieldsByWhereClause(array $aFields, $sWhere) {
1203:         $oDb = $this->_getSecondDBInstance();
1204: 
1205:         $aEntries = array();
1206: 
1207:         if (count($aFields) == 0) {
1208:             return $aEntries;
1209:         }
1210: 
1211:         // Delete multiple db entries at once
1212:         $aEscapedFields = array_map(array(
1213:             $oDb,
1214:             'escape'
1215:         ), $aFields);
1216: 
1217:         $fields = implode(', ', $aEscapedFields);
1218: 
1219:         // Get all fields
1220:         $sql = 'SELECT ' . $fields . ' FROM `' . $this->table . '` WHERE ' . $sWhere;
1221:         $oDb->query($sql);
1222:         while ($oDb->nextRecord()) {
1223:             $data = array();
1224:             foreach ($aFields as $field) {
1225:                 $data[$field] = $oDb->f($field);
1226:             }
1227:             $aEntries[] = $data;
1228:         }
1229: 
1230:         return $aEntries;
1231:     }
1232: 
1233:     /**
1234:      * Returns all ids of recordsets in the table.
1235:      *
1236:      * @return array
1237:      *         List of ids
1238:      */
1239:     public function getAllIds() {
1240:         $oDb = $this->_getSecondDBInstance();
1241: 
1242:         $aIds = array();
1243: 
1244:         // Get all ids
1245:         $sql = 'SELECT ' . $this->getPrimaryKeyName() . ' AS pk FROM `' . $this->table . '`';
1246:         $oDb->query($sql);
1247:         while ($oDb->nextRecord()) {
1248:             $aIds[] = $oDb->f('pk');
1249:         }
1250: 
1251:         return $aIds;
1252:     }
1253: 
1254:     /**
1255:      * Deletes an item in the table.
1256:      * Deletes also cached e entry and any existing properties.
1257:      *
1258:      * @param mixed $mId
1259:      *         Id of entry to delete
1260:      * @return bool
1261:      */
1262:     public function delete($mId) {
1263:         $result = $this->_delete($mId);
1264:         return $result;
1265:     }
1266: 
1267:     /**
1268:      * Deletes all found items in the table matching the rules in the passed
1269:      * where clause.
1270:      * Deletes also cached e entries and any existing properties.
1271:      *
1272:      * @param string $sWhere
1273:      *         The where clause of the SQL statement
1274:      * @return int
1275:      *         Number of deleted entries
1276:      */
1277:     public function deleteByWhereClause($sWhere) {
1278:         // Get all ids and delete related entries
1279:         $aIds = $this->getIdsByWhereClause($sWhere);
1280: 
1281:         if (!is_array($aIds) || 0 >= count($aIds)) {
1282:             return 0;
1283:         }
1284: 
1285:         $numDeleted = $this->_deleteMultiple($aIds);
1286:         return $numDeleted;
1287:     }
1288: 
1289:     /**
1290:      * Deletes all found items in the table matching the passed field and it's
1291:      * value.
1292:      * Deletes also cached e entries and any existing properties.
1293:      *
1294:      * @param string $sField
1295:      *         The field name
1296:      * @param mixed $mValue
1297:      *         The value of the field
1298:      * @return int
1299:      *         Number of deleted entries
1300:      */
1301:     public function deleteBy($sField, $mValue) {
1302:         $where = (is_string($mValue)) ? "`%s` = '%s'" : "`%s` = %d";
1303:         $where = $this->db->prepare($where, $sField, $mValue);
1304: 
1305:         return $this->deleteByWhereClause($where);
1306:     }
1307: 
1308:     // TODO
1309:     // /**
1310:     //  * Deletes all found items in the table matching the passed field and it's value.
1311:     //  * Deletes also cached e entries and any existing properties.
1312:     //  *
1313:     //  * @param mixed $mValue
1314:     //  *         The value of the field
1315:     //  * @return bool
1316:     //  */
1317:     // public function deleteByMany($values) {
1318:     // }
1319: 
1320:     /**
1321:      * Deletes an item in the table, deletes also existing cache entries and
1322:      * properties of the item.
1323:      *
1324:      * @param mixed $mId
1325:      *         Id of entry to delete
1326:      * @return bool
1327:      */
1328:     protected function _delete($mId) {
1329:         $this->_executeCallbacks(self::DELETE_BEFORE, $this->_itemClass, array(
1330:             $mId
1331:         ));
1332: 
1333:         $oDb = $this->_getSecondDBInstance();
1334: 
1335:         // delete db entry
1336:         $sql = "DELETE FROM `%s` WHERE %s = '%s'";
1337:         $oDb->query($sql, $this->table, $this->getPrimaryKeyName(), $mId);
1338:         $success = $oDb->affectedRows();
1339: 
1340:         // delete cache entry
1341:         $this->_oCache->removeItem($mId);
1342: 
1343:         // delete the property values
1344:         $oProperties = $this->_getPropertiesCollectionInstance();
1345:         $oProperties->deleteProperties($this->getPrimaryKeyName(), $mId);
1346: 
1347:         if ($success == 0) {
1348:             $this->_executeCallbacks(self::DELETE_FAILURE, $this->_itemClass, array(
1349:                 $mId
1350:             ));
1351:             return false;
1352:         } else {
1353:             $this->_executeCallbacks(self::DELETE_SUCCESS, $this->_itemClass, array(
1354:                 $mId
1355:             ));
1356:             return true;
1357:         }
1358:     }
1359: 
1360:     /**
1361:      * Deletes all items in the table, deletes also existing cache entries and
1362:      * properties of the item.
1363:      *
1364:      * @param array $aIds
1365:      *         Id of entries to delete (has to be called w/ an array!)
1366:      * @return int
1367:      *         Number of affected records
1368:      */
1369:     protected function _deleteMultiple(array $aIds) {
1370:         foreach ($aIds as $mId) {
1371:             $this->_executeCallbacks(self::DELETE_BEFORE, $this->_itemClass, array(
1372:                 $mId
1373:             ));
1374:         }
1375: 
1376:         $oDb = $this->_getSecondDBInstance();
1377: 
1378:         // Delete multiple db entries at once
1379:         $aEscapedIds = array_map(array(
1380:             $oDb,
1381:             'escape'
1382:         ), $aIds);
1383:         $in = "'" . implode("', '", $aEscapedIds) . "'";
1384:         $sql = "DELETE FROM `%s` WHERE %s IN (" . $in . ")";
1385:         $oDb->query($sql, $this->table, $this->getPrimaryKeyName());
1386:         $numAffected = $oDb->affectedRows();
1387: 
1388:         // Delete cache entries
1389:         $this->_oCache->removeItems($aIds);
1390: 
1391:         // Delete the property values
1392:         $oProperties = $this->_getPropertiesCollectionInstance();
1393:         $oProperties->deletePropertiesMultiple($this->getPrimaryKeyName(), $aIds);
1394: 
1395:         // NOTE: Deleteing multiple entries at once has a drawback. There is no
1396:         // way to detect faulty ids, if one or more entries couldn't deleted.
1397:         if ($numAffected == 0) {
1398:             foreach ($aIds as $mId) {
1399:                 $this->_executeCallbacks(self::DELETE_FAILURE, $this->_itemClass, array(
1400:                     $mId
1401:                 ));
1402:             }
1403:         } else {
1404:             foreach ($aIds as $mId) {
1405:                 $this->_executeCallbacks(self::DELETE_SUCCESS, $this->_itemClass, array(
1406:                     $mId
1407:                 ));
1408:             }
1409:         }
1410:         return $numAffected;
1411:     }
1412: 
1413:     /**
1414:      * Fetches an array of fields from the database.
1415:      *
1416:      * Example:
1417:      * $i = $object->fetchArray('idartlang', array('idlang', 'name'));
1418:      *
1419:      * could result in:
1420:      * $i[5] = array('idlang' => 5, 'name' => 'My Article');
1421:      *
1422:      * Important: If you don't pass an array for fields, the function
1423:      * doesn't create an array.
1424:      *
1425:      * @param string $sKey
1426:      *         Name of the field to use for the key
1427:      * @param mixed $mFields
1428:      *         String or array
1429:      * @return array
1430:      *         Resulting array
1431:      */
1432:     public function fetchArray($sKey, $mFields) {
1433:         $aResult = array();
1434: 
1435:         while (($item = $this->next()) !== false) {
1436:             if (is_array($mFields)) {
1437:                 foreach ($mFields as $value) {
1438:                     $aResult[$item->get($sKey)][$value] = $item->get($value);
1439:                 }
1440:             } else {
1441:                 $aResult[$item->get($sKey)] = $item->get($mFields);
1442:             }
1443:         }
1444: 
1445:         return $aResult;
1446:     }
1447: }
1448: 
CMS CONTENIDO 4.9.8 API documentation generated by ApiGen 2.8.0