Skip to content

Commit

Permalink
Merge pull request #19 from jackalope/node_type_support
Browse files Browse the repository at this point in the history
Added support for registering node types
  • Loading branch information
dantleech committed Apr 26, 2015
2 parents 970bf8b + 31ea99e commit b0a57bb
Show file tree
Hide file tree
Showing 6 changed files with 230 additions and 15 deletions.
1 change: 0 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ php:
before_script:
- composer selfupdate
- composer install
- composer require "jackalope/jackalope" "dev-node_validator as dev-master"

script: phpunit

Expand Down
14 changes: 4 additions & 10 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
<phpunit backupGlobals="false"
backupStaticAttributes="false"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
syntaxCheck="true"
bootstrap="tests/bootstrap.php">
<phpunit
colors="true"
bootstrap="tests/bootstrap.php"
>
<php>
<var name="phpcr.user" value="admin" />
<var name="phpcr.pass" value="admin" />
Expand Down
38 changes: 35 additions & 3 deletions src/Transport/Fs/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,12 @@
use PHPCR\PathNotFoundException;
use PHPCR\ReferentialIntegrityException;
use Jackalope\Transport\Fs\Model\Node;
use Jackalope\Transport\NodeTypeManagementInterface;
use Jackalope\Transport\Fs\NodeType\NodeTypeStorage;

/**
*/
class Client extends BaseTransport implements WorkspaceManagementInterface, WritingInterface, QueryInterface
class Client extends BaseTransport implements WorkspaceManagementInterface, WritingInterface, QueryInterface, NodeTypeManagementInterface
{
private $loggedIn;

Expand Down Expand Up @@ -83,6 +85,7 @@ public function __construct($factory, $parameters = array(), Filesystem $filesys
$this->storage = new Storage(new Filesystem($adapter), $this->eventDispatcher);
$this->valueConverter = new ValueConverter();
$this->nodeSerializer = new YamlNodeSerializer();
$this->nodeTypeStorage = new NodeTypeStorage($this->storage);
$this->factory = $factory;

$this->registerEventSubscribers();
Expand Down Expand Up @@ -158,6 +161,29 @@ public function getRepositoryDescriptors()
);
}

public function registerNodeTypes($nodeTypes, $allowUpdate)
{
$standardNodeTypes = StandardNodeTypes::getNodeTypeData();

foreach ($nodeTypes as $nodeType) {
if (isset($standardNodeTypes[$nodeType->getName()])) {
throw new RepositoryException(sprintf(
'Cannot overwrite standard node type "%s"', $nodeType->getName()
));
}

if (!$allowUpdate) {
if ($this->nodeTypeStorage->hasNodeType($nodeType->getName())) {
throw new RepositoryException(sprintf(
'Node type "%s" already exists and allowUpdate is false',
$nodeType->getName()
));
}
}
$this->nodeTypeStorage->registerNodeType($this->workspaceName, $nodeType);
}
}

/**
* {@inheritDoc}
*/
Expand Down Expand Up @@ -348,8 +374,12 @@ public function setNodeTypeManager($nodeTypeManager)
*/
public function getNodeTypes($nodeTypes = array())
{
$standardTypes = StandardNodeTypes::getNodeTypeData();
return $standardTypes;
$types = array_merge(
StandardNodeTypes::getNodeTypeData(),
$this->nodeTypeStorage->getNodeTypes($this->workspaceName)
);

return $types;
}

