44
55use PHPCR \SessionInterface ;
66use PHPCR \ItemInterface ;
7+ use PHPCR \RepositoryException ;
8+ use PHPCR \NamespaceException ;
79
810/**
911 * Helper with only static methods to work with PHPCR nodes
@@ -26,7 +28,7 @@ private function __construct()
2628 * @param SessionInterface $session the phpcr session to create the path
2729 * @param string $path full path, like /content/jobs/data
2830 *
29- * @return PHPCR\NodeInterface the last node of the path, i.e. data
31+ * @return \ PHPCR\NodeInterface the last node of the path, i.e. data
3032 */
3133 public static function createPath (SessionInterface $ session , $ path )
3234 {
@@ -82,4 +84,140 @@ public static function isSystemItem(ItemInterface $item)
8284
8385 return strpos ($ name , 'jcr: ' ) === 0 || strpos ($ name , 'rep: ' ) === 0 ;
8486 }
87+
88+ /**
89+ * Helper method to implement NodeInterface::addNodeAutoNamed
90+ *
91+ * This method only checks for valid namespaces. All other exceptions must
92+ * be thrown by the addNodeAutoNamed implementation.
93+ *
94+ * @param string[] $usedNames list of child names that is currently used and may not be chosen.
95+ * @param string[] $namespaces namespace prefix to uri map of all currently known namespaces.
96+ * @param string $defaultNamespace namespace prefix to use if the hint does not specify.
97+ * @param string $nameHint the name hint according to the API definition
98+ *
99+ * @return string A valid node name for this node
100+ *
101+ * @throws NamespaceException if a namespace prefix is provided in the
102+ * $nameHint which does not exist and this implementation performs
103+ * this validation immediately.
104+ */
105+ public static function generateAutoNodeName ($ usedNames , $ namespaces , $ defaultNamespace , $ nameHint = null )
106+ {
107+ $ usedNames = array_flip ($ usedNames );
108+
109+ /*
110+ * null: The new node name will be generated entirely by the repository.
111+ */
112+ if (null === $ nameHint ) {
113+
114+ return self ::generateWithPrefix ($ usedNames , $ defaultNamespace . ': ' );
115+ }
116+
117+ /*
118+ * "" (the empty string), ":" (colon) or "{}": The new node name will
119+ * be in the empty namespace and the local part of the name will be
120+ * generated by the repository.
121+ */
122+ if ('' === $ nameHint || ': ' == $ nameHint || '{} ' == $ nameHint ) {
123+
124+ return self ::generateWithPrefix ($ usedNames , '' );
125+ }
126+
127+ /*
128+ * "<i>somePrefix</i>:" where <i>somePrefix</i> is a syntactically
129+ * valid namespace prefix
130+ */
131+ if (': ' == $ nameHint [strlen ($ nameHint )-1 ]
132+ && substr_count ($ nameHint , ': ' ) === 1
133+ && preg_match ('#^[a-zA-Z][a-zA-Z0-9]*:$# ' , $ nameHint )
134+ ) {
135+ $ prefix = substr ($ nameHint , 0 , -1 );
136+ if (! isset ($ namespaces [$ prefix ])) {
137+ throw new NamespaceException ("Invalid nameHint ' $ nameHint' " );
138+ }
139+
140+ return self ::generateWithPrefix ($ usedNames , $ prefix . ': ' );
141+ }
142+
143+ /*
144+ * "{<i>someURI</i>}" where <i>someURI</i> is a syntactically valid
145+ * namespace URI
146+ */
147+ if (strlen ($ nameHint ) > 2
148+ && '{ ' == $ nameHint [0 ]
149+ && '} ' == $ nameHint [strlen ($ nameHint )-1 ]
150+ && filter_var (substr ($ nameHint , 1 , -1 ), FILTER_VALIDATE_URL )
151+ ) {
152+ $ prefix = array_search (substr ($ nameHint , 1 , -1 ), $ namespaces );
153+ if (! $ prefix ) {
154+ throw new NamespaceException ("Invalid nameHint ' $ nameHint' " );
155+ }
156+
157+ return self ::generateWithPrefix ($ usedNames , $ prefix . ': ' );
158+ }
159+
160+ /*
161+ * "<i>somePrefix</i>:<i>localNameHint</i>" where <i>somePrefix</i> is
162+ * a syntactically valid namespace prefix and <i>localNameHint</i> is
163+ * syntactically valid local name: The repository will attempt to create a
164+ * name in the namespace represented by that prefix as described in (3),
165+ * above. The local part of the name is generated by the repository using
166+ * <i>localNameHint</i> as a basis. The way in which the local name is
167+ * constructed from the hint may vary across implementations.
168+ */
169+ if (1 === substr_count ($ nameHint , ': ' )) {
170+ list ($ prefix , $ name ) = explode (': ' , $ nameHint );
171+ if (preg_match ('#^[a-zA-Z][a-zA-Z0-9]*$# ' , $ prefix )
172+ && preg_match ('#^[a-zA-Z][a-zA-Z0-9]*$# ' , $ name )
173+ ) {
174+ if (! isset ($ namespaces [$ prefix ])) {
175+ throw new NamespaceException ("Invalid nameHint ' $ nameHint' " );
176+ }
177+
178+ return self ::generateWithPrefix ($ usedNames , $ prefix . ': ' , $ name );
179+ }
180+ }
181+
182+ /*
183+ * "{<i>someURI</i>}<i>localNameHint</i>" where <i>someURI</i> is a
184+ * syntactically valid namespace URI and <i>localNameHint</i> is
185+ * syntactically valid local name: The repository will attempt to create a
186+ * name in the namespace specified as described in (4), above. The local
187+ * part of the name is generated by the repository using <i>localNameHint</i>
188+ * as a basis. The way in which the local name is constructed from the hint
189+ * may vary across implementations.
190+ */
191+ $ matches = array ();
192+ //if (preg_match('#^\\{([^\\}]+)\\}([a-zA-Z][a-zA-Z0-9]*)$}#', $nameHint, $matches)) {
193+ if (preg_match ('#^ \\{([^ \\}]+) \\}([a-zA-Z][a-zA-Z0-9]*)$# ' , $ nameHint , $ matches )) {
194+ $ ns = $ matches [1 ];
195+ $ name = $ matches [2 ];
196+
197+ $ prefix = array_search ($ ns , $ namespaces );
198+ if (! $ prefix ) {
199+ throw new NamespaceException ("Invalid nameHint ' $ nameHint' " );
200+ }
201+
202+ return self ::generateWithPrefix ($ usedNames , $ prefix . ': ' , $ name );
203+ }
204+
205+ throw new RepositoryException ("Invalid nameHint ' $ nameHint' " );
206+ }
207+
208+ /**
209+ * @param string[] $usedNames names that are forbidden
210+ * @param string $prefix the prefix including the colon at the end
211+ * @param string $namepart start for the localname
212+ *
213+ * @return string
214+ */
215+ private static function generateWithPrefix ($ usedNames , $ prefix , $ namepart = '' )
216+ {
217+ do {
218+ $ name = $ prefix . $ namepart . mt_rand ();
219+ } while (isset ($ usedNames [$ name ]));
220+
221+ return $ name ;
222+ }
85223}
0 commit comments