- <?php
- namespace Jackalope;
- use Iterator;
- use ArrayIterator;
- use IteratorAggregate;
- use PHPCR\UnsupportedRepositoryOperationException;
- use PHPCR\ItemNotFoundException;
- use PHPCR\NamespaceRegistryInterface;
- use PHPCR\NamespaceException;
- use Jackalope\Transport\TransportInterface;
- use Jackalope\Transport\WritingInterface;
- /**
-  * {@inheritDoc}
-  *
-  * @license http://www.apache.org/licenses Apache License Version 2.0, January 2004
-  * @license http://opensource.org/licenses/MIT MIT License
-  */
- class NamespaceRegistry implements IteratorAggregate, NamespaceRegistryInterface
- {
-     /**
-      * Instance of an implementation of the TransportInterface
-      * @var WritingInterface
-      */
-     protected $transport;
-     /**
-      * The factory to instantiate objects
-      * @var FactoryInterface
-      */
-     protected $factory;
-     /**
-      * List of predefined namespaces.
-      *
-      * @var array
-      */
-     protected $defaultNamespaces = [
-         self::PREFIX_JCR   => self::NAMESPACE_JCR,
-         self::PREFIX_SV    => self::NAMESPACE_SV,
-         self::PREFIX_NT    => self::NAMESPACE_NT,
-         self::PREFIX_MIX   => self::NAMESPACE_MIX,
-         self::PREFIX_XML   => self::NAMESPACE_XML,
-         self::PREFIX_EMPTY => self::NAMESPACE_EMPTY,
-     ];
-     /**
-      * Set of namespaces registered by the user.
-      *
-      * @var array
-      */
-     protected $userNamespaces = null;
-     /**
-      * Initializes the created object.
-      *
-      * @param FactoryInterface   $factory
-      * @param TransportInterface $transport
-      *
-      * @throws ItemNotFoundException If property not found
-      */
-     public function __construct(FactoryInterface $factory, TransportInterface $transport)
-     {
-         $this->factory = $factory;
-         $this->transport = $transport;
-     }
-     /**
-      * Makes sure the namespaces are available.
-      *
-      * We are lazy and only load the namespaces when they are needed for the
-      * first time. This method has to be called by all methods that need to
-      * do something with user defined namespaces.
-      */
-     protected function lazyLoadNamespaces()
-     {
-         if ($this->userNamespaces === null) {
-             $namespaces = $this->transport->getNamespaces();
-             $this->userNamespaces = [];
-             foreach ($namespaces as $prefix => $uri) {
-                 if (! array_key_exists($prefix, $this->defaultNamespaces)) {
-                     $this->userNamespaces[$prefix] = $uri;
-                 }
-             }
-         }
-     }
-     /**
-      * {@inheritDoc}
-      *
-      * @api
-      */
-     public function registerNamespace($prefix, $uri)
-     {
-         if (! $this->transport instanceof WritingInterface) {
-             throw new UnsupportedRepositoryOperationException('Transport does not support writing');
-         }
-         // prevent default namespace prefixes to be overridden.
-         $this->checkPrefix($prefix);
-         // prevent default namespace uris to be overridden
-         if (false !== array_search($uri, $this->defaultNamespaces)) {
-             throw new NamespaceException("Can not change default namespace $prefix = $uri");
-         }
-         $this->lazyLoadNamespaces();
-         //first try putting the stuff in backend, and only afterwards update local info
-         // this has no impact on running sessions, go directly to storage
-         $this->transport->registerNamespace($prefix, $uri);
-         // update local info
-         if (false !== $oldpref = array_search($uri, $this->userNamespaces)) {
-             // the backend takes care of storing this, but we have to update frontend info
-             unset($this->userNamespaces[$oldpref]);
-         }
-         $this->userNamespaces[$prefix] = $uri;
-     }
-     /**
-      * {@inheritDoc}
-      *
-      * @api
-      */
-     public function unregisterNamespaceByURI($uri)
-     {
-         if (! $this->transport instanceof WritingInterface) {
-             throw new UnsupportedRepositoryOperationException('Transport does not support writing');
-         }
-         $this->lazyLoadNamespaces();
-         $prefix = array_search($uri, $this->userNamespaces);
-         if ($prefix === false) {
-             throw new NamespaceException("Namespace '$uri' is not currently registered");
-         }
-         // now check whether this is a prefix out of the defaultNamespaces in checkPrefix
-         $this->checkPrefix($prefix);
-         $this->transport->unregisterNamespace($prefix);
-         //remove the prefix from the local userNamespaces array
-         unset($this->userNamespaces[$prefix]);
-     }
-     /**
-      * {@inheritDoc}
-      *
-      * @api
-      */
-     public function getPrefixes()
-     {
-         $this->lazyLoadNamespaces();
-         return array_merge(
-             array_keys($this->defaultNamespaces),
-             array_keys($this->userNamespaces)
-         );
-     }
-     /**
-      * {@inheritDoc}
-      *
-      * @api
-      */
-     public function getURIs()
-     {
-         $this->lazyLoadNamespaces();
-         return array_merge(
-             array_values($this->defaultNamespaces),
-             array_values($this->userNamespaces)
-         );
-     }
-     /**
-      * {@inheritDoc}
-      *
-      * @api
-      */
-     public function getURI($prefix)
-     {
-         $this->lazyLoadNamespaces();
-         if (isset($this->defaultNamespaces[$prefix])) {
-             return $this->defaultNamespaces[$prefix];
-         } elseif (isset($this->userNamespaces[$prefix])) {
-             $this->lazyLoadNamespaces();
-             return $this->userNamespaces[$prefix];
-         }
-         throw new NamespaceException("Mapping for '$prefix' is not defined");
-     }
-     /**
-      * {@inheritDoc}
-      *
-      * @api
-      */
-     public function getPrefix($uri)
-     {
-         $prefix = array_search($uri, $this->defaultNamespaces);
-         if ($prefix === false) {
-             $this->lazyLoadNamespaces();
-             $prefix = array_search($uri, $this->userNamespaces);
-             if ($prefix === false) {
-                 throw new NamespaceException("URI '$uri' is not defined in registry");
-             }
-         }
-         return $prefix;
-     }
-     /**
-      * Provide Traversable interface: iterator over all namespaces
-      *
-      * @return Iterator over all namespaces, with prefix as key and url as value
-      */
-     public function getIterator()
-     {
-         $this->lazyLoadNamespaces();
-         return new ArrayIterator(array_merge($this->defaultNamespaces, $this->userNamespaces));
-     }
-     /**
-      * Implement verification if this is a valid prefix
-      *
-      * Throws the NamespaceException if trying to use one of the
-      * built-in prefixes or a prefix that begins with the characters "xml"
-      * (in any combination of case)
-      *
-      * @param string $prefix the prefix name to check
-      *
-      * @throws NamespaceException if re-assign built-in prefix or prefix starting with xml
-      *
-      * @private
-      * TODO: can we refactor Session::setNamespacePrefix to not need to directly access this?
-      */
-     public function checkPrefix($prefix)
-     {
-         if (! strncasecmp('xml', $prefix, 3)) {
-             throw new NamespaceException("Do not use xml in prefixes for namespace changes: '$prefix'");
-         }
-         if (array_key_exists($prefix, $this->defaultNamespaces)) {
-             throw new NamespaceException("Do not change the predefined prefixes: '$prefix'");
-         }
-         if (false !== strpos($prefix, ' ') || false !== strpos($prefix, ':')) {
-             throw new NamespaceException("Not a valid namespace prefix '$prefix'");
-         }
-     }
-     /**
-      * Get all defined namespaces
-      *
-      * @private
-      */
-     public function getNamespaces()
-     {
-         $this->lazyLoadNamespaces();
-         return array_merge($this->defaultNamespaces, $this->userNamespaces);
-     }
- }
-