|
1 <?php |
|
2 /** |
|
3 * Zend Framework |
|
4 * |
|
5 * LICENSE |
|
6 * |
|
7 * This source file is subject to the new BSD license that is bundled |
|
8 * with this package in the file LICENSE.txt. |
|
9 * It is also available through the world-wide-web at this URL: |
|
10 * http://framework.zend.com/license/new-bsd |
|
11 * If you did not receive a copy of the license and are unable to |
|
12 * obtain it through the world-wide-web, please send an email |
|
13 * to license@zend.com so we can send you a copy immediately. |
|
14 * |
|
15 * @category Zend |
|
16 * @package Zend_Ldap |
|
17 * @subpackage Node |
|
18 * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) |
|
19 * @license http://framework.zend.com/license/new-bsd New BSD License |
|
20 * @version $Id: Node.php 22662 2010-07-24 17:37:36Z mabe $ |
|
21 */ |
|
22 |
|
23 /** |
|
24 * @see Zend_Ldap |
|
25 */ |
|
26 require_once 'Zend/Ldap.php'; |
|
27 /** |
|
28 * @see Zend_Ldap_Node_Abstract |
|
29 */ |
|
30 require_once 'Zend/Ldap/Node/Abstract.php'; |
|
31 |
|
32 /** |
|
33 * Zend_Ldap_Node provides an object oriented view into a LDAP node. |
|
34 * |
|
35 * @category Zend |
|
36 * @package Zend_Ldap |
|
37 * @subpackage Node |
|
38 * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) |
|
39 * @license http://framework.zend.com/license/new-bsd New BSD License |
|
40 */ |
|
41 class Zend_Ldap_Node extends Zend_Ldap_Node_Abstract implements Iterator, RecursiveIterator |
|
42 { |
|
43 /** |
|
44 * Holds the node's new DN if node is renamed. |
|
45 * |
|
46 * @var Zend_Ldap_Dn |
|
47 */ |
|
48 protected $_newDn; |
|
49 /** |
|
50 * Holds the node's orginal attributes (as loaded). |
|
51 * |
|
52 * @var array |
|
53 */ |
|
54 protected $_originalData; |
|
55 /** |
|
56 * This node will be added |
|
57 * |
|
58 * @var boolean |
|
59 */ |
|
60 protected $_new; |
|
61 /** |
|
62 * This node will be deleted |
|
63 * |
|
64 * @var boolean |
|
65 */ |
|
66 protected $_delete; |
|
67 /** |
|
68 * Holds the connection to the LDAP server if in connected mode. |
|
69 * |
|
70 * @var Zend_Ldap |
|
71 */ |
|
72 protected $_ldap; |
|
73 |
|
74 /** |
|
75 * Holds an array of the current node's children. |
|
76 * |
|
77 * @var array |
|
78 */ |
|
79 protected $_children; |
|
80 |
|
81 /** |
|
82 * Controls iteration status |
|
83 * |
|
84 * @var boolean |
|
85 */ |
|
86 private $_iteratorRewind = false; |
|
87 |
|
88 /** |
|
89 * Constructor. |
|
90 * |
|
91 * Constructor is protected to enforce the use of factory methods. |
|
92 * |
|
93 * @param Zend_Ldap_Dn $dn |
|
94 * @param array $data |
|
95 * @param boolean $fromDataSource |
|
96 * @param Zend_Ldap $ldap |
|
97 * @throws Zend_Ldap_Exception |
|
98 */ |
|
99 protected function __construct(Zend_Ldap_Dn $dn, array $data, $fromDataSource, Zend_Ldap $ldap = null) |
|
100 { |
|
101 parent::__construct($dn, $data, $fromDataSource); |
|
102 if ($ldap !== null) $this->attachLdap($ldap); |
|
103 else $this->detachLdap(); |
|
104 } |
|
105 |
|
106 /** |
|
107 * Serialization callback |
|
108 * |
|
109 * Only DN and attributes will be serialized. |
|
110 * |
|
111 * @return array |
|
112 */ |
|
113 public function __sleep() |
|
114 { |
|
115 return array('_dn', '_currentData', '_newDn', '_originalData', |
|
116 '_new', '_delete', '_children'); |
|
117 } |
|
118 |
|
119 /** |
|
120 * Deserialization callback |
|
121 * |
|
122 * Enforces a detached node. |
|
123 * |
|
124 * @return null |
|
125 */ |
|
126 public function __wakeup() |
|
127 { |
|
128 $this->detachLdap(); |
|
129 } |
|
130 |
|
131 /** |
|
132 * Gets the current LDAP connection. |
|
133 * |
|
134 * @return Zend_Ldap |
|
135 * @throws Zend_Ldap_Exception |
|
136 */ |
|
137 public function getLdap() |
|
138 { |
|
139 if ($this->_ldap === null) { |
|
140 /** |
|
141 * @see Zend_Ldap_Exception |
|
142 */ |
|
143 require_once 'Zend/Ldap/Exception.php'; |
|
144 throw new Zend_Ldap_Exception(null, 'No LDAP connection specified.', Zend_Ldap_Exception::LDAP_OTHER); |
|
145 } |
|
146 else return $this->_ldap; |
|
147 } |
|
148 |
|
149 /** |
|
150 * Attach node to an LDAP connection |
|
151 * |
|
152 * This is an offline method. |
|
153 * |
|
154 * @uses Zend_Ldap_Dn::isChildOf() |
|
155 * @param Zend_Ldap $ldap |
|
156 * @return Zend_Ldap_Node Provides a fluid interface |
|
157 * @throws Zend_Ldap_Exception |
|
158 */ |
|
159 public function attachLdap(Zend_Ldap $ldap) |
|
160 { |
|
161 if (!Zend_Ldap_Dn::isChildOf($this->_getDn(), $ldap->getBaseDn())) { |
|
162 /** |
|
163 * @see Zend_Ldap_Exception |
|
164 */ |
|
165 require_once 'Zend/Ldap/Exception.php'; |
|
166 throw new Zend_Ldap_Exception(null, 'LDAP connection is not responsible for given node.', |
|
167 Zend_Ldap_Exception::LDAP_OTHER); |
|
168 } |
|
169 |
|
170 if ($ldap !== $this->_ldap) { |
|
171 $this->_ldap = $ldap; |
|
172 if (is_array($this->_children)) { |
|
173 foreach ($this->_children as $child) { |
|
174 $child->attachLdap($ldap); |
|
175 } |
|
176 } |
|
177 } |
|
178 return $this; |
|
179 } |
|
180 |
|
181 /** |
|
182 * Detach node from LDAP connection |
|
183 * |
|
184 * This is an offline method. |
|
185 * |
|
186 * @return Zend_Ldap_Node Provides a fluid interface |
|
187 */ |
|
188 public function detachLdap() |
|
189 { |
|
190 $this->_ldap = null; |
|
191 if (is_array($this->_children)) { |
|
192 foreach ($this->_children as $child) { |
|
193 $child->detachLdap(); |
|
194 } |
|
195 } |
|
196 return $this; |
|
197 } |
|
198 |
|
199 /** |
|
200 * Checks if the current node is attached to a LDAP server. |
|
201 * |
|
202 * This is an offline method. |
|
203 * |
|
204 * @return boolean |
|
205 */ |
|
206 public function isAttached() |
|
207 { |
|
208 return ($this->_ldap !== null); |
|
209 } |
|
210 |
|
211 /** |
|
212 * @param array $data |
|
213 * @param boolean $fromDataSource |
|
214 * @throws Zend_Ldap_Exception |
|
215 */ |
|
216 protected function _loadData(array $data, $fromDataSource) |
|
217 { |
|
218 parent::_loadData($data, $fromDataSource); |
|
219 if ($fromDataSource === true) { |
|
220 $this->_originalData = $data; |
|
221 } else { |
|
222 $this->_originalData = array(); |
|
223 } |
|
224 $this->_children = null; |
|
225 $this->_markAsNew(($fromDataSource === true) ? false : true); |
|
226 $this->_markAsToBeDeleted(false); |
|
227 } |
|
228 |
|
229 /** |
|
230 * Factory method to create a new detached Zend_Ldap_Node for a given DN. |
|
231 * |
|
232 * @param string|array|Zend_Ldap_Dn $dn |
|
233 * @param array $objectClass |
|
234 * @return Zend_Ldap_Node |
|
235 * @throws Zend_Ldap_Exception |
|
236 */ |
|
237 public static function create($dn, array $objectClass = array()) |
|
238 { |
|
239 if (is_string($dn) || is_array($dn)) { |
|
240 $dn = Zend_Ldap_Dn::factory($dn); |
|
241 } else if ($dn instanceof Zend_Ldap_Dn) { |
|
242 $dn = clone $dn; |
|
243 } else { |
|
244 /** |
|
245 * @see Zend_Ldap_Exception |
|
246 */ |
|
247 require_once 'Zend/Ldap/Exception.php'; |
|
248 throw new Zend_Ldap_Exception(null, '$dn is of a wrong data type.'); |
|
249 } |
|
250 $new = new self($dn, array(), false, null); |
|
251 $new->_ensureRdnAttributeValues(); |
|
252 $new->setAttribute('objectClass', $objectClass); |
|
253 return $new; |
|
254 } |
|
255 |
|
256 /** |
|
257 * Factory method to create an attached Zend_Ldap_Node for a given DN. |
|
258 * |
|
259 * @param string|array|Zend_Ldap_Dn $dn |
|
260 * @param Zend_Ldap $ldap |
|
261 * @return Zend_Ldap_Node|null |
|
262 * @throws Zend_Ldap_Exception |
|
263 */ |
|
264 public static function fromLdap($dn, Zend_Ldap $ldap) |
|
265 { |
|
266 if (is_string($dn) || is_array($dn)) { |
|
267 $dn = Zend_Ldap_Dn::factory($dn); |
|
268 } else if ($dn instanceof Zend_Ldap_Dn) { |
|
269 $dn = clone $dn; |
|
270 } else { |
|
271 /** |
|
272 * @see Zend_Ldap_Exception |
|
273 */ |
|
274 require_once 'Zend/Ldap/Exception.php'; |
|
275 throw new Zend_Ldap_Exception(null, '$dn is of a wrong data type.'); |
|
276 } |
|
277 $data = $ldap->getEntry($dn, array('*', '+'), true); |
|
278 if ($data === null) { |
|
279 return null; |
|
280 } |
|
281 $entry = new self($dn, $data, true, $ldap); |
|
282 return $entry; |
|
283 } |
|
284 |
|
285 /** |
|
286 * Factory method to create a detached Zend_Ldap_Node from array data. |
|
287 * |
|
288 * @param array $data |
|
289 * @param boolean $fromDataSource |
|
290 * @return Zend_Ldap_Node |
|
291 * @throws Zend_Ldap_Exception |
|
292 */ |
|
293 public static function fromArray(array $data, $fromDataSource = false) |
|
294 { |
|
295 if (!array_key_exists('dn', $data)) { |
|
296 /** |
|
297 * @see Zend_Ldap_Exception |
|
298 */ |
|
299 require_once 'Zend/Ldap/Exception.php'; |
|
300 throw new Zend_Ldap_Exception(null, '\'dn\' key is missing in array.'); |
|
301 } |
|
302 if (is_string($data['dn']) || is_array($data['dn'])) { |
|
303 $dn = Zend_Ldap_Dn::factory($data['dn']); |
|
304 } else if ($data['dn'] instanceof Zend_Ldap_Dn) { |
|
305 $dn = clone $data['dn']; |
|
306 } else { |
|
307 /** |
|
308 * @see Zend_Ldap_Exception |
|
309 */ |
|
310 require_once 'Zend/Ldap/Exception.php'; |
|
311 throw new Zend_Ldap_Exception(null, '\'dn\' key is of a wrong data type.'); |
|
312 } |
|
313 $fromDataSource = ($fromDataSource === true) ? true : false; |
|
314 $new = new self($dn, $data, $fromDataSource, null); |
|
315 $new->_ensureRdnAttributeValues(); |
|
316 return $new; |
|
317 } |
|
318 |
|
319 /** |
|
320 * Ensures that teh RDN attributes are correctly set. |
|
321 * |
|
322 * @return void |
|
323 */ |
|
324 protected function _ensureRdnAttributeValues() |
|
325 { |
|
326 foreach ($this->getRdnArray() as $key => $value) { |
|
327 Zend_Ldap_Attribute::setAttribute($this->_currentData, $key, $value, false); |
|
328 } |
|
329 } |
|
330 |
|
331 /** |
|
332 * Marks this node as new. |
|
333 * |
|
334 * Node will be added (instead of updated) on calling update() if $new is true. |
|
335 * |
|
336 * @param boolean $new |
|
337 */ |
|
338 protected function _markAsNew($new) |
|
339 { |
|
340 $this->_new = ($new === false) ? false : true; |
|
341 } |
|
342 |
|
343 /** |
|
344 * Tells if the node is consiedered as new (not present on the server) |
|
345 * |
|
346 * Please note, that this doesn't tell you if the node is present on the server. |
|
347 * Use {@link exits()} to see if a node is already there. |
|
348 * |
|
349 * @return boolean |
|
350 */ |
|
351 public function isNew() |
|
352 { |
|
353 return $this->_new; |
|
354 } |
|
355 |
|
356 /** |
|
357 * Marks this node as to be deleted. |
|
358 * |
|
359 * Node will be deleted on calling update() if $delete is true. |
|
360 * |
|
361 * @param boolean $delete |
|
362 */ |
|
363 protected function _markAsToBeDeleted($delete) |
|
364 { |
|
365 $this->_delete = ($delete === true) ? true : false; |
|
366 } |
|
367 |
|
368 |
|
369 /** |
|
370 * Is this node going to be deleted once update() is called? |
|
371 * |
|
372 * @return boolean |
|
373 */ |
|
374 public function willBeDeleted() |
|
375 { |
|
376 return $this->_delete; |
|
377 } |
|
378 |
|
379 /** |
|
380 * Marks this node as to be deleted |
|
381 * |
|
382 * Node will be deleted on calling update() if $delete is true. |
|
383 * |
|
384 * @return Zend_Ldap_Node Provides a fluid interface |
|
385 */ |
|
386 public function delete() |
|
387 { |
|
388 $this->_markAsToBeDeleted(true); |
|
389 return $this; |
|
390 } |
|
391 |
|
392 /** |
|
393 * Is this node going to be moved once update() is called? |
|
394 * |
|
395 * @return boolean |
|
396 */ |
|
397 public function willBeMoved() |
|
398 { |
|
399 if ($this->isNew() || $this->willBeDeleted()) { |
|
400 return false; |
|
401 } else if ($this->_newDn !== null) { |
|
402 return ($this->_dn != $this->_newDn); |
|
403 } else { |
|
404 return false; |
|
405 } |
|
406 } |
|
407 |
|
408 /** |
|
409 * Sends all pending changes to the LDAP server |
|
410 * |
|
411 * @param Zend_Ldap $ldap |
|
412 * @return Zend_Ldap_Node Provides a fluid interface |
|
413 * @throws Zend_Ldap_Exception |
|
414 */ |
|
415 public function update(Zend_Ldap $ldap = null) |
|
416 { |
|
417 if ($ldap !== null) { |
|
418 $this->attachLdap($ldap); |
|
419 } |
|
420 $ldap = $this->getLdap(); |
|
421 if (!($ldap instanceof Zend_Ldap)) { |
|
422 /** |
|
423 * @see Zend_Ldap_Exception |
|
424 */ |
|
425 require_once 'Zend/Ldap/Exception.php'; |
|
426 throw new Zend_Ldap_Exception(null, 'No LDAP connection available'); |
|
427 } |
|
428 |
|
429 if ($this->willBeDeleted()) { |
|
430 if ($ldap->exists($this->_dn)) { |
|
431 $ldap->delete($this->_dn); |
|
432 } |
|
433 return $this; |
|
434 } |
|
435 |
|
436 if ($this->isNew()) { |
|
437 $data = $this->getData(); |
|
438 $ldap->add($this->_getDn(), $data); |
|
439 $this->_loadData($data, true); |
|
440 return $this; |
|
441 } |
|
442 |
|
443 $changedData = $this->getChangedData(); |
|
444 if ($this->willBeMoved()) { |
|
445 $recursive = $this->hasChildren(); |
|
446 $ldap->rename($this->_dn, $this->_newDn, $recursive, false); |
|
447 foreach ($this->_newDn->getRdn() as $key => $value) { |
|
448 if (array_key_exists($key, $changedData)) { |
|
449 unset($changedData[$key]); |
|
450 } |
|
451 } |
|
452 $this->_dn = $this->_newDn; |
|
453 $this->_newDn = null; |
|
454 } |
|
455 if (count($changedData) > 0) { |
|
456 $ldap->update($this->_getDn(), $changedData); |
|
457 } |
|
458 $this->_originalData = $this->_currentData; |
|
459 return $this; |
|
460 } |
|
461 |
|
462 /** |
|
463 * Gets the DN of the current node as a Zend_Ldap_Dn. |
|
464 * |
|
465 * This is an offline method. |
|
466 * |
|
467 * @return Zend_Ldap_Dn |
|
468 */ |
|
469 protected function _getDn() |
|
470 { |
|
471 return ($this->_newDn === null) ? parent::_getDn() : $this->_newDn; |
|
472 } |
|
473 |
|
474 /** |
|
475 * Gets the current DN of the current node as a Zend_Ldap_Dn. |
|
476 * The method returns a clone of the node's DN to prohibit modification. |
|
477 * |
|
478 * This is an offline method. |
|
479 * |
|
480 * @return Zend_Ldap_Dn |
|
481 */ |
|
482 public function getCurrentDn() |
|
483 { |
|
484 $dn = clone parent::_getDn(); |
|
485 return $dn; |
|
486 } |
|
487 |
|
488 /** |
|
489 * Sets the new DN for this node |
|
490 * |
|
491 * This is an offline method. |
|
492 * |
|
493 * @param Zend_Ldap_Dn|string|array $newDn |
|
494 * @throws Zend_Ldap_Exception |
|
495 * @return Zend_Ldap_Node Provides a fluid interface |
|
496 */ |
|
497 public function setDn($newDn) |
|
498 { |
|
499 if ($newDn instanceof Zend_Ldap_Dn) { |
|
500 $this->_newDn = clone $newDn; |
|
501 } else { |
|
502 $this->_newDn = Zend_Ldap_Dn::factory($newDn); |
|
503 } |
|
504 $this->_ensureRdnAttributeValues(); |
|
505 return $this; |
|
506 } |
|
507 |
|
508 /** |
|
509 * {@see setDn()} |
|
510 * |
|
511 * This is an offline method. |
|
512 * |
|
513 * @param Zend_Ldap_Dn|string|array $newDn |
|
514 * @throws Zend_Ldap_Exception |
|
515 * @return Zend_Ldap_Node Provides a fluid interface |
|
516 */ |
|
517 public function move($newDn) |
|
518 { |
|
519 return $this->setDn($newDn); |
|
520 } |
|
521 |
|
522 /** |
|
523 * {@see setDn()} |
|
524 * |
|
525 * This is an offline method. |
|
526 * |
|
527 * @param Zend_Ldap_Dn|string|array $newDn |
|
528 * @throws Zend_Ldap_Exception |
|
529 * @return Zend_Ldap_Node Provides a fluid interface |
|
530 */ |
|
531 public function rename($newDn) |
|
532 { |
|
533 return $this->setDn($newDn); |
|
534 } |
|
535 |
|
536 /** |
|
537 * Sets the objectClass. |
|
538 * |
|
539 * This is an offline method. |
|
540 * |
|
541 * @param array|string $value |
|
542 * @return Zend_Ldap_Node Provides a fluid interface |
|
543 * @throws Zend_Ldap_Exception |
|
544 */ |
|
545 public function setObjectClass($value) |
|
546 { |
|
547 $this->setAttribute('objectClass', $value); |
|
548 return $this; |
|
549 } |
|
550 |
|
551 /** |
|
552 * Appends to the objectClass. |
|
553 * |
|
554 * This is an offline method. |
|
555 * |
|
556 * @param array|string $value |
|
557 * @return Zend_Ldap_Node Provides a fluid interface |
|
558 * @throws Zend_Ldap_Exception |
|
559 */ |
|
560 public function appendObjectClass($value) |
|
561 { |
|
562 $this->appendToAttribute('objectClass', $value); |
|
563 return $this; |
|
564 } |
|
565 |
|
566 /** |
|
567 * Returns a LDIF representation of the current node |
|
568 * |
|
569 * @param array $options Additional options used during encoding |
|
570 * @return string |
|
571 */ |
|
572 public function toLdif(array $options = array()) |
|
573 { |
|
574 $attributes = array_merge(array('dn' => $this->getDnString()), $this->getData(false)); |
|
575 /** |
|
576 * Zend_Ldap_Ldif_Encoder |
|
577 */ |
|
578 require_once 'Zend/Ldap/Ldif/Encoder.php'; |
|
579 return Zend_Ldap_Ldif_Encoder::encode($attributes, $options); |
|
580 } |
|
581 |
|
582 /** |
|
583 * Gets changed node data. |
|
584 * |
|
585 * The array contains all changed attributes. |
|
586 * This format can be used in {@link Zend_Ldap::add()} and {@link Zend_Ldap::update()}. |
|
587 * |
|
588 * This is an offline method. |
|
589 * |
|
590 * @return array |
|
591 */ |
|
592 public function getChangedData() |
|
593 { |
|
594 $changed = array(); |
|
595 foreach ($this->_currentData as $key => $value) { |
|
596 if (!array_key_exists($key, $this->_originalData) && !empty($value)) { |
|
597 $changed[$key] = $value; |
|
598 } else if ($this->_originalData[$key] !== $this->_currentData[$key]) { |
|
599 $changed[$key] = $value; |
|
600 } |
|
601 } |
|
602 return $changed; |
|
603 } |
|
604 |
|
605 /** |
|
606 * Returns all changes made. |
|
607 * |
|
608 * This is an offline method. |
|
609 * |
|
610 * @return array |
|
611 */ |
|
612 public function getChanges() |
|
613 { |
|
614 $changes = array( |
|
615 'add' => array(), |
|
616 'delete' => array(), |
|
617 'replace' => array()); |
|
618 foreach ($this->_currentData as $key => $value) { |
|
619 if (!array_key_exists($key, $this->_originalData) && !empty($value)) { |
|
620 $changes['add'][$key] = $value; |
|
621 } else if (count($this->_originalData[$key]) === 0 && !empty($value)) { |
|
622 $changes['add'][$key] = $value; |
|
623 } else if ($this->_originalData[$key] !== $this->_currentData[$key]) { |
|
624 if (empty($value)) { |
|
625 $changes['delete'][$key] = $value; |
|
626 } else { |
|
627 $changes['replace'][$key] = $value; |
|
628 } |
|
629 } |
|
630 } |
|
631 return $changes; |
|
632 } |
|
633 |
|
634 /** |
|
635 * Sets a LDAP attribute. |
|
636 * |
|
637 * This is an offline method. |
|
638 * |
|
639 * @param string $name |
|
640 * @param mixed $value |
|
641 * @return Zend_Ldap_Node Provides a fluid interface |
|
642 * @throws Zend_Ldap_Exception |
|
643 */ |
|
644 public function setAttribute($name, $value) |
|
645 { |
|
646 $this->_setAttribute($name, $value, false); |
|
647 return $this; |
|
648 } |
|
649 |
|
650 /** |
|
651 * Appends to a LDAP attribute. |
|
652 * |
|
653 * This is an offline method. |
|
654 * |
|
655 * @param string $name |
|
656 * @param mixed $value |
|
657 * @return Zend_Ldap_Node Provides a fluid interface |
|
658 * @throws Zend_Ldap_Exception |
|
659 */ |
|
660 public function appendToAttribute($name, $value) |
|
661 { |
|
662 $this->_setAttribute($name, $value, true); |
|
663 return $this; |
|
664 } |
|
665 |
|
666 /** |
|
667 * Checks if the attribute can be set and sets it accordingly. |
|
668 * |
|
669 * @param string $name |
|
670 * @param mixed $value |
|
671 * @param boolean $append |
|
672 * @throws Zend_Ldap_Exception |
|
673 */ |
|
674 protected function _setAttribute($name, $value, $append) |
|
675 { |
|
676 $this->_assertChangeableAttribute($name); |
|
677 Zend_Ldap_Attribute::setAttribute($this->_currentData, $name, $value, $append); |
|
678 } |
|
679 |
|
680 /** |
|
681 * Sets a LDAP date/time attribute. |
|
682 * |
|
683 * This is an offline method. |
|
684 * |
|
685 * @param string $name |
|
686 * @param integer|array $value |
|
687 * @param boolean $utc |
|
688 * @return Zend_Ldap_Node Provides a fluid interface |
|
689 * @throws Zend_Ldap_Exception |
|
690 */ |
|
691 public function setDateTimeAttribute($name, $value, $utc = false) |
|
692 { |
|
693 $this->_setDateTimeAttribute($name, $value, $utc, false); |
|
694 return $this; |
|
695 } |
|
696 |
|
697 /** |
|
698 * Appends to a LDAP date/time attribute. |
|
699 * |
|
700 * This is an offline method. |
|
701 * |
|
702 * @param string $name |
|
703 * @param integer|array $value |
|
704 * @param boolean $utc |
|
705 * @return Zend_Ldap_Node Provides a fluid interface |
|
706 * @throws Zend_Ldap_Exception |
|
707 */ |
|
708 public function appendToDateTimeAttribute($name, $value, $utc = false) |
|
709 { |
|
710 $this->_setDateTimeAttribute($name, $value, $utc, true); |
|
711 return $this; |
|
712 } |
|
713 |
|
714 /** |
|
715 * Checks if the attribute can be set and sets it accordingly. |
|
716 * |
|
717 * @param string $name |
|
718 * @param integer|array $value |
|
719 * @param boolean $utc |
|
720 * @param boolean $append |
|
721 * @throws Zend_Ldap_Exception |
|
722 */ |
|
723 protected function _setDateTimeAttribute($name, $value, $utc, $append) |
|
724 { |
|
725 $this->_assertChangeableAttribute($name); |
|
726 Zend_Ldap_Attribute::setDateTimeAttribute($this->_currentData, $name, $value, $utc, $append); |
|
727 } |
|
728 |
|
729 /** |
|
730 * Sets a LDAP password. |
|
731 * |
|
732 * @param string $password |
|
733 * @param string $hashType |
|
734 * @param string $attribName |
|
735 * @return Zend_Ldap_Node Provides a fluid interface |
|
736 * @throws Zend_Ldap_Exception |
|
737 */ |
|
738 public function setPasswordAttribute($password, $hashType = Zend_Ldap_Attribute::PASSWORD_HASH_MD5, |
|
739 $attribName = 'userPassword') |
|
740 { |
|
741 $this->_assertChangeableAttribute($attribName); |
|
742 Zend_Ldap_Attribute::setPassword($this->_currentData, $password, $hashType, $attribName); |
|
743 return $this; |
|
744 } |
|
745 |
|
746 /** |
|
747 * Deletes a LDAP attribute. |
|
748 * |
|
749 * This method deletes the attribute. |
|
750 * |
|
751 * This is an offline method. |
|
752 * |
|
753 * @param string $name |
|
754 * @return Zend_Ldap_Node Provides a fluid interface |
|
755 * @throws Zend_Ldap_Exception |
|
756 */ |
|
757 public function deleteAttribute($name) |
|
758 { |
|
759 if ($this->existsAttribute($name, true)) { |
|
760 $this->_setAttribute($name, null, false); |
|
761 } |
|
762 return $this; |
|
763 } |
|
764 |
|
765 /** |
|
766 * Removes duplicate values from a LDAP attribute |
|
767 * |
|
768 * @param string $attribName |
|
769 * @return void |
|
770 */ |
|
771 public function removeDuplicatesFromAttribute($attribName) |
|
772 { |
|
773 Zend_Ldap_Attribute::removeDuplicatesFromAttribute($this->_currentData, $attribName); |
|
774 } |
|
775 |
|
776 /** |
|
777 * Remove given values from a LDAP attribute |
|
778 * |
|
779 * @param string $attribName |
|
780 * @param mixed|array $value |
|
781 * @return void |
|
782 */ |
|
783 public function removeFromAttribute($attribName, $value) |
|
784 { |
|
785 Zend_Ldap_Attribute::removeFromAttribute($this->_currentData, $attribName, $value); |
|
786 } |
|
787 |
|
788 /** |
|
789 * @param string $name |
|
790 * @return boolean |
|
791 * @throws Zend_Ldap_Exception |
|
792 */ |
|
793 protected function _assertChangeableAttribute($name) |
|
794 { |
|
795 $name = strtolower($name); |
|
796 $rdn = $this->getRdnArray(Zend_Ldap_Dn::ATTR_CASEFOLD_LOWER); |
|
797 if ($name == 'dn') { |
|
798 /** |
|
799 * @see Zend_Ldap_Exception |
|
800 */ |
|
801 require_once 'Zend/Ldap/Exception.php'; |
|
802 throw new Zend_Ldap_Exception(null, 'DN cannot be changed.'); |
|
803 } |
|
804 else if (array_key_exists($name, $rdn)) { |
|
805 /** |
|
806 * @see Zend_Ldap_Exception |
|
807 */ |
|
808 require_once 'Zend/Ldap/Exception.php'; |
|
809 throw new Zend_Ldap_Exception(null, 'Cannot change attribute because it\'s part of the RDN'); |
|
810 } else if (in_array($name, self::$_systemAttributes)) { |
|
811 /** |
|
812 * @see Zend_Ldap_Exception |
|
813 */ |
|
814 require_once 'Zend/Ldap/Exception.php'; |
|
815 throw new Zend_Ldap_Exception(null, 'Cannot change attribute because it\'s read-only'); |
|
816 } |
|
817 else return true; |
|
818 } |
|
819 |
|
820 /** |
|
821 * Sets a LDAP attribute. |
|
822 * |
|
823 * This is an offline method. |
|
824 * |
|
825 * @param string $name |
|
826 * @param mixed $value |
|
827 * @return null |
|
828 * @throws Zend_Ldap_Exception |
|
829 */ |
|
830 public function __set($name, $value) |
|
831 { |
|
832 $this->setAttribute($name, $value); |
|
833 } |
|
834 |
|
835 /** |
|
836 * Deletes a LDAP attribute. |
|
837 * |
|
838 * This method deletes the attribute. |
|
839 * |
|
840 * This is an offline method. |
|
841 * |
|
842 * @param string $name |
|
843 * @return null |
|
844 * @throws Zend_Ldap_Exception |
|
845 */ |
|
846 public function __unset($name) |
|
847 { |
|
848 $this->deleteAttribute($name); |
|
849 } |
|
850 |
|
851 /** |
|
852 * Sets a LDAP attribute. |
|
853 * Implements ArrayAccess. |
|
854 * |
|
855 * This is an offline method. |
|
856 * |
|
857 * @param string $name |
|
858 * @param mixed $value |
|
859 * @return null |
|
860 * @throws Zend_Ldap_Exception |
|
861 */ |
|
862 public function offsetSet($name, $value) |
|
863 { |
|
864 $this->setAttribute($name, $value); |
|
865 } |
|
866 |
|
867 /** |
|
868 * Deletes a LDAP attribute. |
|
869 * Implements ArrayAccess. |
|
870 * |
|
871 * This method deletes the attribute. |
|
872 * |
|
873 * This is an offline method. |
|
874 * |
|
875 * @param string $name |
|
876 * @return null |
|
877 * @throws Zend_Ldap_Exception |
|
878 */ |
|
879 public function offsetUnset($name) |
|
880 { |
|
881 $this->deleteAttribute($name); |
|
882 } |
|
883 |
|
884 /** |
|
885 * Check if node exists on LDAP. |
|
886 * |
|
887 * This is an online method. |
|
888 * |
|
889 * @param Zend_Ldap $ldap |
|
890 * @return boolean |
|
891 * @throws Zend_Ldap_Exception |
|
892 */ |
|
893 public function exists(Zend_Ldap $ldap = null) |
|
894 { |
|
895 if ($ldap !== null) { |
|
896 $this->attachLdap($ldap); |
|
897 } |
|
898 $ldap = $this->getLdap(); |
|
899 return $ldap->exists($this->_getDn()); |
|
900 } |
|
901 |
|
902 /** |
|
903 * Reload node attributes from LDAP. |
|
904 * |
|
905 * This is an online method. |
|
906 * |
|
907 * @param Zend_Ldap $ldap |
|
908 * @return Zend_Ldap_Node Provides a fluid interface |
|
909 * @throws Zend_Ldap_Exception |
|
910 */ |
|
911 public function reload(Zend_Ldap $ldap = null) |
|
912 { |
|
913 if ($ldap !== null) { |
|
914 $this->attachLdap($ldap); |
|
915 } |
|
916 $ldap = $this->getLdap(); |
|
917 parent::reload($ldap); |
|
918 return $this; |
|
919 } |
|
920 |
|
921 /** |
|
922 * Search current subtree with given options. |
|
923 * |
|
924 * This is an online method. |
|
925 * |
|
926 * @param string|Zend_Ldap_Filter_Abstract $filter |
|
927 * @param integer $scope |
|
928 * @param string $sort |
|
929 * @return Zend_Ldap_Node_Collection |
|
930 * @throws Zend_Ldap_Exception |
|
931 */ |
|
932 public function searchSubtree($filter, $scope = Zend_Ldap::SEARCH_SCOPE_SUB, $sort = null) |
|
933 { |
|
934 /** |
|
935 * @see Zend_Ldap_Node_Collection |
|
936 */ |
|
937 require_once 'Zend/Ldap/Node/Collection.php'; |
|
938 return $this->getLdap()->search($filter, $this->_getDn(), $scope, array('*', '+'), $sort, |
|
939 'Zend_Ldap_Node_Collection'); |
|
940 } |
|
941 |
|
942 /** |
|
943 * Count items in current subtree found by given filter. |
|
944 * |
|
945 * This is an online method. |
|
946 * |
|
947 * @param string|Zend_Ldap_Filter_Abstract $filter |
|
948 * @param integer $scope |
|
949 * @return integer |
|
950 * @throws Zend_Ldap_Exception |
|
951 */ |
|
952 public function countSubtree($filter, $scope = Zend_Ldap::SEARCH_SCOPE_SUB) |
|
953 { |
|
954 return $this->getLdap()->count($filter, $this->_getDn(), $scope); |
|
955 } |
|
956 |
|
957 /** |
|
958 * Count children of current node. |
|
959 * |
|
960 * This is an online method. |
|
961 * |
|
962 * @return integer |
|
963 * @throws Zend_Ldap_Exception |
|
964 */ |
|
965 public function countChildren() |
|
966 { |
|
967 return $this->countSubtree('(objectClass=*)', Zend_Ldap::SEARCH_SCOPE_ONE); |
|
968 } |
|
969 |
|
970 /** |
|
971 * Gets children of current node. |
|
972 * |
|
973 * This is an online method. |
|
974 * |
|
975 * @param string|Zend_Ldap_Filter_Abstract $filter |
|
976 * @param string $sort |
|
977 * @return Zend_Ldap_Node_Collection |
|
978 * @throws Zend_Ldap_Exception |
|
979 */ |
|
980 public function searchChildren($filter, $sort = null) |
|
981 { |
|
982 return $this->searchSubtree($filter, Zend_Ldap::SEARCH_SCOPE_ONE, $sort); |
|
983 } |
|
984 |
|
985 /** |
|
986 * Checks if current node has children. |
|
987 * Returns whether the current element has children. |
|
988 * |
|
989 * Can be used offline but returns false if children have not been retrieved yet. |
|
990 * |
|
991 * @return boolean |
|
992 * @throws Zend_Ldap_Exception |
|
993 */ |
|
994 public function hasChildren() |
|
995 { |
|
996 if (!is_array($this->_children)) { |
|
997 if ($this->isAttached()) { |
|
998 return ($this->countChildren() > 0); |
|
999 } else { |
|
1000 return false; |
|
1001 } |
|
1002 } else { |
|
1003 return (count($this->_children) > 0); |
|
1004 } |
|
1005 } |
|
1006 |
|
1007 /** |
|
1008 * Returns the children for the current node. |
|
1009 * |
|
1010 * Can be used offline but returns an empty array if children have not been retrieved yet. |
|
1011 * |
|
1012 * @return Zend_Ldap_Node_ChildrenIterator |
|
1013 * @throws Zend_Ldap_Exception |
|
1014 */ |
|
1015 public function getChildren() |
|
1016 { |
|
1017 if (!is_array($this->_children)) { |
|
1018 $this->_children = array(); |
|
1019 if ($this->isAttached()) { |
|
1020 $children = $this->searchChildren('(objectClass=*)', null); |
|
1021 foreach ($children as $child) { |
|
1022 $this->_children[$child->getRdnString(Zend_Ldap_Dn::ATTR_CASEFOLD_LOWER)] = $child; |
|
1023 } |
|
1024 } |
|
1025 } |
|
1026 /** |
|
1027 * @see Zend_Ldap_Node_ChildrenIterator |
|
1028 */ |
|
1029 require_once 'Zend/Ldap/Node/ChildrenIterator.php'; |
|
1030 return new Zend_Ldap_Node_ChildrenIterator($this->_children); |
|
1031 } |
|
1032 |
|
1033 /** |
|
1034 * Returns the parent of the current node. |
|
1035 * |
|
1036 * @param Zend_Ldap $ldap |
|
1037 * @return Zend_Ldap_Node |
|
1038 * @throws Zend_Ldap_Exception |
|
1039 */ |
|
1040 public function getParent(Zend_Ldap $ldap = null) |
|
1041 { |
|
1042 if ($ldap !== null) { |
|
1043 $this->attachLdap($ldap); |
|
1044 } |
|
1045 $ldap = $this->getLdap(); |
|
1046 $parentDn = $this->_getDn()->getParentDn(1); |
|
1047 return self::fromLdap($parentDn, $ldap); |
|
1048 } |
|
1049 |
|
1050 /** |
|
1051 * Return the current attribute. |
|
1052 * Implements Iterator |
|
1053 * |
|
1054 * @return array |
|
1055 */ |
|
1056 public function current() |
|
1057 { |
|
1058 return $this; |
|
1059 } |
|
1060 |
|
1061 /** |
|
1062 * Return the attribute name. |
|
1063 * Implements Iterator |
|
1064 * |
|
1065 * @return string |
|
1066 */ |
|
1067 public function key() |
|
1068 { |
|
1069 return $this->getRdnString(); |
|
1070 } |
|
1071 |
|
1072 /** |
|
1073 * Move forward to next attribute. |
|
1074 * Implements Iterator |
|
1075 */ |
|
1076 public function next() |
|
1077 { |
|
1078 $this->_iteratorRewind = false; |
|
1079 } |
|
1080 |
|
1081 /** |
|
1082 * Rewind the Iterator to the first attribute. |
|
1083 * Implements Iterator |
|
1084 */ |
|
1085 public function rewind() |
|
1086 { |
|
1087 $this->_iteratorRewind = true; |
|
1088 } |
|
1089 |
|
1090 /** |
|
1091 * Check if there is a current attribute |
|
1092 * after calls to rewind() or next(). |
|
1093 * Implements Iterator |
|
1094 * |
|
1095 * @return boolean |
|
1096 */ |
|
1097 public function valid() |
|
1098 { |
|
1099 return $this->_iteratorRewind; |
|
1100 } |
|
1101 } |