PageRenderTime 56ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/vendor/Eva/Mvc/Item/AbstractItem.php

https://github.com/zc1415926/eva-engine
PHP | 876 lines | 682 code | 94 blank | 100 comment | 59 complexity | 97e665777cc1fbbf7f3abbcfe6d49250 MD5 | raw file
  1. <?php
  2. /**
  3. * EvaEngine
  4. *
  5. * @link https://github.com/AlloVince/eva-engine
  6. * @copyright Copyright (c) 2012 AlloVince (http://avnpc.com/)
  7. * @license http://framework.zend.com/license/new-bsd New BSD License
  8. * @package Eva_Api.php
  9. * @author AlloVince
  10. */
  11. namespace Eva\Mvc\Item;
  12. use Eva\Mvc\Model\AbstractModel,
  13. Eva\Paginator\Paginator,
  14. Zend\Mvc\Exception,
  15. Zend\ServiceManager\ServiceLocatorAwareInterface,
  16. Zend\ServiceManager\ServiceLocatorInterface,
  17. Zend\Stdlib\Hydrator\ClassMethods;
  18. use ArrayObject;
  19. use ArrayIterator;
  20. use ArrayAccess;
  21. use Iterator;
  22. /**
  23. * Mvc Abstract Model for item / itemlist / paginator
  24. *
  25. * @category Eva
  26. * @package Eva_Mvc
  27. * @subpackage Model
  28. * @copyright Copyright (c) 2012 AlloVince (http://avnpc.com/)
  29. * @license http://framework.zend.com/license/new-bsd New BSD License
  30. */
  31. abstract class AbstractItem implements ArrayAccess, Iterator, ServiceLocatorAwareInterface
  32. {
  33. /**
  34. * @var null|int
  35. */
  36. protected $count = null;
  37. /**
  38. * @var Eva\Mvc\Model\AbstractModel
  39. */
  40. protected $model;
  41. /**
  42. * @var Iterator|IteratorAggregate
  43. */
  44. protected $dataSource = null;
  45. /**
  46. * @var DbTable | Webservice
  47. */
  48. protected $dataSourceType = 'DbTable';
  49. protected $dataSourceClass = '';
  50. protected $relationships = array();
  51. protected $inverseRelationships = array();
  52. protected $initialized = false;
  53. /**
  54. * @var null
  55. */
  56. protected $objectPrototype = null;
  57. /**
  58. * @var ServiceLocatorInterface
  59. */
  60. protected $serviceLocator;
  61. protected $paginator;
  62. /**
  63. * Set the service locator.
  64. *
  65. * @param ServiceLocatorInterface $serviceLocator
  66. * @return AbstractHelper
  67. */
  68. public function setServiceLocator(ServiceLocatorInterface $serviceLocator)
  69. {
  70. $this->serviceLocator = $serviceLocator;
  71. return $this;
  72. }
  73. /**
  74. * Get the service locator.
  75. *
  76. * @return \Zend\ServiceManager\ServiceLocatorInterface
  77. */
  78. public function getServiceLocator()
  79. {
  80. return $this->serviceLocator;
  81. }
  82. /**
  83. * Set the row object prototype
  84. *
  85. * @param object $objectPrototype
  86. * @return ResultSet
  87. */
  88. public function setObjectPrototype($objectPrototype)
  89. {
  90. if (!is_object($objectPrototype)) {
  91. throw new Exception\InvalidArgumentException(
  92. 'An object must be set as the object prototype, a ' . gettype($objectPrototype) . ' was provided.'
  93. );
  94. }
  95. $this->objectPrototype = $objectPrototype;
  96. return $this;
  97. }
  98. public function getModel()
  99. {
  100. return $this->model;
  101. }
  102. public function setModel($model)
  103. {
  104. if(!$model instanceof AbstractModel){
  105. throw new Exception\MissingLocatorException(printf('Model Service Locator not set by class %s',
  106. get_class($this)));
  107. }
  108. $this->model = $model;
  109. $this->initialize();
  110. return $this;
  111. }
  112. public function setPaginator($paginator)
  113. {
  114. $this->paginator = $paginator;
  115. }
  116. public function getPaginator(array $paginatorOptions = array())
  117. {
  118. $defaultPaginatorOptions = array(
  119. 'itemCountPerPage' => 10,
  120. 'pageRange' => 5,
  121. 'pageNumber' => 1,
  122. );
  123. $dataClass = $this->getDataClass();
  124. $count = $dataClass->getCount();
  125. if(!$count) {
  126. return $this->paginator = null;
  127. }
  128. $dbPaginatorOptions = $dataClass->getPaginatorOptions();
  129. $paginatorOptions = array_merge($defaultPaginatorOptions, $dbPaginatorOptions, $paginatorOptions);
  130. $count = (int) $count;
  131. $diConfig = array(
  132. 'instance' => array(
  133. 'Zend\Paginator\Adapter\DbSelect' => array(
  134. 'parameters' => array(
  135. 'rowCount' => $count,
  136. 'select' => $dataClass->getSelect(),
  137. 'adapterOrSqlObject' => $dataClass->getSql(),
  138. )
  139. ),
  140. 'Eva\Paginator\Paginator' => array(
  141. 'parameters' => array(
  142. 'rowCount' => $count,
  143. 'adapter' => 'Zend\Paginator\Adapter\DbSelect',
  144. ),
  145. ),
  146. )
  147. );
  148. foreach ($paginatorOptions as $key => $value) {
  149. if(false === in_array($key, array('itemCountPerPage', 'pageNumber', 'pageRange'))){
  150. continue;
  151. }
  152. $diConfig['instance']['Eva\Paginator\Paginator']['parameters'][$key] = $paginatorOptions[$key];
  153. }
  154. $di = new \Zend\Di\Di();
  155. $di->configure(new \Zend\Di\Config($diConfig));
  156. $paginator = $di->get('Eva\Paginator\Paginator');
  157. return $this->paginator = $paginator;
  158. }
  159. public function dbTable()
  160. {
  161. $tableClassName = $this->dataSourceClass;
  162. $serviceManager = $this->getServiceLocator();
  163. if($serviceManager->has($tableClassName)){
  164. return $serviceManager->get($tableClassName);
  165. }
  166. $serviceManager->setFactory($tableClassName, function(ServiceLocatorInterface $serviceLocator) use ($tableClassName){
  167. return new $tableClassName($serviceLocator->get('Zend\Db\Adapter\Adapter'));
  168. });
  169. return $serviceManager->get($tableClassName);
  170. }
  171. public function webService()
  172. {
  173. }
  174. public function getDataClass()
  175. {
  176. if($this->dataSourceType == 'WebService'){
  177. return $this->getWebService();
  178. }
  179. return $this->dbTable();
  180. }
  181. /**
  182. * Get the data source used to create the result set
  183. *
  184. * @return null|Iterator
  185. */
  186. public function getDataSource()
  187. {
  188. return $this->dataSource;
  189. }
  190. public function mergeDataSource(array $dataSource)
  191. {
  192. foreach($dataSource as $key => $value){
  193. if($value !== null){
  194. $this->dataSource[$key] = $value;
  195. }
  196. }
  197. return $this;
  198. }
  199. public function setDataSource($dataSource)
  200. {
  201. if (is_array($dataSource)) {
  202. // its safe to get numbers from an array
  203. $first = current($dataSource);
  204. reset($dataSource);
  205. $this->count = count($dataSource);
  206. $this->dataSource = new ArrayIterator($dataSource);
  207. } elseif ($dataSource instanceof IteratorAggregate) {
  208. $this->dataSource = $dataSource->getIterator();
  209. } elseif ($dataSource instanceof Iterator) {
  210. $this->dataSource = $dataSource;
  211. } else {
  212. throw new Exception\InvalidArgumentException('DataSource provided is not an array, nor does it implement Iterator or IteratorAggregate');
  213. }
  214. return $this;
  215. }
  216. public function hasLoadedRelationships()
  217. {
  218. $hasRelationships = false;
  219. foreach($this->relationships as $key => $relationship){
  220. if(isset($relationship['dataSource']) && $relationship['dataSource']){
  221. $hasRelationships = true;
  222. break;
  223. }
  224. }
  225. return $hasRelationships;
  226. }
  227. public function hasRelationship($key)
  228. {
  229. if(isset($this->relationships[$key]) && is_array($this->relationships[$key])){
  230. return true;
  231. }
  232. return false;
  233. }
  234. public function hasInverseRelationship($key)
  235. {
  236. if(isset($this->inverseRelationships[$key]) && is_array($this->inverseRelationships[$key])){
  237. return true;
  238. }
  239. return false;
  240. }
  241. public function getRelationship($key)
  242. {
  243. if(isset($this->relationships[$key]) && is_array($this->relationships[$key]) && $this->relationships[$key]){
  244. return $this->relationships[$key];
  245. }
  246. return array();
  247. }
  248. public function getInverseRelationship($key)
  249. {
  250. if(isset($this->inverseRelationships[$key]) && is_array($this->inverseRelationships[$key]) && $this->inverseRelationships[$key]){
  251. return $this->inverseRelationships[$key];
  252. }
  253. return array();
  254. }
  255. public function getRelationships()
  256. {
  257. return $this->relationships;
  258. }
  259. public function getLoadedRelationships()
  260. {
  261. $relationships = new ArrayObject();
  262. $model = $this->getModel();
  263. foreach($this->relationships as $key => $relationship){
  264. if(isset($relationship['dataSource']) && $relationship['dataSource'] && isset($relationship['targetEntity']) && $relationship['targetEntity']){
  265. $relItem = $this->join($key);
  266. if(isset($relationship['dataSource'][0])){
  267. //Join Many use Set because may be join items total number change
  268. $relItem->setDataSource($relationship['dataSource']);
  269. } else {
  270. //Join OneToOne use merge to passing referenced id
  271. $relItem->mergeDataSource($relationship['dataSource']);
  272. }
  273. $relationships[$key] = $relItem;
  274. }
  275. }
  276. return $relationships;
  277. }
  278. public function addRelationship($key, array $relationship)
  279. {
  280. if(isset($this->relationships[$key])){
  281. throw new Exception\InvalidArgumentException(sprintf('Relationship %s already exists in %, failed to add same one.', $key, get_class($this)));
  282. }
  283. $this->relationships[$key] = $relationship;
  284. return $this;
  285. }
  286. public function removeRelationship($key)
  287. {
  288. if(isset($this->relationships[$key])){
  289. unset($this->relationships[$key]);
  290. }
  291. return $this;
  292. }
  293. /**
  294. * Cast result set to array of arrays
  295. *
  296. * @return array
  297. * @throws Exception\RuntimeException if any row is not castable to an array
  298. */
  299. public function toArray(array $map = array())
  300. {
  301. if(0 === count($this->dataSource)){
  302. return array();
  303. }
  304. if(isset($this->dataSource[0])){
  305. foreach($this->dataSource as $key => $subDataSource){
  306. if(method_exists($subDataSource, 'toArray')){
  307. $this->dataSource[$key] = $subDataSource->toArray($map);
  308. }
  309. }
  310. return $this->singleToArray(array());
  311. } else {
  312. return $this->singleToArray($map);
  313. }
  314. }
  315. public function getArrayCopy()
  316. {
  317. return $this->toArray();
  318. }
  319. protected function singleToArray($map)
  320. {
  321. if($map){
  322. if(is_array(current($map))){
  323. $self = isset($map['self']) ? $map['self'] : array();
  324. $join = isset($map['join']) ? $map['join'] : array();
  325. $proxy = isset($map['proxy']) ? $map['proxy'] : array();
  326. $return = $this->dump($self, $join, $proxy);
  327. } else {
  328. $this->self($map);
  329. }
  330. }
  331. $return = $this->arrayAccessToArray($this->dataSource);
  332. return $return;
  333. }
  334. protected function arrayAccessToArray($arr)
  335. {
  336. $arr = (array) $arr;
  337. foreach($arr as $key => $value){
  338. if(is_object($value)){
  339. $value = (array) $value;
  340. }
  341. $arr[$key] = $value;
  342. }
  343. return $arr;
  344. }
  345. protected function dump(array $self, array $join, array $proxy)
  346. {
  347. $self = $this->self($self);
  348. //If item complete empty will not join
  349. if(0 === count($self->dataSource)){
  350. return $self;
  351. }
  352. foreach($proxy as $key => $map){
  353. list($moduleItemClass, $relationshipKey) = explode('::', $key);
  354. $modulesLoaded = $this->serviceLocator->get('modulemanager')->getLoadedModules();
  355. $module = array_shift(explode('\\', $moduleItemClass));
  356. if(!isset($modulesLoaded[$module])){
  357. continue;
  358. }
  359. $proxyItem = $this->model->getItem($moduleItemClass);
  360. if($proxyItem->hasInverseRelationship($relationshipKey)){
  361. $relationshipArray = $proxyItem->getInverseRelationship($relationshipKey);
  362. $this->addRelationship($relationshipKey, $relationshipArray);
  363. $join[$relationshipKey] = $map;
  364. }
  365. }
  366. foreach($join as $key => $map){
  367. if(!isset($this->relationships[$key])){
  368. continue;
  369. }
  370. $relationship = $this->relationships[$key];
  371. $joinedItem = $this->join($key);
  372. //Insert manytomany join middle item to parent level
  373. if(isset($relationship['inversedMappedBy'])){
  374. $mapKey = $relationship['inversedMappedBy'];
  375. $middleItems = array();
  376. foreach($joinedItem as $key => $item){
  377. $item = $item->$mapKey;
  378. if($item && method_exists($item, 'toArray')){
  379. $item = $item->toArray();
  380. $middleItems[$key] = $item;
  381. $joinedItem[$key][$mapKey] = $item;
  382. }
  383. }
  384. $self->$mapKey = $middleItems;
  385. }
  386. $joinedArray = $joinedItem->toArray($map);
  387. if(isset($relationship['mappedBy'])){
  388. $mapKey = $relationship['mappedBy'];
  389. $self->$mapKey = $joinedArray;
  390. } else {
  391. $self->$key = $joinedArray;
  392. }
  393. }
  394. return $self;
  395. }
  396. public function collections($params = null)
  397. {
  398. $dataClass = $this->getDataClass();
  399. if($params && method_exists($dataClass, 'setParameters')){
  400. if(is_array($params)){
  401. $params = new \Zend\Stdlib\Parameters($params);
  402. } elseif($params instanceof \Zend\Stdlib\Parameters){
  403. $params = $params;
  404. } else {
  405. throw new Exception\InvalidArgumentException(sprintf(
  406. 'Item collection require array or Zend\Stdlib\Parameters input'
  407. ));
  408. }
  409. $dataClass->setParameters($params);
  410. }
  411. $items = $dataClass->find('all');
  412. foreach($items as $key => $dataSource){
  413. $item = clone $this;
  414. $item->setDataSource((array) $dataSource);
  415. $this->dataSource[] = $item;
  416. }
  417. return $this;
  418. }
  419. public function self(array $map = array())
  420. {
  421. $columns = array();
  422. $functions = array();
  423. $selectAll = false;
  424. if(!$map){
  425. return $this;
  426. }
  427. if($map && in_array('*', $map)){
  428. $selectAll = true;
  429. if($map) {
  430. unset($map[array_search('*', $map)]);
  431. }
  432. }
  433. foreach($map as $key => $value){
  434. if(false === strrpos($value, '()')){
  435. $columns[] = $value;
  436. } else {
  437. $functions[] = str_replace('()', '', $value);
  438. }
  439. }
  440. $dataSource = array();
  441. if(true === $selectAll || $columns){
  442. $dataClass = $this->getDataClass();
  443. if(false === $selectAll){
  444. $dataClass->columns($columns);
  445. }
  446. $where = $this->getPrimaryArray();
  447. $dataSource = $dataClass->where($where)->find('one');
  448. //Not find in DB
  449. if(!$dataSource){
  450. $this->setDataSource(array());
  451. return $this;
  452. }
  453. }
  454. //Merge to original DataSource
  455. $originalDataSource = $this->getDataSource();
  456. if($dataSource){
  457. foreach($dataSource as $key => $value){
  458. if($value !== null){
  459. $originalDataSource[$key] = $value;
  460. }
  461. }
  462. }
  463. $dataSource = $originalDataSource;
  464. if(!$dataSource){
  465. $this->setDataSource(array());
  466. } else {
  467. $this->setDataSource((array) $dataSource);
  468. }
  469. //Auto complete
  470. if($functions){
  471. foreach($functions as $key => $function){
  472. if(true === method_exists($this, $function)){
  473. $this->$function();
  474. }
  475. }
  476. }
  477. return $this;
  478. }
  479. public function join($key)
  480. {
  481. $model = $this->getModel();
  482. if(!isset($this->relationships[$key]) || !$this->relationships[$key]){
  483. return new ArrayObject();
  484. }
  485. $relationship = $this->relationships[$key];
  486. //Important : here must use clone to create many entities
  487. $relItem = clone $model->getItem($relationship['targetEntity']);
  488. //Important : Joined item should have no dataSource
  489. $relItem->setDataSource(array());
  490. $joinFuncName = 'join' . ucfirst($key);
  491. if(method_exists($this, $joinFuncName)){
  492. $this->$joinFuncName($relItem);
  493. } else {
  494. $joinFuncName = 'join' . $relationship['relationship'];
  495. if(!method_exists($this, $joinFuncName)){
  496. throw new Exception\InvalidArgumentException(printf(
  497. 'Undefined relationship when join %s in class %s',
  498. $key,
  499. get_class($this)
  500. ));
  501. }
  502. $this->$joinFuncName($key, $relItem, $relationship);
  503. }
  504. return $relItem;
  505. }
  506. protected function joinOneToOne($key, $relItem, $relationship)
  507. {
  508. $joinColumn = $relationship['joinColumn'];
  509. $referencedColumn = $relationship['referencedColumn'];
  510. $relItem->$joinColumn = $this->$referencedColumn;
  511. //p(sprintf('%s joinOneToOne with %s : joinColumn %s => %s joined %s => %s', get_class($this), get_class($relItem), $joinColumn, $relItem->$joinColumn , $referencedColumn, $this->$referencedColumn));
  512. return $this;
  513. }
  514. protected function joinOneToMany($key, $relItem, $relationship)
  515. {
  516. $joinColumn = $relationship['joinColumn'];
  517. $referencedColumn = $relationship['referencedColumn'];
  518. $params = array(
  519. $joinColumn => $this->$referencedColumn,
  520. );
  521. if(isset($relationship['joinParameters']) && is_array($relationship['joinParameters'])){
  522. $params = array_merge($params, $relationship['joinParameters']);
  523. }
  524. //p(sprintf('joinOneToMany Joined Class %s : joinColumn %s => %s joined %s => %s', get_class($relItem), $joinColumn, $relItem->$joinColumn , $referencedColumn, $this->$referencedColumn));
  525. return $relItem->collections($params);
  526. }
  527. protected function joinManyToOne($key, $relItem, $relationship)
  528. {
  529. $joinColumn = $relationship['joinColumn'];
  530. $referencedColumn = $relationship['referencedColumn'];
  531. $relItem->$joinColumn = $this->$referencedColumn;
  532. //p(sprintf('joinManyToOne Joined Class %s : joinColumn %s => %s joined %s => %s', get_class($relItem), $joinColumn, $relItem->$joinColumn , $referencedColumn, $this->$referencedColumn));
  533. return $this;
  534. }
  535. protected function joinManyToMany($key, $relItem, $relationship)
  536. {
  537. $joinLeftColumn = $relationship['joinColumns']['joinColumn'];
  538. $referencedLeftColumn = $relationship['joinColumns']['referencedColumn'];
  539. $middleItem = clone $relItem->model->getItem($relationship['inversedBy']);
  540. $middleItem->setDataSource(array());
  541. $params = array(
  542. $joinLeftColumn => $this->$referencedLeftColumn
  543. );
  544. if(isset($relationship['joinColumns']['joinParameters']) && is_array($relationship['joinColumns']['joinParameters'])){
  545. $params = array_merge($params, $relationship['joinColumns']['joinParameters']);
  546. }
  547. $middleItems = $middleItem->collections($params);
  548. $joinRightColumn = $relationship['inverseJoinColumns']['joinColumn'];
  549. $referencedRightColumn = $relationship['inverseJoinColumns']['referencedColumn'];
  550. foreach($middleItems as $middleItem){
  551. $rightItem = clone $relItem;
  552. $rightItem->setDataSource(array());
  553. $rightItem->$referencedRightColumn = $middleItem->$joinRightColumn;
  554. $inversedMapKey = isset($relationship['inversedMappedBy']) ? $relationship['inversedMappedBy'] : get_class($middleItem);
  555. $rightItem->$inversedMapKey = $middleItem;
  556. $relItem[] = $rightItem;
  557. }
  558. //p(@sprintf('joinManyToMany Joined Class %s : joinColumn %s => %s joined %s => %s', get_class($relItem), $joinColumn, $relItem->$joinColumn , $referencedColumn, $this->$referencedColumn));
  559. return $relItem;
  560. }
  561. public function proxy($key)
  562. {
  563. list($moduleItemClass, $relationshipKey) = explode('::', $key);
  564. $modulesLoaded = $this->serviceLocator->get('modulemanager')->getLoadedModules();
  565. $module = array_shift(explode('\\', $moduleItemClass));
  566. if(!isset($modulesLoaded[$module])){
  567. return new ArrayObject();
  568. }
  569. $proxyItem = $this->model->getItem($moduleItemClass);
  570. if($proxyItem->hasInverseRelationship($relationshipKey)){
  571. $this->addRelationship($relationshipKey, $proxyItem->getInverseRelationship($relationshipKey));
  572. }
  573. return $this->join($relationshipKey);
  574. }
  575. public function create()
  576. {
  577. $dataClass = $this->getDataClass();
  578. $data = $this->toArray(
  579. isset($this->map['create']) ? $this->map['create'] : array()
  580. );
  581. $primaryKey = $dataClass->getPrimaryKey();
  582. if($dataClass->create($data)){
  583. $this->$primaryKey = $dataClass->getLastInsertValue();
  584. }
  585. return $this->$primaryKey;
  586. }
  587. public function save()
  588. {
  589. $dataClass = $this->getDataClass();
  590. $data = $this->toArray(
  591. isset($this->map['save']) ? $this->map['save'] : array()
  592. );
  593. $where = $this->getPrimaryArray();
  594. $dataClass->where($where)->save($data);
  595. return true;
  596. }
  597. public function remove()
  598. {
  599. $dataClass = $this->getDataClass();
  600. $where = $this->getPrimaryArray();
  601. $dataClass->where($where)->remove();
  602. return true;
  603. }
  604. protected function getPrimaryArray()
  605. {
  606. $dataClass = $this->getDataClass();
  607. $primaryKey = $dataClass->getPrimaryKey();
  608. if(is_string($primaryKey)){
  609. if(!$this->$primaryKey){
  610. throw new Exception\InvalidArgumentException(sprintf('Primary Key %s not set in item %s', $primaryKey, get_class($this)));
  611. }
  612. $where = array($primaryKey => $this->$primaryKey);
  613. } elseif(is_array($primaryKey)) {
  614. $where = array();
  615. foreach($primaryKey as $key){
  616. if(!$this->$key){
  617. throw new Exception\InvalidArgumentException(sprintf('Primary Key not set in item %s', get_class($this)));
  618. }
  619. $where[$key] = $this->$key;
  620. }
  621. } else {
  622. throw new Exception\InvalidArgumentException(sprintf('Primary Key not found or not correct in class %s', get_class($dataClass)));
  623. }
  624. return $where;
  625. }
  626. public function initialize()
  627. {
  628. if(true === $this->initialized){
  629. return $this;
  630. }
  631. $dataSource = $this->dataSource;
  632. //Auto set datasource from model if they are connected
  633. if(!$dataSource && $this->model && $this->model->getItemClass() == get_class($this)){
  634. $dataSource = $this->model->getDataSource();
  635. }
  636. if($dataSource){
  637. foreach($dataSource as $key => $data){
  638. if(is_array($data)){
  639. $this->relationships[$key]['dataSource'] = $data;
  640. unset($dataSource[$key]);
  641. }
  642. }
  643. }
  644. if(!$dataSource){
  645. $dataSource = array();
  646. }
  647. $this->setDataSource($dataSource);
  648. $this->initialized = true;
  649. return $this;
  650. }
  651. public function __get($name)
  652. {
  653. if(isset($this->dataSource[$name])){
  654. return $this->dataSource[$name];
  655. }
  656. return null;
  657. }
  658. public function __set($name, $value)
  659. {
  660. $this->dataSource[$name] = $value;
  661. return $this;
  662. }
  663. /**
  664. * Iterator: move pointer to next item
  665. *
  666. * @return void
  667. */
  668. public function next()
  669. {
  670. $this->dataSource->next();
  671. }
  672. /**
  673. * Iterator: retrieve current key
  674. *
  675. * @return mixed
  676. */
  677. public function key()
  678. {
  679. return $this->dataSource->key();
  680. }
  681. /**
  682. * Iterator: get current item
  683. *
  684. * @return array
  685. */
  686. public function current()
  687. {
  688. return $this->dataSource->current();
  689. }
  690. /**
  691. * Iterator: is pointer valid?
  692. *
  693. * @return bool
  694. */
  695. public function valid()
  696. {
  697. return $this->dataSource->valid();
  698. }
  699. /**
  700. * Iterator: rewind
  701. *
  702. * @return void
  703. */
  704. public function rewind()
  705. {
  706. $this->dataSource->rewind();
  707. // return void
  708. }
  709. /**
  710. * Countable: return count of rows
  711. *
  712. * @return int
  713. */
  714. public function count()
  715. {
  716. if ($this->count !== null) {
  717. return $this->count;
  718. }
  719. $this->count = count($this->dataSource);
  720. return $this->count;
  721. }
  722. public function offsetExists($index) {
  723. return isset($this->dataSource[$index]);
  724. }
  725. public function offsetGet($index) {
  726. if($this->offsetExists($index)) {
  727. return $this->dataSource[$index];
  728. }
  729. return false;
  730. }
  731. public function offsetSet($index, $value) {
  732. if($index) {
  733. $this->dataSource[$index] = $value;
  734. } else {
  735. $this->dataSource[] = $value;
  736. }
  737. return true;
  738. }
  739. public function offsetUnset($index) {
  740. unset($this->dataSource[$index]);
  741. return true;
  742. }
  743. }