- <?php
- /**
- * Zend Framework (http://framework.zend.com/)
- *
- * @link http://github.com/zendframework/zf2 for the canonical source repository
- * @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com)
- * @license http://framework.zend.com/license/new-bsd New BSD License
- */
-
- namespace Zend\Ldap;
-
- use Iterator;
- use RecursiveIterator;
- use Zend\EventManager\EventManager;
-
- /**
- * Zend\Ldap\Node provides an object oriented view into a LDAP node.
- */
- class Node extends Node\AbstractNode implements Iterator, RecursiveIterator
- {
- /**
- * Holds the node's new Dn if node is renamed.
- *
- * @var Dn
- */
- protected $newDn;
-
- /**
- * Holds the node's original attributes (as loaded).
- *
- * @var array
- */
- protected $originalData;
-
- /**
- * This node will be added
- *
- * @var bool
- */
- protected $new;
-
- /**
- * This node will be deleted
- *
- * @var bool
- */
- protected $delete;
-
- /**
- * Holds the connection to the LDAP server if in connected mode.
- *
- * @var Ldap
- */
- protected $ldap;
-
- /**
- * Holds an array of the current node's children.
- *
- * @var Node[]
- */
- protected $children;
-
- /**
- * Controls iteration status
- *
- * @var bool
- */
- private $iteratorRewind = false;
-
- /** @var EventManager */
- protected $events;
-
- /**
- * Constructor.
- *
- * Constructor is protected to enforce the use of factory methods.
- *
- * @param Dn $dn
- * @param array $data
- * @param bool $fromDataSource
- * @param Ldap $ldap
- * @throws Exception\LdapException
- */
- protected function __construct(Dn $dn, array $data, $fromDataSource, Ldap $ldap = null)
- {
- parent::__construct($dn, $data, $fromDataSource);
- if ($ldap !== null) {
- $this->attachLdap($ldap);
- } else {
- $this->detachLdap();
- }
- }
-
- /**
- * Serialization callback
- *
- * Only Dn and attributes will be serialized.
- *
- * @return array
- */
- public function __sleep()
- {
- return array('dn', 'currentData', 'newDn', 'originalData',
- 'new', 'delete', 'children');
- }
-
- /**
- * Deserialization callback
- *
- * Enforces a detached node.
- */
- public function __wakeup()
- {
- $this->detachLdap();
- }
-
- /**
- * Gets the current LDAP connection.
- *
- * @return Ldap
- * @throws Exception\LdapException
- */
- public function getLdap()
- {
- if ($this->ldap === null) {
- throw new Exception\LdapException(null, 'No LDAP connection specified.',
- Exception\LdapException::LDAP_OTHER);
- }
-
- return $this->ldap;
- }
-
- /**
- * Attach node to an LDAP connection
- *
- * This is an offline method.
- *
- * @param Ldap $ldap
- * @return Node Provides a fluid interface
- * @throws Exception\LdapException
- */
- public function attachLdap(Ldap $ldap)
- {
- if (!Dn::isChildOf($this->_getDn(), $ldap->getBaseDn())) {
- throw new Exception\LdapException(null, 'LDAP connection is not responsible for given node.',
- Exception\LdapException::LDAP_OTHER);
- }
-
- if ($ldap !== $this->ldap) {
- $this->ldap = $ldap;
- if (is_array($this->children)) {
- foreach ($this->children as $child) {
- $child->attachLdap($ldap);
- }
- }
- }
-
- return $this;
- }
-
- /**
- * Detach node from LDAP connection
- *
- * This is an offline method.
- *
- * @return Node Provides a fluid interface
- */
- public function detachLdap()
- {
- $this->ldap = null;
- if (is_array($this->children)) {
- foreach ($this->children as $child) {
- $child->detachLdap();
- }
- }
-
- return $this;
- }
-
- /**
- * Checks if the current node is attached to a LDAP server.
- *
- * This is an offline method.
- *
- * @return bool
- */
- public function isAttached()
- {
- return ($this->ldap !== null);
- }
-
- /**
- * Trigger an event
- *
- * @param string $event Event name
- * @param array|\ArrayAccess $argv Array of arguments; typically, should be associative
- */
- protected function triggerEvent($event, $argv = array())
- {
- if (null === $this->events) {
- if (class_exists('\Zend\EventManager\EventManager')) {
- $this->events = new EventManager(__CLASS__);
- } else {
- return;
- }
- }
- $this->events->trigger($event, $this, $argv);
- }
-
- /**
- * @param array $data
- * @param bool $fromDataSource
- * @throws Exception\LdapException
- */
- protected function loadData(array $data, $fromDataSource)
- {
- parent::loadData($data, $fromDataSource);
- if ($fromDataSource === true) {
- $this->originalData = $data;
- } else {
- $this->originalData = array();
- }
- $this->children = null;
- $this->markAsNew(($fromDataSource === true) ? false : true);
- $this->markAsToBeDeleted(false);
- }
-
- /**
- * Factory method to create a new detached Zend\Ldap\Node for a given DN.
- *
- * @param string|array|Dn $dn
- * @param array $objectClass
- * @return Node
- * @throws Exception\LdapException
- */
- public static function create($dn, array $objectClass = array())
- {
- if (is_string($dn) || is_array($dn)) {
- $dn = Dn::factory($dn);
- } elseif ($dn instanceof Dn) {
- $dn = clone $dn;
- } else {
- throw new Exception\LdapException(null, '$dn is of a wrong data type.');
- }
- $new = new static($dn, array(), false, null);
- $new->ensureRdnAttributeValues();
- $new->setAttribute('objectClass', $objectClass);
-
- return $new;
- }
-
- /**
- * Factory method to create an attached Zend\Ldap\Node for a given DN.
- *
- * @param string|array|Dn $dn
- * @param Ldap $ldap
- * @return Node|null
- * @throws Exception\LdapException
- */
- public static function fromLdap($dn, Ldap $ldap)
- {
- if (is_string($dn) || is_array($dn)) {
- $dn = Dn::factory($dn);
- } elseif ($dn instanceof Dn) {
- $dn = clone $dn;
- } else {
- throw new Exception\LdapException(null, '$dn is of a wrong data type.');
- }
- $data = $ldap->getEntry($dn, array('*', '+'), true);
- if ($data === null) {
- return null;
- }
- $entry = new static($dn, $data, true, $ldap);
-
- return $entry;
- }
-
- /**
- * Factory method to create a detached Zend\Ldap\Node from array data.
- *
- * @param array $data
- * @param bool $fromDataSource
- * @return Node
- * @throws Exception\LdapException
- */
- public static function fromArray(array $data, $fromDataSource = false)
- {
- if (!array_key_exists('dn', $data)) {
- throw new Exception\LdapException(null, '\'dn\' key is missing in array.');
- }
- if (is_string($data['dn']) || is_array($data['dn'])) {
- $dn = Dn::factory($data['dn']);
- } elseif ($data['dn'] instanceof Dn) {
- $dn = clone $data['dn'];
- } else {
- throw new Exception\LdapException(null, '\'dn\' key is of a wrong data type.');
- }
- $fromDataSource = ($fromDataSource === true) ? true : false;
- $new = new static($dn, $data, $fromDataSource, null);
- $new->ensureRdnAttributeValues();
-
- return $new;
- }
-
- /**
- * Ensures that teh RDN attributes are correctly set.
- *
- * @param bool $overwrite True to overwrite the RDN attributes
- * @return void
- */
- protected function ensureRdnAttributeValues($overwrite = false)
- {
- foreach ($this->getRdnArray() as $key => $value) {
- if (!array_key_exists($key, $this->currentData) || $overwrite) {
- Attribute::setAttribute($this->currentData, $key, $value, false);
- } elseif (!in_array($value, $this->currentData[$key])) {
- Attribute::setAttribute($this->currentData, $key, $value, true);
- }
- }
- }
-
- /**
- * Marks this node as new.
- *
- * Node will be added (instead of updated) on calling update() if $new is true.
- *
- * @param bool $new
- */
- protected function markAsNew($new)
- {
- $this->new = ($new === false) ? false : true;
- }
-
- /**
- * Tells if the node is considered as new (not present on the server)
- *
- * Please note, that this doesn't tell you if the node is present on the server.
- * Use {@link exists()} to see if a node is already there.
- *
- * @return bool
- */
- public function isNew()
- {
- return $this->new;
- }
-
- /**
- * Marks this node as to be deleted.
- *
- * Node will be deleted on calling update() if $delete is true.
- *
- * @param bool $delete
- */
- protected function markAsToBeDeleted($delete)
- {
- $this->delete = ($delete === true) ? true : false;
- }
-
-
- /**
- * Is this node going to be deleted once update() is called?
- *
- * @return bool
- */
- public function willBeDeleted()
- {
- return $this->delete;
- }
-
- /**
- * Marks this node as to be deleted
- *
- * Node will be deleted on calling update() if $delete is true.
- *
- * @return Node Provides a fluid interface
- */
- public function delete()
- {
- $this->markAsToBeDeleted(true);
-
- return $this;
- }
-
- /**
- * Is this node going to be moved once update() is called?
- *
- * @return bool
- */
- public function willBeMoved()
- {
- if ($this->isNew() || $this->willBeDeleted()) {
- return false;
- } elseif ($this->newDn !== null) {
- return ($this->dn != $this->newDn);
- }
-
- return false;
- }
-
- /**
- * Sends all pending changes to the LDAP server
- *
- * @param Ldap $ldap
- * @return Node Provides a fluid interface
- * @throws Exception\LdapException
- * @trigger pre-delete
- * @trigger post-delete
- * @trigger pre-add
- * @trigger post-add
- * @trigger pre-rename
- * @trigger post-rename
- * @trigger pre-update
- * @trigger post-update
- */
- public function update(Ldap $ldap = null)
- {
- if ($ldap !== null) {
- $this->attachLdap($ldap);
- }
- $ldap = $this->getLdap();
- if (!($ldap instanceof Ldap)) {
- throw new Exception\LdapException(null, 'No LDAP connection available');
- }
-
- if ($this->willBeDeleted()) {
- if ($ldap->exists($this->dn)) {
- $this->triggerEvent('pre-delete');
- $ldap->delete($this->dn);
- $this->triggerEvent('post-delete');
- }
- return $this;
- }
-
- if ($this->isNew()) {
- $this->triggerEvent('pre-add');
- $data = $this->getData();
- $ldap->add($this->_getDn(), $data);
- $this->loadData($data, true);
- $this->triggerEvent('post-add');
-
- return $this;
- }
-
- $changedData = $this->getChangedData();
- if ($this->willBeMoved()) {
- $this->triggerEvent('pre-rename');
- $recursive = $this->hasChildren();
- $ldap->rename($this->dn, $this->newDn, $recursive, false);
- foreach ($this->newDn->getRdn() as $key => $value) {
- if (array_key_exists($key, $changedData)) {
- unset($changedData[$key]);
- }
- }
- $this->dn = $this->newDn;
- $this->newDn = null;
- $this->triggerEvent('post-rename');
- }
- if (count($changedData) > 0) {
- $this->triggerEvent('pre-update');
- $ldap->update($this->_getDn(), $changedData);
- $this->triggerEvent('post-update');
- }
- $this->originalData = $this->currentData;
-
- return $this;
- }
-
- /**
- * Gets the DN of the current node as a Zend\Ldap\Dn.
- *
- * This is an offline method.
- *
- * @return Dn
- */
- protected function _getDn()
- {
- return ($this->newDn === null) ? parent::_getDn() : $this->newDn;
- }
-
- /**
- * Gets the current DN of the current node as a Zend\Ldap\Dn.
- * The method returns a clone of the node's DN to prohibit modification.
- *
- * This is an offline method.
- *
- * @return Dn
- */
- public function getCurrentDn()
- {
- $dn = clone parent::_getDn();
-
- return $dn;
- }
-
- /**
- * Sets the new DN for this node
- *
- * This is an offline method.
- *
- * @param Dn|string|array $newDn
- * @throws Exception\LdapException
- * @return Node Provides a fluid interface
- */
- public function setDn($newDn)
- {
- if ($newDn instanceof Dn) {
- $this->newDn = clone $newDn;
- } else {
- $this->newDn = Dn::factory($newDn);
- }
- $this->ensureRdnAttributeValues(true);
-
- return $this;
- }
-
- /**
- * {@see setDn()}
- *
- * This is an offline method.
- *
- * @param Dn|string|array $newDn
- * @throws Exception\LdapException
- * @return Node Provides a fluid interface
- */
- public function move($newDn)
- {
- return $this->setDn($newDn);
- }
-
- /**
- * {@see setDn()}
- *
- * This is an offline method.
- *
- * @param Dn|string|array $newDn
- * @throws Exception\LdapException
- * @return Node Provides a fluid interface
- */
- public function rename($newDn)
- {
- return $this->setDn($newDn);
- }
-
- /**
- * Sets the objectClass.
- *
- * This is an offline method.
- *
- * @param array|string $value
- * @return Node Provides a fluid interface
- * @throws Exception\LdapException
- */
- public function setObjectClass($value)
- {
- $this->setAttribute('objectClass', $value);
-
- return $this;
- }
-
- /**
- * Appends to the objectClass.
- *
- * This is an offline method.
- *
- * @param array|string $value
- * @return Node Provides a fluid interface
- * @throws Exception\LdapException
- */
- public function appendObjectClass($value)
- {
- $this->appendToAttribute('objectClass', $value);
-
- return $this;
- }
-
- /**
- * Returns a LDIF representation of the current node
- *
- * @param array $options Additional options used during encoding
- * @return string
- */
- public function toLdif(array $options = array())
- {
- $attributes = array_merge(array('dn' => $this->getDnString()), $this->getData(false));
-
- return Ldif\Encoder::encode($attributes, $options);
- }
-
- /**
- * Gets changed node data.
- *
- * The array contains all changed attributes.
- * This format can be used in {@link Zend\Ldap\Ldap::add()} and {@link Zend\Ldap\Ldap::update()}.
- *
- * This is an offline method.
- *
- * @return array
- */
- public function getChangedData()
- {
- $changed = array();
- foreach ($this->currentData as $key => $value) {
- if (!array_key_exists($key, $this->originalData) && !empty($value)) {
- $changed[$key] = $value;
- } elseif ($this->originalData[$key] !== $this->currentData[$key]) {
- $changed[$key] = $value;
- }
- }
-
- return $changed;
- }
-
- /**
- * Returns all changes made.
- *
- * This is an offline method.
- *
- * @return array
- */
- public function getChanges()
- {
- $changes = array(
- 'add' => array(),
- 'delete' => array(),
- 'replace' => array());
- foreach ($this->currentData as $key => $value) {
- if (!array_key_exists($key, $this->originalData) && !empty($value)) {
- $changes['add'][$key] = $value;
- } elseif (count($this->originalData[$key]) === 0 && !empty($value)) {
- $changes['add'][$key] = $value;
- } elseif ($this->originalData[$key] !== $this->currentData[$key]) {
- if (empty($value)) {
- $changes['delete'][$key] = $value;
- } else {
- $changes['replace'][$key] = $value;
- }
- }
- }
-
- return $changes;
- }
-
- /**
- * Sets a LDAP attribute.
- *
- * This is an offline method.
- *
- * @param string $name
- * @param mixed $value
- * @return Node Provides a fluid interface
- * @throws Exception\LdapException
- */
- public function setAttribute($name, $value)
- {
- $this->_setAttribute($name, $value, false);
- return $this;
- }
-
- /**
- * Appends to a LDAP attribute.
- *
- * This is an offline method.
- *
- * @param string $name
- * @param mixed $value
- * @return Node Provides a fluid interface
- * @throws Exception\LdapException
- */
- public function appendToAttribute($name, $value)
- {
- $this->_setAttribute($name, $value, true);
-
- return $this;
- }
-
- /**
- * Checks if the attribute can be set and sets it accordingly.
- *
- * @param string $name
- * @param mixed $value
- * @param bool $append
- * @throws Exception\LdapException
- */
- protected function _setAttribute($name, $value, $append)
- {
- $this->assertChangeableAttribute($name);
- Attribute::setAttribute($this->currentData, $name, $value, $append);
- }
-
- /**
- * Sets a LDAP date/time attribute.
- *
- * This is an offline method.
- *
- * @param string $name
- * @param int|array $value
- * @param bool $utc
- * @return Node Provides a fluid interface
- * @throws Exception\LdapException
- */
- public function setDateTimeAttribute($name, $value, $utc = false)
- {
- $this->_setDateTimeAttribute($name, $value, $utc, false);
- return $this;
- }
-
- /**
- * Appends to a LDAP date/time attribute.
- *
- * This is an offline method.
- *
- * @param string $name
- * @param int|array $value
- * @param bool $utc
- * @return Node Provides a fluid interface
- * @throws Exception\LdapException
- */
- public function appendToDateTimeAttribute($name, $value, $utc = false)
- {
- $this->_setDateTimeAttribute($name, $value, $utc, true);
-
- return $this;
- }
-
- /**
- * Checks if the attribute can be set and sets it accordingly.
- *
- * @param string $name
- * @param int|array $value
- * @param bool $utc
- * @param bool $append
- * @throws Exception\LdapException
- */
- protected function _setDateTimeAttribute($name, $value, $utc, $append)
- {
- $this->assertChangeableAttribute($name);
- Attribute::setDateTimeAttribute($this->currentData, $name, $value, $utc, $append);
- }
-
- /**
- * Sets a LDAP password.
- *
- * @param string $password
- * @param string $hashType
- * @param string $attribName
- * @return Node Provides a fluid interface
- * @throws Exception\LdapException
- */
- public function setPasswordAttribute($password, $hashType = Attribute::PASSWORD_HASH_MD5,
- $attribName = 'userPassword'
- ) {
- $this->assertChangeableAttribute($attribName);
- Attribute::setPassword($this->currentData, $password, $hashType, $attribName);
-
- return $this;
- }
-
- /**
- * Deletes a LDAP attribute.
- *
- * This method deletes the attribute.
- *
- * This is an offline method.
- *
- * @param string $name
- * @return Node Provides a fluid interface
- * @throws Exception\LdapException
- */
- public function deleteAttribute($name)
- {
- if ($this->existsAttribute($name, true)) {
- $this->_setAttribute($name, null, false);
- }
-
- return $this;
- }
-
- /**
- * Removes duplicate values from a LDAP attribute
- *
- * @param string $attribName
- * @return void
- */
- public function removeDuplicatesFromAttribute($attribName)
- {
- Attribute::removeDuplicatesFromAttribute($this->currentData, $attribName);
- }
-
- /**
- * Remove given values from a LDAP attribute
- *
- * @param string $attribName
- * @param mixed|array $value
- * @return void
- */
- public function removeFromAttribute($attribName, $value)
- {
- Attribute::removeFromAttribute($this->currentData, $attribName, $value);
- }
-
- /**
- * @param string $name
- * @return bool
- * @throws Exception\LdapException
- */
- protected function assertChangeableAttribute($name)
- {
- $name = strtolower($name);
- $rdn = $this->getRdnArray(Dn::ATTR_CASEFOLD_LOWER);
- if ($name == 'dn') {
- throw new Exception\LdapException(null, 'DN cannot be changed.');
- } elseif (array_key_exists($name, $rdn)) {
- throw new Exception\LdapException(null, 'Cannot change attribute because it\'s part of the RDN');
- } elseif (in_array($name, static::$systemAttributes)) {
- throw new Exception\LdapException(null, 'Cannot change attribute because it\'s read-only');
- }
-
- return true;
- }
-
- /**
- * Sets a LDAP attribute.
- *
- * This is an offline method.
- *
- * @param string $name
- * @param $value
- */
- public function __set($name, $value)
- {
- $this->setAttribute($name, $value);
- }
-
- /**
- * Deletes a LDAP attribute.
- *
- * This method deletes the attribute.
- *
- * This is an offline method.
- *
- * @param string $name
- * @throws Exception\LdapException
- */
- public function __unset($name)
- {
- $this->deleteAttribute($name);
- }
-
- /**
- * Sets a LDAP attribute.
- * Implements ArrayAccess.
- *
- * This is an offline method.
- *
- * @param string $name
- * @param mixed $value
- * @throws Exception\LdapException
- */
- public function offsetSet($name, $value)
- {
- $this->setAttribute($name, $value);
- }
-
- /**
- * Deletes a LDAP attribute.
- * Implements ArrayAccess.
- *
- * This method deletes the attribute.
- *
- * This is an offline method.
- *
- * @param string $name
- * @throws Exception\LdapException
- */
- public function offsetUnset($name)
- {
- $this->deleteAttribute($name);
- }
-
- /**
- * Check if node exists on LDAP.
- *
- * This is an online method.
- *
- * @param Ldap $ldap
- * @return bool
- * @throws Exception\LdapException
- */
- public function exists(Ldap $ldap = null)
- {
- if ($ldap !== null) {
- $this->attachLdap($ldap);
- }
- $ldap = $this->getLdap();
-
- return $ldap->exists($this->_getDn());
- }
-
- /**
- * Reload node attributes from LDAP.
- *
- * This is an online method.
- *
- * @param Ldap $ldap
- * @return Node Provides a fluid interface
- * @throws Exception\LdapException
- */
- public function reload(Ldap $ldap = null)
- {
- if ($ldap !== null) {
- $this->attachLdap($ldap);
- }
- $ldap = $this->getLdap();
- parent::reload($ldap);
-
- return $this;
- }
-
- /**
- * Search current subtree with given options.
- *
- * This is an online method.
- *
- * @param string|Filter\AbstractFilter $filter
- * @param int $scope
- * @param string $sort
- * @return Node\Collection
- * @throws Exception\LdapException
- */
- public function searchSubtree($filter, $scope = Ldap::SEARCH_SCOPE_SUB, $sort = null)
- {
- return $this->getLdap()->search(
- $filter, $this->_getDn(), $scope, array('*', '+'), $sort,
- 'Zend\Ldap\Node\Collection'
- );
- }
-
- /**
- * Count items in current subtree found by given filter.
- *
- * This is an online method.
- *
- * @param string|Filter\AbstractFilter $filter
- * @param int $scope
- * @return int
- * @throws Exception\LdapException
- */
- public function countSubtree($filter, $scope = Ldap::SEARCH_SCOPE_SUB)
- {
- return $this->getLdap()->count($filter, $this->_getDn(), $scope);
- }
-
- /**
- * Count children of current node.
- *
- * This is an online method.
- *
- * @return int
- * @throws Exception\LdapException
- */
- public function countChildren()
- {
- return $this->countSubtree('(objectClass=*)', Ldap::SEARCH_SCOPE_ONE);
- }
-
- /**
- * Gets children of current node.
- *
- * This is an online method.
- *
- * @param string|Filter\AbstractFilter $filter
- * @param string $sort
- * @return Node\Collection
- * @throws Exception\LdapException
- */
- public function searchChildren($filter, $sort = null)
- {
- return $this->searchSubtree($filter, Ldap::SEARCH_SCOPE_ONE, $sort);
- }
-
- /**
- * Checks if current node has children.
- * Returns whether the current element has children.
- *
- * Can be used offline but returns false if children have not been retrieved yet.
- *
- * @return bool
- * @throws Exception\LdapException
- */
- public function hasChildren()
- {
- if (!is_array($this->children)) {
- if ($this->isAttached()) {
- return ($this->countChildren() > 0);
- }
- return false;
- }
- return (count($this->children) > 0);
- }
-
- /**
- * Returns the children for the current node.
- *
- * Can be used offline but returns an empty array if children have not been retrieved yet.
- *
- * @return Node\ChildrenIterator
- * @throws Exception\LdapException
- */
- public function getChildren()
- {
- if (!is_array($this->children)) {
- $this->children = array();
- if ($this->isAttached()) {
- $children = $this->searchChildren('(objectClass=*)', null);
- foreach ($children as $child) {
- $this->children[$child->getRdnString(Dn::ATTR_CASEFOLD_LOWER)] = $child;
- }
- }
- }
-
- return new Node\ChildrenIterator($this->children);
- }
-
- /**
- * Returns the parent of the current node.
- *
- * @param Ldap $ldap
- * @return Node
- * @throws Exception\LdapException
- */
- public function getParent(Ldap $ldap = null)
- {
- if ($ldap !== null) {
- $this->attachLdap($ldap);
- }
- $ldap = $this->getLdap();
- $parentDn = $this->_getDn()->getParentDn(1);
-
- return static::fromLdap($parentDn, $ldap);
- }
-
- /**
- * Return the current attribute.
- * Implements Iterator
- *
- * @return array
- */
- public function current()
- {
- return $this;
- }
-
- /**
- * Return the attribute name.
- * Implements Iterator
- *
- * @return string
- */
- public function key()
- {
- return $this->getRdnString();
- }
-
- /**
- * Move forward to next attribute.
- * Implements Iterator
- */
- public function next()
- {
- $this->iteratorRewind = false;
- }
-
- /**
- * Rewind the Iterator to the first attribute.
- * Implements Iterator
- */
- public function rewind()
- {
- $this->iteratorRewind = true;
- }
-
- /**
- * Check if there is a current attribute
- * after calls to rewind() or next().
- * Implements Iterator
- *
- * @return bool
- */
- public function valid()
- {
- return $this->iteratorRewind;
- }
- }