vendor/jackalope/jackalope/src/Jackalope/NodeType/NodeTypeManager.php line 269
<?phpnamespace Jackalope\NodeType;use Iterator;use IteratorAggregate;use ArrayIterator;use PHPCR\AccessDeniedException;use PHPCR\NamespaceException;use PHPCR\NamespaceRegistryInterface;use PHPCR\NodeType\NodeTypeInterface;use PHPCR\NodeType\NodeTypeDefinitionInterface;use PHPCR\NodeType\NodeTypeManagerInterface;use PHPCR\NodeType\NoSuchNodeTypeException;use PHPCR\NodeType\NodeTypeExistsException;use Jackalope\ObjectManager;use Jackalope\NotImplementedException;use Jackalope\FactoryInterface;use PHPCR\RepositoryException;/*** {@inheritDoc}** In Jackalope, we try to do lazy fetching of node types to reduce overhead.* Jackalope supports registering node types, and when using the jackrabbit for* transport, there is an additional method registerNodeTypesCnd for the* jackrabbit specific textual node type specification.** @license http://www.apache.org/licenses Apache License Version 2.0, January 2004* @license http://opensource.org/licenses/MIT MIT License*/class NodeTypeManager implements IteratorAggregate, NodeTypeManagerInterface{/*** The factory to instantiate objects.** @var FactoryInterface*/protected $factory;/*** @var ObjectManager*/protected $objectManager;/*** @var NamespaceRegistryInterface*/protected $namespaceRegistry;/*** Cache of already fetched primary node type instances.** @var array*/protected $primaryTypes;/*** Cache of already fetched mixin node type instances.** @var array*/protected $mixinTypes;/*** Array of arrays with the super type as key and its sub types as values.* @var array*/protected $nodeTree = [];/*** Flag to only load all node types from the backend once.** Methods like hasNodeType() need to fetch all node types. Others like* getNodeType() do not need all, but just the requested one. Unless we* need all, we only load specific ones and cache them.** @var boolean*/protected $fetchedAllFromBackend = false;/*** Create the node type manager for a session.** There may be only one instance per session* @param FactoryInterface $factory* @param ObjectManager $objectManager* @param NamespaceRegistryInterface $namespaceRegistry*/public function __construct(FactoryInterface $factory,ObjectManager $objectManager,NamespaceRegistryInterface $namespaceRegistry) {$this->factory = $factory;$this->objectManager = $objectManager;$this->namespaceRegistry = $namespaceRegistry;}/*** Fetch a node type from backend.** Without a filter parameter, this will fetch all node types from the backend.** It is no problem to call this method with null as name, it will remember* once it fetched all node types and do nothing after that.** On fetch all, already cached node types are kept.** @param string $name type name to fetch. defaults to null which will* fetch all nodes.*/protected function fetchNodeTypes($name = null){if ($this->fetchedAllFromBackend) {return;}if (null !== $name) {if (!empty($this->primaryTypes[$name]) || !empty($this->mixinTypes[$name])) {return; //we already know this node}//OPTIMIZE: also avoid trying to fetch nonexisting definitions we already tried to get$nodeTypes = $this->objectManager->getNodeType($name);} else {$nodeTypes = $this->objectManager->getNodeTypes();$this->fetchedAllFromBackend = true;}foreach ($nodeTypes as $nodeType) {/** @var NodeType $nodeType */$nodeType = $this->factory->get(NodeType::class, [$this, $nodeType]);$name = $nodeType->getName();//do not overwrite existing types. maybe they where changed locallyif (empty($this->primaryTypes[$name]) && empty($this->mixinTypes[$name])) {$this->addNodeType($nodeType);}}}/*** Stores the node type in our internal structures (flat && tree)** @param NodeTypeInterface $nodeType The nodetype to add*/protected function addNodeType(NodeTypeInterface $nodeType){if ($nodeType->isMixin()) {$this->mixinTypes[$nodeType->getName()] = $nodeType;} else {$this->primaryTypes[$nodeType->getName()] = $nodeType;}$this->addToNodeTree($nodeType);}/*** Helper method for node types: Returns the declared subtypes of a given* nodename.** @param string $nodeTypeName** @return array with the names of the subnode types pointing to the node type instances** @see NodeType::getDeclaredSubtypes** @private*/public function getDeclaredSubtypes($nodeTypeName){// OPTIMIZE: any way to avoid loading all nodes at this point?$this->fetchNodeTypes();if (empty($this->nodeTree[$nodeTypeName])) {return [];}return $this->nodeTree[$nodeTypeName];}/*** Helper method for NodeType: Returns all sub types of a node and their* sub types.** @param string $nodeTypeName** @return array with the names of the subnode types pointing to the node type instances** @see NodeType::getSubtypes** @private*/public function getSubtypes($nodeTypeName){// OPTIMIZE: any way to avoid loading all nodes at this point?$this->fetchNodeTypes();$ret = [];if (isset($this->nodeTree[$nodeTypeName])) {foreach ($this->nodeTree[$nodeTypeName] as $name => $subnode) {$ret = array_merge($ret, [$name => $subnode], $this->getSubtypes($name));}}return $ret;}/*** Adds the declared super types of a node type to the tree to be able to* fetch the sub types of those super types later on.** Part of addNodeType.** @param NodeTypeInterface $nodetype the node type to add.*/private function addToNodeTree($nodetype){foreach ($nodetype->getDeclaredSupertypeNames() as $declaredSupertypeName) {if (isset($this->nodeTree[$declaredSupertypeName])) {$this->nodeTree[$declaredSupertypeName] =array_merge($this->nodeTree[$declaredSupertypeName],[$nodetype->getName() => $nodetype]);} else {$this->nodeTree[$declaredSupertypeName] = [$nodetype->getName() => $nodetype];}}}/*** {@inheritDoc}** @api*/public function getNodeType($nodeTypeName){if (null === $nodeTypeName) {throw new NoSuchNodeTypeException('nodeTypeName is <null>');}if ('' === $nodeTypeName) {throw new NoSuchNodeTypeException('nodeTypeName is empty string');}if ($nodeTypeName[0] === '{') {list($uri, $name) = explode('}', substr($nodeTypeName, 1));$prefix = $this->namespaceRegistry->getPrefix($uri);$nodeTypeName = "$prefix:$name";}$this->fetchNodeTypes($nodeTypeName);if (isset($this->primaryTypes[$nodeTypeName])) {return $this->primaryTypes[$nodeTypeName];}if (isset($this->mixinTypes[$nodeTypeName])) {return $this->mixinTypes[$nodeTypeName];}throw new NoSuchNodeTypeException($nodeTypeName);}/*** {@inheritDoc}** @api*/public function hasNodeType($name){try {$this->fetchNodeTypes($name);} catch (NoSuchNodeTypeException $e) {// if we have not yet fetched all types and this type is not existing// we get an exception. just ignore the exception, we don't have the type.return false;}return isset($this->primaryTypes[$name]) || isset($this->mixinTypes[$name]);}/*** {@inheritDoc}** @api*/public function getAllNodeTypes(){$this->fetchNodeTypes();return new ArrayIterator(array_merge($this->primaryTypes, $this->mixinTypes));}/*** {@inheritDoc}** @api*/public function getPrimaryNodeTypes(){$this->fetchNodeTypes();return new ArrayIterator($this->primaryTypes);}/*** {@inheritDoc}** @api*/public function getMixinNodeTypes(){$this->fetchNodeTypes();return new ArrayIterator($this->mixinTypes);}/*** {@inheritDoc}** @api*/public function createNodeTypeTemplate($ntd = null){return $this->factory->get(NodeTypeTemplate::class, [$this, $ntd]);}/*** {@inheritDoc}** @api*/public function createNodeDefinitionTemplate(){return $this->factory->get(NodeDefinitionTemplate::class, [$this]);}/*** {@inheritDoc}** @api*/public function createPropertyDefinitionTemplate(){return $this->factory->get(PropertyDefinitionTemplate::class, [$this]);}/*** {@inheritDoc}** @api*/public function registerNodeType(NodeTypeDefinitionInterface $ntd, $allowUpdate){$this->registerNodeTypes([$ntd], $allowUpdate);return $ntd;}/*** Internally create a node type object** @param NodeTypeDefinitionInterface $ntd* @param bool $allowUpdate whether updating the definition is to be allowed or not** @return NodeType the new node type** @throws RepositoryException* @throws NodeTypeExistsException*/protected function createNodeType(NodeTypeDefinitionInterface $ntd, $allowUpdate){if ($this->hasNodeType($ntd->getName()) && !$allowUpdate) {throw new NodeTypeExistsException('NodeType already existing: '.$ntd->getName());}return $this->factory->get(NodeType::class, [$this, $ntd]);}/*** {@inheritDoc}** @api*/public function registerNodeTypes(array $definitions, $allowUpdate){$nts = [];// prepare them first (all or nothing)foreach ($definitions as $definition) {$nts[$definition->getName()] = $this->createNodeType($definition, $allowUpdate);}$this->objectManager->registerNodeTypes($definitions, $allowUpdate);// no need to fetch the node types as with cnd, we already have the def and can// now register them ourselvesforeach ($nts as $nt) {$this->addNodeType($nt);}return new ArrayIterator($nts);}/*** {@inheritDoc}** @throws AccessDeniedException* @throws NamespaceException** @api*/public function registerNodeTypesCnd($cnd, $allowUpdate){//set fetched from backend to false to allow to load the new types from backend$fetched = $this->fetchedAllFromBackend;$this->fetchedAllFromBackend = false;$this->objectManager->registerNodeTypesCnd($cnd, $allowUpdate);//parse out type names and fetch types to return definitions of the new nodespreg_match_all('/\[([^\]]*)\]/', $cnd, $names);$types = [];foreach ($names[1] as $name) {$types[$name] = $this->getNodeType($name);}$this->fetchedAllFromBackend = $fetched;return $types;}/*** {@inheritDoc}** @api*/public function unregisterNodeType($name){if (!empty($this->primaryTypes[$name])) {unset($this->primaryTypes[$name]);} elseif (!empty($this->mixinTypes[$name])) {unset($this->mixinTypes[$name]);} else {throw new NoSuchNodeTypeException('NodeType not found: '.$name);}throw new NotImplementedException('TODO: remove from nodeTree and register with server (jackrabbit has not implemented this yet)');}/*** {@inheritDoc}** @api*/public function unregisterNodeTypes(array $names){foreach ($names as $name) {$this->unregisterNodeType($name);}}/*** Provide Traversable interface: redirect to getAllNodeTypes** @return Iterator over all node types* @throws RepositoryException*/#[\ReturnTypeWillChange]public function getIterator(): \Traversable{return $this->getAllNodeTypes();}}