/**
Expand Down Expand Up @@ -587,6 +617,8 @@ public function updateProperties(JackalopeNode $phpcrNode)
public function registerNamespace($prefix, $uri)
{
$this->storage->registerNamespace($this->workspaceName, $prefix, $uri);

$this->init();
}

/**
Expand Down
6 changes: 6 additions & 0 deletions src/Transport/Fs/Filesystem/Storage.php
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,12 @@ public function workspaceInit($name)
$node = new Node();
$node->setProperty('jcr:primaryType', 'nt:unstructured', 'Name');
$this->writeNode($name, '/', $node);
$node = new Node();
$node->setProperty('jcr:primaryType', 'rep:system', 'Name');
$this->writeNode($name, '/jcr:system', $node);
$node = new Node();
$node->setProperty('jcr:primaryType', 'rep:nodeTypes', 'Name');
$this->writeNode($name, '/jcr:system/jcr:nodeTypes', $node);
}

public function ls($workspace, $path)
Expand Down
185 changes: 185 additions & 0 deletions src/Transport/Fs/NodeType/NodeTypeStorage.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
<?php

namespace Jackalope\Transport\Fs\NodeType;

use Jackalope\Transport\Fs\Filesystem\Storage;
use PHPCR\NodeType\NodeTypeDefinitionInterface;
use Jackalope\Transport\Fs\Model\Node;

class NodeTypeStorage
{
const PATH = '/jcr:system/jcr:nodeTypes';

private $storage;

public function __construct(Storage $storage)
{
$this->storage = $storage;
}

public function hasNodeType($workspace, $nodeType)
{
return $this->storage->nodeExists($workspace, self::PATH . '/' . $nodeType);
}

public function registerNodeType($workspace, NodeTypeDefinitionInterface $definition)
{
$node = new Node();
$node->setProperty('jcr:hasOrderableChildNodes', $definition->hasOrderableChildNodes(), 'Boolean');
$node->setProperty('jcr:isMixin', $definition->isMixin());
$node->setProperty('jcr:nodeTypeName', $definition->getName(), 'Name');
$node->setProperty('jcr:superTypes', $definition->getDeclaredSupertypeNames(), 'Name');
$node->setProperty('jcr:primaryType', 'nt:nodeType', 'Name');

$this->storage->writeNode($workspace, self::PATH . '/' . $definition->getName(), $node);

foreach ($definition->getDeclaredPropertyDefinitions() ? : array() as $propDefinition) {
$propNode = new Node();
$propNode->setProperty('jcr:requiredType', $propDefinition->getRequiredType(), 'Reference');
$propNode->setProperty('jcr:autoCreated', $propDefinition->isAutoCreated(), 'Boolean');
$propNode->setProperty('jcr:mandatory', $propDefinition->isMandatory(), 'Boolean');
$propNode->setProperty('jcr:protected', $propDefinition->isProtected(), 'Boolean');
$propNode->setProperty('jcr:onParentVersion', $propDefinition->getOnParentVersion(), 'String');
$propNode->setProperty('jcr:name', $propDefinition->getName(), 'String');
$propNode->setProperty('jcr:multiple', $propDefinition->isMultiple(), 'Boolean');
$propNode->setProperty('jcr:primaryType', 'nt:propertyDefinition', 'Name');

$this->storage->writeNode(
$workspace,
self::PATH . '/' . $definition->getName() . '/prop-' . $propDefinition->getName(),
$propNode
);
}

foreach ($definition->getDeclaredChildNodeDefinitions() ? : array() as $childDefinition) {
$childNode = new Node();
$childNode->setProperty('jcr:name', $childDefinition->getName(), 'String');
$childNode->setProperty('jcr:requiredPrimaryTypes', $childDefinition->getRequiredPrimaryTypeNames(), 'Reference');
$childNode->setProperty('jcr:autoCreated', $childDefinition->isAutoCreated(), 'Boolean');
$childNode->setProperty('jcr:defaultPrimaryType', $childDefinition->getDefaultPrimaryTypeName(), 'Name');
$childNode->setProperty('jcr:protected', $childDefinition->isProtected(), 'Boolean');
$childNode->setProperty('jcr:mandatory', $childDefinition->isMandatory(), 'Boolean');
$childNode->setProperty('jcr:sameNameSiblings', $childDefinition->allowsSameNameSiblings());
$childNode->setProperty('jcr:onParentVersion', $childDefinition->getOnParentVersion(), 'String');
$childNode->setProperty('jcr:primaryType', 'nt:childNodeDefinition', 'Name');

$this->storage->writeNode(
$workspace,
self::PATH . '/' . $definition->getName() . '/child-' . $childDefinition->getName(),
$childNode
);
}
}

public function getNodeTypes($workspace)
{
$nodeTypeNames = $this->storage->ls($workspace, self::PATH);
$nodeTypeData = array();

foreach ($nodeTypeNames['dirs'] as $nodeTypeName) {
$nodeTypePath = self::PATH . '/' . $nodeTypeName;
$node = $this->storage->readNode($workspace, $nodeTypePath);

$propertyData = $this->getPropertyData($workspace, $nodeTypeName, $nodeTypePath);
$childData = $this->getChildData($workspace, $nodeTypeName, $nodeTypePath);

$nodeTypeData[$nodeTypeName] = array(
'name' => $nodeTypeName,
'isAbstract' => false,
'isMixin' => $node->getPropertyValue('jcr:isMixin'),
'isQueryable' => true,
'hasOrderableChildNodes' => $node->getPropertyValue('jcr:hasOrderableChildNodes'),
'primaryItemName' => null,
'declaredSuperTypeNames' => $node->getPropertyValue('jcr:superTypes'),
'declaredPropertyDefinitions' => $propertyData,
'declaredNodeDefinitions' => $childData,
);
}

return $nodeTypeData;
}

private function getPropertyData($workspace, $nodeType, $path)
{
$propertyNodeNames = $this->storage->ls($workspace, $path);

$propertyData = array();

foreach ($propertyNodeNames['dirs'] as $propertyNodeName) {
if (substr($propertyNodeName, 0, 4) !== 'prop') {
continue;
}
$node = $this->storage->readNode($workspace, $path . '/' . $propertyNodeName);

$data = array(
'declaringNodeType' => $nodeType,
'name' => $node->getPropertyValue('jcr:name'),
'isAutoCreated' => $node->getPropertyValue('jcr:autoCreated'),
'isMandatory' => $node->getPropertyValue('jcr:mandatory'),
'isProtected' => $node->getPropertyValue('jcr:protected'),
'onParentVersion' => $node->getPropertyValue('jcr:onParentVersion'),
'requiredType' => $node->getPropertyValue('jcr:requiredType'),
'multiple' => $node->getPropertyValue('jcr:multiple'),
'fullTextSearchable' => true,
'queryOrderable' => true,
'availableQueryOperators' =>
array(
0 => 'jcr.operator.equal.to',
1 => 'jcr.operator.not.equal.to',
2 => 'jcr.operator.greater.than',
3 => 'jcr.operator.greater.than.or.equal.to',
4 => 'jcr.operator.less.than',
5 => 'jcr.operator.less.than.or.equal.to',
6 => 'jcr.operator.like',
),
);

$propertyData[] = $data;
}

return $propertyData;
}

private function getChildData($workspace, $nodeType, $path)
{
$childNodeNames = $this->storage->ls($workspace, $path);

$childData = array();

foreach ($childNodeNames['dirs'] as $childNodeName) {
if (substr($childNodeName, 0, 5) !== 'child') {
continue;
}

$node = $this->storage->readNode($workspace, $path . '/' . $childNodeName);

$data = array(
'declaringNodeType' => $nodeType,
);

$map = array(
'name' => 'jcr:name',
'isAutoCreated' => 'jcr:autoCreated',
'isMandatory' => 'jcr:mandatory',
'isProtected' => 'jcr:protected',
'onParentVersion' => 'jcr:onParentVersion',
'allowsSameNameSiblings' => 'jcr:sameNameSiblings',
'defaultPrimaryTypeName' => 'jcr:defaultPrimaryType',
'requiredPrimaryTypeNames' => 'jcr:requiredPrimaryTypes',
);

$this->mapData($map, $node, $data);

$childData[] = $data;
}

return $childData;
}

private function mapData($map, $node, &$data)
{
foreach ($map as $key => $propertyName) {
$data[$key] = $node->hasProperty($propertyName) ? $node->getPropertyValue($propertyName) : null;
}
}
}
1 change: 0 additions & 1 deletion tests/ImplementationLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ protected function __construct()
'AccessControlManagement',
'Locking',
'LifecycleManagement',
'NodeTypeManagement',
'RetentionAndHold',
'Transactions',
'SameNameSiblings',
Expand Down

0 comments on commit b0a57bb

Please sign in to comment.