Skip to content

Commit 43edbba

Browse files
committed
implement cnd writer
1 parent eafca96 commit 43edbba

File tree

1 file changed

+236
-0
lines changed

1 file changed

+236
-0
lines changed
Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
<?php
2+
3+
namespace PHPCR\Util\CND\Writer;
4+
5+
use PHPCR\NamespaceRegistryInterface;
6+
use PHPCR\PropertyType;
7+
use PHPCR\Version\OnParentVersionAction;
8+
use PHPCR\NodeType\NodeDefinitionInterface;
9+
use PHPCR\NodeType\NodeTypeDefinitionInterface;
10+
use PHPCR\NodeType\NodeTypeManagerInterface;
11+
use PHPCR\NodeType\NodeTypeTemplateInterface;
12+
use PHPCR\NodeType\PropertyDefinitionInterface;
13+
14+
/**
15+
* Generator for JCR-2.0 CND files.
16+
*
17+
* Walk an array of node types and generate the CND file for them, including
18+
* the namespaces.
19+
*
20+
* @see http://www.day.com/specs/jcr/2.0/25_Appendix.html#25.2.3 CND Grammar
21+
* @see http://jackrabbit.apache.org/node-type-notation.html
22+
*
23+
* @author David Buchmann <david@liip.ch>
24+
*/
25+
class CndWriter
26+
{
27+
/**
28+
* @var NamespaceRegistryInterface
29+
*/
30+
private $ns;
31+
32+
/** @var array hashmap of prefix => namespace uri */
33+
private $namespaces = array();
34+
35+
/**
36+
* @param NodeTypeManagerInterface $ntm
37+
*/
38+
public function __construct(NamespaceRegistryInterface $ns)
39+
{
40+
$this->ns = $ns;
41+
}
42+
43+
/**
44+
* Parse a file with CND statements.
45+
*
46+
* @param NodeTypeTemplateInterface[] $nodeTypes
47+
*
48+
* @return string with declarations for all non-system namespaces and for
49+
* all node types in that array.
50+
*/
51+
public function writeString(array $nodeTypes)
52+
{
53+
$cnd = '';
54+
foreach ($nodeTypes as $nodeType) {
55+
$cnd .= $this->writeNodeType($nodeType);
56+
}
57+
58+
return $this->writeNamespaces() . $cnd;
59+
}
60+
61+
/**
62+
* Generate the namespace mapping of all encountered namespaces.
63+
*
64+
* NamespaceMapping ::= '<' Prefix '=' Uri '>'
65+
* Prefix ::= String
66+
* Uri ::= String
67+
*/
68+
protected function writeNamespaces()
69+
{
70+
$ns = '';
71+
foreach ($this->namespaces as $prefix => $uri) {
72+
$ns .= "<$prefix=$uri>\n";
73+
}
74+
75+
return $ns;
76+
}
77+
78+
private function checkNamespace($name)
79+
{
80+
if (false === strpos($name, ':')) {
81+
return;
82+
}
83+
list($prefix) = explode(':', $name);
84+
85+
// namespace registry will throw exception if namespace prefix not found
86+
$this->namespaces[$prefix] = "'" . $this->ns->getURI($prefix) . "'";
87+
}
88+
89+
/**
90+
* A node type definition consists of a node type name followed by an optional
91+
* supertypes block, an optional node type attributes block and zero or more
92+
* blocks, each of which is either a property or child node definition.
93+
*
94+
* NodeTypeDef ::= NodeTypeName [Supertypes]
95+
* [NodeTypeAttribute {NodeTypeAttribute}]
96+
* {PropertyDef | ChildNodeDef}
97+
*/
98+
protected function writeNodeType(NodeTypeDefinitionInterface $nodeType)
99+
{
100+
$this->checkNamespace($nodeType->getName());
101+
$s = '[' . $nodeType->getName() . ']';
102+
if ($superTypes = $nodeType->getDeclaredSupertypeNames()) {
103+
foreach ($superTypes as $superType) {
104+
$this->checkNamespace($superType);
105+
}
106+
$s .= ' > ' . implode(', ', $superTypes);
107+
}
108+
$s .= "\n";
109+
110+
$attributes = '';
111+
112+
if ($nodeType->hasOrderableChildNodes()) {
113+
$attributes .= 'orderable ';
114+
}
115+
if ($nodeType->isMixin()) {
116+
$attributes .= 'mixin ';
117+
}
118+
if ($nodeType->isAbstract()) {
119+
$attributes .= 'abstract ';
120+
}
121+
$attributes .= $nodeType->isQueryable() ? 'query ' : 'noquery ';
122+
if ($nodeType->getPrimaryItemName()) {
123+
$attributes .= 'primaryitem ' . $nodeType->getPrimaryItemName() . ' ';
124+
}
125+
if ($attributes) {
126+
$s .= trim($attributes) . "\n";
127+
}
128+
129+
$s .= $this->writeProperties($nodeType->getDeclaredPropertyDefinitions());
130+
131+
$s .= $this->writeChildren($nodeType->getDeclaredChildNodeDefinitions());
132+
133+
return $s;
134+
}
135+
136+
private function writeProperties($properties)
137+
{
138+
$s = '';
139+
140+
/** @var $property PropertyDefinitionInterface */
141+
foreach ($properties as $property) {
142+
$this->checkNamespace($property->getName());
143+
$s .= '- ' . $property->getName();
144+
145+
if ($property->getRequiredType()) {
146+
$s .= ' (' . PropertyType::nameFromValue($property->getRequiredType()) . ')';
147+
}
148+
$s .= "\n";
149+
if ($property->getDefaultValues()) {
150+
$s .= "= '" . implode("', '", $property->getDefaultValues()) . "'\n";
151+
}
152+
$attributes = '';
153+
if ($property->isMandatory()) {
154+
$attributes .= 'mandatory ';
155+
}
156+
if ($property->isAutoCreated()) {
157+
$attributes .= 'autocreated ';
158+
}
159+
if ($property->isProtected()) {
160+
$attributes .= 'protected ';
161+
}
162+
if ($property->isMultiple()) {
163+
$attributes .= 'multiple ';
164+
}
165+
if ($property->getAvailableQueryOperators()) {
166+
$attributes .= implode("', '", $property->getAvailableQueryOperators());
167+
}
168+
if (! $property->isFullTextSearchable()) {
169+
$attributes .= 'nofulltext ';
170+
}
171+
if (! $property->isQueryOrderable()) {
172+
$attributes .= 'noqueryorder ';
173+
}
174+
175+
if (OnParentVersionAction::COPY !== $property->getOnParentVersion()) {
176+
$attributes .= OnParentVersionAction::nameFromValue($property->getOnParentVersion()) . ' ';
177+
}
178+
179+
if ($attributes) {
180+
$s .= trim($attributes) . "\n";
181+
}
182+
183+
if ($property->getValueConstraints()) {
184+
$s .= "< '" . implode("', '", $property->getValueConstraints()) . "'\n";
185+
}
186+
}
187+
188+
return $s;
189+
}
190+
191+
private function writeChildren($children)
192+
{
193+
$s = '';
194+
195+
/** @var $child NodeDefinitionInterface */
196+
foreach ($children as $child) {
197+
$this->checkNamespace($child->getName());
198+
$s .= '+ ' . $child->getName();
199+
200+
if ($child->getRequiredPrimaryTypeNames()) {
201+
foreach ($child->getRequiredPrimaryTypeNames() as $typeName) {
202+
$this->checkNamespace($typeName);
203+
}
204+
$s .= ' (' . implode(', ', $child->getRequiredPrimaryTypeNames()) . ')';
205+
}
206+
if ($child->getDefaultPrimaryTypeName()) {
207+
$this->checkNamespace($child->getDefaultPrimaryTypeName());
208+
$s .= "\n= " . $child->getDefaultPrimaryTypeName();
209+
}
210+
$s .= "\n";
211+
212+
$attributes = '';
213+
if ($child->isMandatory()) {
214+
$attributes .= 'mandatory ';
215+
}
216+
if ($child->isAutoCreated()) {
217+
$attributes .= 'autocreated ';
218+
}
219+
if ($child->isProtected()) {
220+
$attributes .= 'protected ';
221+
}
222+
if (OnParentVersionAction::COPY != $child->getOnParentVersion()) {
223+
$attributes .= OnParentVersionAction::nameFromValue($child->getOnParentVersion()) . ' ';
224+
}
225+
if ($child->allowsSameNameSiblings()) {
226+
$attributes .= 'sns ';
227+
}
228+
229+
if ($attributes) {
230+
$s .= trim($attributes) . "\n";
231+
}
232+
}
233+
234+
return $s;
235+
}
236+
}

0 commit comments

Comments
 (0)