/
Session.php
584 lines (539 loc) · 23.2 KB
/
Session.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
<?php
/**
* The Session object provides read and (if implemented) write access to the
* content of a particular workspace in the repository.
*
* The Session object is returned by Repository.login(). It encapsulates both
* the authorization settings of a particular user (as specified by the passed
* Credentials) and a binding to the workspace specified by the workspaceName
* passed on login.
*
* Each Session object is associated one-to-one with a Workspace object. The
* Workspace object represents a "view" of an actual repository workspace
* entity as seen through the authorization settings of its associated Session.
*/
class jackalope_Session implements PHPCR_SessionInterface {
protected $repository;
protected $workspace;
protected $objectManager;
protected $credentials;
protected $logout = false;
/** creates the corresponding workspace */
public function __construct(jackalope_Repository $repository, $workspaceName, PHPCR_SimpleCredentials $credentials, jackalope_TransportInterface $transport) {
$this->repository = $repository;
$this->objectManager = jackalope_Factory::get('ObjectManager', array($transport, $this));
$this->workspace = jackalope_Factory::get('Workspace', array($this, $this->objectManager, $workspaceName));
$this->credentials = $credentials;
}
/**
* Returns the Repository object through which this session was acquired.
*
* @return PHPCR_RepositoryInterface a Repository object.
* @api
*/
public function getRepository() {
return $this->repository;
}
/**
* Gets the user ID associated with this Session. How the user ID is set is
* up to the implementation, it may be a string passed in as part of the
* credentials or it may be a string acquired in some other way. This method
* is free to return an "anonymous user ID" or null.
*
* @return string The user id associated with this Session.
* @api
*/
public function getUserID() {
return $this->credentials->getUserID(); //TODO: what if its not simple credentials? what about anonymous login?
}
/**
* Returns the names of the attributes set in this session as a result of
* the Credentials that were used to acquire it. Not all Credentials
* implementations will contain attributes (though, for example,
* SimpleCredentials does allow for them). This method returns an empty
* array if the Credentials instance did not provide attributes.
*
* @return array A string array containing the names of all attributes passed in the credentials used to acquire this session.
* @api
*/
public function getAttributeNames() {
return $this->credentials->getAttributeNames();
}
/**
* Returns the value of the named attribute as an Object, or null if no
* attribute of the given name exists. See getAttributeNames().
*
* @param string $name The name of an attribute passed in the credentials used to acquire this session.
* @return object The value of the attribute or null if no attribute of the given name exists.
* @api
*/
public function getAttribute($name) {
return $this->credentials->getAttribute($name);
}
/**
* Returns the Workspace attached to this Session.
*
* @return PHPCR_WorkspaceInterface a Workspace object.
* @api
*/
public function getWorkspace() {
return $this->workspace;
}
/**
* Returns the root node of the workspace, "/". This node is the main access
* point to the content of the workspace.
*
* @return PHPCR_NodeInterface The root node of the workspace: a Node object.
* @throws RepositoryException if an error occurs.
* @api
*/
public function getRootNode() {
return $this->getNode('/');
}
/**
* Returns a new session in accordance with the specified (new) Credentials.
* Allows the current user to "impersonate" another using incomplete or relaxed
* credentials requirements (perhaps including a user name but no password, for
* example), assuming that this Session gives them that permission.
* The new Session is tied to a new Workspace instance. In other words, Workspace
* instances are not re-used. However, the Workspace instance returned represents
* the same actual persistent workspace entity in the repository as is represented
* by the Workspace object tied to this Session.
*
* @param PHPCR_CredentialsInterface $credentials A Credentials object
* @return PHPCR_SessionInterface a Session object
* @throws PHPCR_LoginException if the current session does not have sufficient access to perform the operation.
* @throws PHPCR_RepositoryException if another error occurs.
* @api
*/
public function impersonate(PHPCR_CredentialsInterface $credentials) {
throw new PHPCR_LoginException('Not supported');
}
/**
* Returns the node specified by the given identifier. Applies to both referenceable
* and non-referenceable nodes.
*
* @param string $id An identifier.
* @return PHPCR_NodeInterface A Node.
* @throws PHPCR_ItemNotFoundException if no node with the specified identifier exists or if this Session does not have read access to the node with the specified identifier.
* @throws PHPCR_RepositoryException if another error occurs.
* @api
*/
public function getNodeByIdentifier($id) {
return $this->objectManager->getNode($id);
}
/**
* Returns the node at the specified absolute path in the workspace. If no such
* node exists, then it returns the property at the specified path.
*
* This method should only be used if the application does not know whether the
* item at the indicated path is property or node. In cases where the application
* has this information, either getNode(java.lang.String) or
* getProperty(java.lang.String) should be used, as appropriate. In many repository
* implementations the node and property-specific methods are likely to be more
* efficient than getItem.
*
* @param string $absPath An absolute path.
* @return PHPCR_ItemInterface
* @throws PHPCR_PathNotFoundException if no accessible item is found at the specified path.
* @throws PHPCR_RepositoryException if another error occurs.
* @api
*/
public function getItem($absPath) {
if(strpos($absPath,'/') !== 0) {
throw new PHPCR_PathNotFoundException('It is forbidden to call getItem on session with a relative path');
}
if ($this->nodeExists($absPath)) {
return $this->getNode($absPath);
} else {
return $this->getProperty($absPath);
}
}
/**
* Returns the node at the specified absolute path in the workspace.
*
* @param string $absPath An absolute path.
* @return PHPCR_NodeInterface A node
* @throws PHPCR_PathNotFoundException if no accessible node is found at the specified path.
* @throws PHPCR_RepositoryException if another error occurs.
* @api
*/
public function getNode($absPath) {
return $this->objectManager->getNodeByPath($absPath);
}
/**
* Returns the property at the specified absolute path in the workspace.
*
* @param string $absPath An absolute path.
* @return PHPCR_PropertyInterface A property
* @throws PHPCR_PathNotFoundException if no accessible property is found at the specified path.
* @throws PHPCR_RepositoryException if another error occurs.
* @api
*/
public function getProperty($absPath) {
return $this->objectManager->getPropertyByPath($absPath);
}
/**
* Returns true if an item exists at absPath and this Session has read
* access to it; otherwise returns false.
*
* @param string $absPath An absolute path.
* @return boolean a boolean
* @throws PHPCR_RepositoryException if absPath is not a well-formed absolute path.
* @api
*/
public function itemExists($absPath) {
if ($absPath == '/') return true;
return $this->nodeExists($absPath) || $this->propertyExists($absPath);
}
/**
* Returns true if a node exists at absPath and this Session has read
* access to it; otherwise returns false.
*
* @param string $absPath An absolute path.
* @return boolean a boolean
* @throws PHPCR_RepositoryException if absPath is not a well-formed absolute path.
* @api
*/
public function nodeExists($absPath) {
if ($absPath == '/') return true;
if (!jackalope_Helper::isAbsolutePath($absPath) || !jackalope_Helper::isValidPath($absPath)) {
throw new PHPCR_RepositoryException("Path is invalid: $absPath");
}
try {
//OPTIMIZE: avoid throwing and catching errors would improve performance if many node exists calls are made
//would need to communicate to the lower layer that we do not want exceptions
$this->getNode($absPath);
} catch(Exception $e) {
return false;
}
return true;
}
/**
* Returns true if a property exists at absPath and this Session has read
* access to it; otherwise returns false.
*
* @param string $absPath An absolute path.
* @return boolean a boolean
* @throws PHPCR_RepositoryException if absPath is not a well-formed absolute path.
* @api
*/
public function propertyExists($absPath) {
// TODO: what about $absPath == '/' here? if not then ::itemExists is faulty
if (!jackalope_Helper::isAbsolutePath($absPath) || !jackalope_Helper::isValidPath($absPath)) {
throw new PHPCR_RepositoryException("Path is invalid: $absPath");
}
try {
//OPTIMIZE: avoid throwing and catching errors would improve performance if many node exists calls are made
//would need to communicate to the lower layer that we do not want exceptions
$this->getProperty($absPath);
} catch(Exception $e) {
return false;
}
return true;
}
/**
* not implemented
*/
public function move($srcAbsPath, $destAbsPath) {
throw new jackalope_NotImplementedException('Write');
}
/**
* not implemented
*/
public function removeItem($absPath) {
throw new jackalope_NotImplementedException('Write');
}
/**
* not implemented
*/
public function save() {
throw new jackalope_NotImplementedException('Write');
}
/**
* not implemented
*/
public function refresh($keepChanges) {
throw new jackalope_NotImplementedException('Write');
}
/**
* Returns true if this session holds pending (that is, unsaved) changes;
* otherwise returns false.
*
* @return boolean a boolean
* @throws PHPCR_RepositoryException if an error occurs
* @api
*/
public function hasPendingChanges() {
throw new jackalope_NotImplementedException('Write');
}
/**
* not implemented
*/
public function getValueFactory() {
throw new jackalope_NotImplementedException('Write');
}
/**
* For ACTION_READ, checks if the path is allowed to be read by the current session.
*
* If anything else/more than ACTION_READ is specified, will return false.
*
* @param string $absPath an absolute path.
* @param string $actions a comma separated list of action strings.
* @return boolean true if this Session has permission to perform the specified actions at the specified absPath.
* @throws PHPCR_RepositoryException if an error occurs.
* @api
*/
public function hasPermission($absPath, $actions) {
if ($actions == self::ACTION_READ) {
throw new jackalope_NotImplementedException('TODO: check read permission');
/*
* The information returned through this method will only reflect the access
* control status (both JCR defined and implementation-specific) and not
* other restrictions that may exist, such as node type constraints. For
* example, even though hasPermission may indicate that a particular Session
* may add a property at /A/B/C, the node type of the node at /A/B may
* prevent the addition of a property called C.
*/
}
//no write operations are supported.
return false;
}
/**
* If hasPermission returns false, throws the security exception
*
* @param string $absPath an absolute path.
* @param string $actions a comma separated list of action strings.
* @return void
* @throws PHPCR_Security_AccessControlException If permission is denied.
* @throws PHPCR_RepositoryException if another error occurs.
* @api
*/
public function checkPermission($absPath, $actions) {
if (! $this->hasPermission($absPath, $actions)) {
throw new PHPCR_Security_AccessControlException($absPath);
}
}
/**
* not really anything right now
*
* @param string $methodName the name of the method.
* @param object $target the target object of the operation.
* @param array $arguments the arguments of the operation.
* @return boolean FALSE if the operation cannot be performed, TRUE if the operation can be performed or if the repository cannot determine whether the operation can be performed.
* @throws PHPCR_RepositoryException if an error occurs
* @api
*/
public function hasCapability($methodName, $target, array $arguments) {
//we never determine wether operation can be performed as it is optional ;-)
//TODO: could implement some
return true;
}
/**
* not implemented
*/
public function getImportContentHandler($parentAbsPath, $uuidBehavior) {
throw new jackalope_NotImplementedException('Write');
}
/**
* not implemented
*/
public function importXML($parentAbsPath, $in, $uuidBehavior) {
throw new jackalope_NotImplementedException('Write');
}
/**
* Serializes the node (and if $noRecurse is false, the whole subgraph) at
* $absPath as an XML stream and outputs it to the supplied URI. The
* resulting XML is in the system view form. Note that $absPath must be
* the path of a node, not a property.
*
* If $skipBinary is true then any properties of PropertyType.BINARY will be serialized
* as if they are empty. That is, the existence of the property will be serialized,
* but its content will not appear in the serialized output (the <sv:value> element
* will have no content). Note that in the case of multi-value BINARY properties,
* the number of values in the property will be reflected in the serialized output,
* though they will all be empty. If $skipBinary is false then the actual value(s)
* of each BINARY property is recorded using Base64 encoding.
*
* If $noRecurse is true then only the node at $absPath and its properties, but not
* its child nodes, are serialized. If $noRecurse is false then the entire subgraph
* rooted at $absPath is serialized.
*
* If the user lacks read access to some subsection of the specified tree, that
* section simply does not get serialized, since, from the user's point of view,
* it is not there.
*
* The serialized output will reflect the state of the current workspace as
* modified by the state of this Session. This means that pending changes
* (regardless of whether they are valid according to node type constraints)
* and all namespace mappings in the namespace registry, as modified by the
* current session-mappings, are reflected in the output.
*
* The output XML will be encoded in UTF-8.
*
* @param string $absPath The path of the root of the subgraph to be serialized. This must be the path to a node, not a property
* @param string $out The URI to which the XML serialization of the subgraph will be output.
* @param boolean $skipBinary A boolean governing whether binary properties are to be serialized.
* @param boolean $noRecurse A boolean governing whether the subgraph at absPath is to be recursed.
* @return void
* @throws PHPCR_PathNotFoundException if no node exists at absPath.
* @throws RuntimeException if an error during an I/O operation occurs.
* @throws PHPCR_RepositoryException if another error occurs.
* @api
*/
public function exportSystemView($absPath, $out, $skipBinary, $noRecurse) {
throw new jackalope_NotImplementedException();
}
/**
* Serializes the node (and if $noRecurse is false, the whole subgraph) at
* $absPath as an XML stream and outputs it to the supplied URI. The
* resulting XML is in the document view form. Note that $absPath must be
* the path of a node, not a property.
*
* If $skipBinary is true then any properties of PropertyType.BINARY will be serialized as if
* they are empty. That is, the existence of the property will be serialized, but its content
* will not appear in the serialized output (the value of the attribute will be empty). If
* $skipBinary is false then the actual value(s) of each BINARY property is recorded using
* Base64 encoding.
*
* If $noRecurse is true then only the node at $absPath and its properties, but not its
* child nodes, are serialized. If $noRecurse is false then the entire subgraph rooted at
* $absPath is serialized.
*
* If the user lacks read access to some subsection of the specified tree, that section
* simply does not get serialized, since, from the user's point of view, it is not there.
*
* The serialized output will reflect the state of the current workspace as modified by
* the state of this Session. This means that pending changes (regardless of whether they
* are valid according to node type constraints) and all namespace mappings in the
* namespace registry, as modified by the current session-mappings, are reflected in
* the output.
*
* The output XML will be encoded in UTF-8.
*
* @param string $absPath The path of the root of the subgraph to be serialized. This must be the path to a node, not a property
* @param string $out The URI to which the XML serialization of the subgraph will be output.
* @param boolean $skipBinary A boolean governing whether binary properties are to be serialized.
* @param boolean $noRecurse A boolean governing whether the subgraph at absPath is to be recursed.
* @return void
* @throws PHPCR_PathNotFoundException if no node exists at absPath.
* @throws RuntimeException if an error during an I/O operation occurs.
* @throws PHPCR_RepositoryException if another error occurs.
* @api
*/
public function exportDocumentView($absPath, $out, $skipBinary, $noRecurse) {
throw new jackalope_NotImplementedException();
}
/**
* Within the scope of this Session, this method maps uri to prefix. The
* remapping only affects operations done through this Session. To clear
* all remappings, the client must acquire a new Session.
* All local mappings already present in the Session that include either
* the specified prefix or the specified uri are removed and the new mapping
* is added.
*
* @param string $prefix a string
* @param string $uri a string
* @return void
* @throws PHPCR_NamespaceException if an attempt is made to map a namespace URI to a prefix beginning with the characters "xml" (in any combination of case) or if an attempt is made to map either the empty prefix or the empty namespace (i.e., if either $prefix or $uri are the empty string).
* @throws PHPCR_RepositoryException if another error occurs.
* @api
*/
public function setNamespacePrefix($prefix, $uri) {
throw new jackalope_NotImplementedException();
}
/**
* Returns all prefixes currently mapped to URIs in this Session.
*
* @return array a string array
* @throws PHPCR_RepositoryException if an error occurs
* @api
*/
public function getNamespacePrefixes() {
throw new jackalope_NotImplementedException();
}
/**
* Returns the URI to which the given prefix is mapped as currently set in
* this Session.
*
* @param string $prefix a string
* @return string a string
* @throws PHPCR_NamespaceException if the specified prefix is unknown.
* @throws PHPCR_RepositoryException if another error occurs
* @api
*/
public function getNamespaceURI($prefix) {
throw new jackalope_NotImplementedException();
}
/**
* Returns the prefix to which the given uri is mapped as currently set in
* this Session.
*
* @param string $uri a string
* @return string a string
* @throws PHPCR_NamespaceException if the specified uri is unknown.
* @throws PHPCR_RepositoryException - if another error occurs
* @api
*/
public function getNamespacePrefix($uri) {
throw new jackalope_NotImplementedException();
}
/**
* Releases all resources associated with this Session. This method should
* be called when a Session is no longer needed.
*
* @return void
* @api
*/
public function logout() {
//TODO anything to do on logout?
//OPTIMIZATION: flush object manager
$this->logout = true;
}
/**
* Returns true if this Session object is usable by the client. Otherwise,
* returns false.
* A usable Session is one that is neither logged-out, timed-out nor in
* any other way disconnected from the repository.
*
* @return boolean true if this Session is usable, false otherwise.
* @api
*/
public function isLive() {
return ! $this->logout;
}
/**
* Returns the access control manager for this Session.
*
* @return PHPCR_Security_AccessControlManager the access control manager for this Session
* @throws PHPCR_UnsupportedRepositoryOperationException if access control is not supported.
* @throws PHPCR_RepositoryException if another error occurs.
* @api
*/
public function getAccessControlManager() {
throw new PHPCR_UnsupportedRepositoryOperationException();
}
/**
* Returns the retention and hold manager for this Session.
*
* @return PHPCR_Retention_RetentionManagerInterface the retention manager for this Session.
* @throws PHPCR_UnsupportedRepositoryOperationException if retention and hold are not supported.
* @throws PHPCR_RepositoryException if another error occurs.
* @api
*/
public function getRetentionManager() {
throw new PHPCR_UnsupportedRepositoryOperationException();
}
/**
* Implementation specific: The object manager is also used by other components, i.e. the QueryManager
*/
public function getObjectManager() {
return $this->objectManager;
}
/**
* Implementation specific: The transport implementation is also used by other components, i.e. the NamespaceRegistry
*/
public function getTransport() {
return $this->objectManager->getTransport();
}
}