public function testCaseSensitivity() { $node = new Node(null, true); $node->get('A', true)->add(array('upper')); $node->get('a', true)->add(array('lower')); $this->assertArraySubset(['upper'], $node->get('A')->getValues()); $this->assertArraySubset(['lower'], $node->get('a')->getValues()); $this->assertTrue($node->has('A')); $this->assertTrue($node->has('a')); $node->removeAttribute('a'); $this->assertArraySubset(['upper'], $node->get('A')->getValues()); $this->assertEmpty($node->get('a')); // default is no case sensitivity $node = new Node(); $node->get('A', true)->add(array('upper')); $node->get('a', true)->add(array('lower')); // both will be lower $this->assertArraySubset(['upper', 'lower'], $node->get('A')->getValues()); $this->assertArraySubset(['upper', 'lower'], $node->get('a')->getValues()); $node->removeAttribute('A'); $this->assertFalse($node->has('A')); $this->assertFalse($node->has('a')); }
/** * _newNode($node). */ protected function _newNode($dn = false) { try { if (!$this->tiesaManagerClass) { $this->_autentication(); } $node = $this->_getNode($dn); if ($node) { $node->tracker->markOverridden(); return $node; } else { $node = new Core\Node(); $node->setDn($dn); $node->tracker->markOverridden(); return $node; } } catch (\Exception $e) { $this->ldapError = $e; return false; } }
/** * Rebase diff based on source node as an origin * * @param Node $node Node to use as a source for origin * * @return void * * @throws RebaseException If source of origin node has uncommitted changes */ public function rebaseDiff(Node $node) { $changes = array_merge($node->getDiffAdditions(), $node->getDiffDeletions(), $node->getDiffReplacements()); if (count($changes) > 0) { throw new RebaseException(sprintf('%s has some uncommitted changes - Cannot rebase %s on %s', $node->getDn(), $this->getDn(), $node->getDn())); } $additions = $this->getDiffAdditions(); $deletions = $this->getDiffDeletions(); $replacements = $this->getDiffReplacements(); $this->snapshot(); $this->attributes = $node->getAttributes(); foreach ($additions as $attribute => $values) { $this->get($attribute, true)->add($values); } foreach ($deletions as $attribute => $values) { if (count($values) == 0) { $this->removeAttribute($attribute); continue; } if ($this->has($attribute)) { $this->get($attribute)->remove($values); } } foreach ($replacements as $attribute => $values) { $this->get($attribute, true)->set($values); } }
/** * Retrieve children Ldap nodes * * @return void */ public function testGetChildren() { $manager = new Manager($this->minimal, $this->driver); $node = new Node(); $node->setDn('test_node'); $set = array(); $set[] = new Entry('ent1', array('val1')); $set[] = new Entry('ent2', array('val2')); $set[] = new Entry('ent3', array('val3')); // Binding exception handling $this->assertBindingFirst($manager, 'getChildrenNodes', array($node)); $manager->connect(); $this->assertBindingFirst($manager, 'getChildrenNodes', array($node)); $manager->bind(); // Basic behaviour $this->driver->getConnection()->stackResults($set); $nodes = $manager->getChildrenNodes($node); $this->assertSearchLog($this->driver->getConnection()->shiftLog(), 'test_node', '(objectclass=*)', SearchInterface::SCOPE_ONE, null, $set); $this->assertNull($this->driver->getConnection()->shiftLog(), 'No other log'); $this->assertTrue(is_array($nodes), 'An array of nodes is retrieved'); $this->assertCount(3, $nodes); $this->assertEquals('ent1', $nodes[0]->getDn()); $this->assertEquals('ent2', $nodes[1]->getDn()); $this->assertEquals('ent3', $nodes[2]->getDn()); // Successful search with no entry in the result set $nodes = $manager->getChildrenNodes($node); $this->assertSearchLog($this->driver->getConnection()->shiftLog(), 'test_node', '(objectclass=*)', SearchInterface::SCOPE_ONE); $this->assertNull($this->driver->getConnection()->shiftLog(), 'No other log'); $this->assertTrue(is_array($nodes), 'An array of nodes is retrieved'); $this->assertCount(0, $nodes); // Handling of NoResultException $this->driver->getConnection()->setFailure(Connection::ERR_NO_RESULT); $nodes = $manager->getChildrenNodes($node); $this->assertTrue(is_array($nodes), 'An array of nodes is retrieved'); $this->assertCount(0, $nodes); // Handling of other search exceptions $this->driver->getConnection()->setFailure(); try { $nodes = $manager->getChildrenNodes($node); $this->fail('Other search exceptions do not get processed and are populated'); } catch (SearchException $e) { $this->assertRegExp('/Search failed/', $e->getMessage()); } }
/** * Deletes a node from the Ldap store * * @param Node $node Node to delete * @param boolean $isRecursive Whether to delete node with its children (Default: false) * * @return void * * @throws DeletionException If node to delete has some children and recursion disabled */ public function delete(Node $node, $isRecursive = false) { if (!$node->isHydrated()) { $node = $this->getNode($node->getDn()); } $children = $this->getChildrenNodes($node); if (count($children) > 0) { if (!$isRecursive) { throw new DeleteException(sprintf('%s cannot be deleted - it has some children left', $node->getDn())); } foreach ($children as $child) { $this->delete($child, true); } } $this->connection->deleteEntry($node->getDn()); }
/** * Tests rebasing a node changes on an existing node * * @return void */ public function testRebaseDiff() { $rebasedNode = new Node(); $rebasedNode->setDn('rebased'); $rebasedNode->get('a', true)->add(array('a2', 'a4')); $rebasedNode->get('b', true)->add(array('b1', 'b3')); $rebasedNode->get('c', true)->add(array('c1', 'c3')); $rebasedNode->get('d', true)->add(array('d1', 'd2', 'd3', 'd4')); $rebasedNode->get('g', true)->add('g1'); $rebasedNode->get('h', true)->add(array('h1', 'h2')); $rebasedNode->get('i', true)->add(array('i1', 'i2')); $rebasedNode->snapshot(); $rebasedNode->get('a')->add(array('a1', 'a3')); $rebasedNode->removeAttribute('b'); $rebasedNode->get('c')->set(array('c4', 'c5')); $rebasedNode->get('d')->remove('d2'); $rebasedNode->get('d')->remove('d3'); $rebasedNode->get('d')->add('d5'); $rebasedNode->get('f', true)->add(array('f1', 'f2')); $rebasedNode->removeAttribute('g'); $rebasedNode->get('h')->set(array('h1', 'h3')); $rebasedNode->get('i')->remove('i2'); $this->assertEquals(array('a' => array('a2', 'a4', 'a1', 'a3'), 'c' => array('c4', 'c5'), 'd' => array(0 => 'd1', 3 => 'd4', 4 => 'd5'), 'f' => array('f1', 'f2'), 'h' => array('h1', 'h3'), 'i' => array('i1')), $rebasedNode->getRawAttributes(), 'All attributes according to plan'); $this->assertEquals(array('a' => array('a1', 'a3'), 'd' => array('d5'), 'f' => array('f1', 'f2')), $rebasedNode->getDiffAdditions(), 'Regular additions tracking'); $this->assertEquals(array('b' => array(), 'd' => array('d2', 'd3'), 'g' => array(), 'i' => array('i2')), $rebasedNode->getDiffDeletions(), 'Regular deletions tracking'); $this->assertEquals(array('c' => array('c4', 'c5'), 'h' => array('h1', 'h3')), $rebasedNode->getDiffReplacements(), 'Regular replacements tracking'); $origNode = new Node(); $origNode->setDn('origin'); $origNode->get('a', true)->add(array('a1', 'a2')); $origNode->get('b', true)->add(array('b1', 'b2')); $origNode->get('c', true)->add(array('c1', 'c2')); $origNode->get('d', true)->add(array('d1', 'd2')); $origNode->get('e', true)->add(array('e1', 'e2')); try { $rebasedNode->rebaseDiff($origNode); $this->fail('Cannot rebase on a node which is not snapshot'); } catch (RebaseException $e) { $this->assertRegExp('/origin has some uncommitted changes - Cannot rebase rebased on origin/', $e->getMessage()); } $this->assertEquals(array('a' => array('a2', 'a4', 'a1', 'a3'), 'c' => array('c4', 'c5'), 'd' => array(0 => 'd1', 3 => 'd4', 4 => 'd5'), 'f' => array('f1', 'f2'), 'h' => array('h1', 'h3'), 'i' => array('i1')), $rebasedNode->getRawAttributes(), 'Rebased node values are unchanged'); $origNode->snapshot(); $backupNode = clone $origNode; $rebasedNode->rebaseDiff($origNode); $this->assertEquals(array('a' => array('a1', 'a2', 'a3'), 'c' => array('c4', 'c5'), 'd' => array(0 => 'd1', 2 => 'd5'), 'e' => array('e1', 'e2'), 'f' => array('f1', 'f2'), 'h' => array('h1', 'h3')), $rebasedNode->getRawAttributes(), 'Rebased diff got applied on origin node values'); $this->assertEquals(array('a' => array('a3'), 'd' => array('d5'), 'f' => array('f1', 'f2'), 'h' => array('h1', 'h3')), $rebasedNode->getDiffAdditions(), 'A new additions diff has been computed (h did not exist in origin node so it is added)'); $this->assertEquals(array('b' => array(), 'd' => array('d2')), $rebasedNode->getDiffDeletions(), 'g and i deletions got ignored in the new deletion diff as they were not set on origin'); $this->assertEquals(array('c' => array('c4', 'c5')), $rebasedNode->getDiffReplacements(), 'h replacement was computed as an addition on origin node'); }
/** * Tests deletion of nodes * * @return void */ public function testDelete() { $manager = new Manager($this->minimal, $this->driver); $node = $this->buildNode('ent1', array()); $this->assertBindingFirst($manager, 'delete', array($node)); $manager->connect(); $this->assertBindingFirst($manager, 'delete', array($node)); $manager->bind(); $this->assertNull($this->driver->getConnection()->shiftLog(), 'Nothing happenned yet'); // No corresponding entry in the Ldap try { $manager->delete($node); $this->fail('This entry is not in the Ldap store'); } catch (NodeNotFoundException $e) { $this->assertRegExp('/ent1 not found/', $e->getMessage()); } $this->assertSearchLog($this->driver->getConnection()->shiftLog(), 'ent1', '(objectclass=*)', SearchInterface::SCOPE_BASE); $this->assertNull($this->driver->getConnection()->shiftLog(), 'Nothing else'); // Basic deletion $set = array(new Entry('ent1')); $this->driver->getConnection()->stackResults($set); $manager->delete($node); $this->assertNull($this->driver->getConnection()->shiftResults(), 'Node got pulled'); $this->assertSearchLog($this->driver->getConnection()->shiftLog(), 'ent1', '(objectclass=*)', SearchInterface::SCOPE_BASE, null, $set); // Deleted node search $this->assertSearchLog($this->driver->getConnection()->shiftLog(), 'ent1', '(objectclass=*)', SearchInterface::SCOPE_ONE); // Deleted node children search $this->assertActionLog($this->driver->getConnection()->shiftLog(), 'delete', 'ent1'); $this->assertNull($this->driver->getConnection()->shiftLog(), 'nothing else'); // Deletion does not search for the entry if the node is already hydrated $node = new Node(); $node->hydrateFromEntry(new Entry('ent1', array())); $this->assertNull($this->driver->getConnection()->shiftResults(), 'No node in the stack'); $manager->delete($node); $this->assertSearchLog($this->driver->getConnection()->shiftLog(), 'ent1', '(objectclass=*)', SearchInterface::SCOPE_ONE); // Only one children search $this->assertActionLog($this->driver->getConnection()->shiftLog(), 'delete', 'ent1'); $this->assertNull($this->driver->getConnection()->shiftLog(), 'nothing else'); // Exception with node children and no recursion configured $node = $this->buildNode('ref', array()); $sets = array(); $sets[] = array(new Entry('ref')); $sets[] = array(new Entry('a-ref'), new Entry('b-ref'), new Entry('c-ref')); $this->driver->getConnection()->stackResults($sets[0]); // The node we want to delete $this->driver->getConnection()->stackResults($sets[1]); // Search for children nodes try { $manager->delete($node); $this->fail('Cannot delete the node, it has children'); } catch (DeleteException $e) { $this->assertRegExp('/ref cannot be deleted/', $e->getMessage()); $this->assertRegExp('/it has some children left/', $e->getMessage()); } $this->assertSearchLog($this->driver->getConnection()->shiftLog(), 'ref', '(objectclass=*)', SearchInterface::SCOPE_BASE, null, $sets[0]); $this->assertSearchLog($this->driver->getConnection()->shiftLog(), 'ref', '(objectclass=*)', SearchInterface::SCOPE_ONE, null, $sets[1]); $this->assertNull($this->driver->getConnection()->shiftLog(), 'nothing else'); // Recursive mode deletion $node = $this->buildNode('tst', array()); $sets = array(array(new Entry('tst')), array(new Entry('a-tst'), new Entry('b-tst'), new Entry('c-tst')), array(), array(new Entry('a-b-tst')), array(), array()); for ($i = 0; $i < count($sets); $i++) { $this->driver->getConnection()->stackResults($sets[$i]); } $manager->delete($node, true); $this->assertSearchLog($this->driver->getConnection()->shiftLog(), 'tst', '(objectclass=*)', SearchInterface::SCOPE_BASE, null, $sets[0]); // Deleted node search $this->assertSearchLog($this->driver->getConnection()->shiftLog(), 'tst', '(objectclass=*)', SearchInterface::SCOPE_ONE, null, $sets[1]); // Deleted node children search $this->assertSearchLog($this->driver->getConnection()->shiftLog(), 'a-tst', '(objectclass=*)', SearchInterface::SCOPE_ONE, null, $sets[2]); // a-tst node children search $this->assertActionLog($this->driver->getConnection()->shiftLog(), 'delete', 'a-tst'); $this->assertSearchLog($this->driver->getConnection()->shiftLog(), 'b-tst', '(objectclass=*)', SearchInterface::SCOPE_ONE, null, $sets[3]); // b-tst node children search $this->assertSearchLog($this->driver->getConnection()->shiftLog(), 'a-b-tst', '(objectclass=*)', SearchInterface::SCOPE_ONE, null, $sets[4]); // a-b-tst node children search $this->assertActionLog($this->driver->getConnection()->shiftLog(), 'delete', 'a-b-tst'); $this->assertActionLog($this->driver->getConnection()->shiftLog(), 'delete', 'b-tst'); $this->assertSearchLog($this->driver->getConnection()->shiftLog(), 'c-tst', '(objectclass=*)', SearchInterface::SCOPE_ONE, null, $sets[5]); // b-tst node children search $this->assertActionLog($this->driver->getConnection()->shiftLog(), 'delete', 'c-tst'); $this->assertActionLog($this->driver->getConnection()->shiftLog(), 'delete', 'tst'); $this->assertNull($this->driver->getConnection()->shiftLog(), 'nothing else'); }
/** * Node factory * * @param string $dn Distinguished name for the node * @param array $attributes Array of attributes * * @return Node node */ protected function buildNode($dn, $attributes) { $node = new Node(); $node->setDn($dn); foreach ($attributes as $name => $data) { $attr = new NodeAttribute($name); $attr->add($data); $node->mergeAttribute($attr); } return $node; }