feature #21856 [LDAP] Allow adding and removing values to/from multi-valued attributes (jean-gui)

This PR was merged into the 4.1-dev branch.

Discussion
----------

[LDAP] Allow adding and removing values to/from multi-valued attributes

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| License       | MIT

`EntryManagerInterface::update(Entry $entry)` is extremely slow in some specific cases such as adding or removing members to or from huge groupOfNames if you also enable the memberOf overlay in OpenLDAP. Disabling memberOf does make things a lot better, but it is still slow compared to inserting/removing only the elements you want.

This PR adds two methods to Symfony\Component\Ldap\Adapter\ExtLdap\EntryManager taking advantage of ldap_mod_add and ldap_mod_del.

I thought about using them directly in the update method, but since you need to know what values to add and remove, it would be necessary to retrieve the old values from LDAP.

I'm also unsure whether these two methods should be in an interface. I think that adding them to EntryManagerInterface would break BC, but I could create another interface, similarly to RenameEntryInterface.

Commits
-------

fa9db29064 Allow adding and removing values to/from multi-valued attributes
This commit is contained in:
Fabien Potencier 2018-04-04 19:33:55 +02:00
commit 2a4d024bcd
3 changed files with 82 additions and 0 deletions

View File

@ -67,6 +67,36 @@ class EntryManager implements EntryManagerInterface
}
}
/**
* Adds values to an entry's multi-valued attribute from the LDAP server.
*
* @throws NotBoundException
* @throws LdapException
*/
public function addAttributeValues(Entry $entry, string $attribute, array $values)
{
$con = $this->getConnectionResource();
if (!@ldap_mod_add($con, $entry->getDn(), array($attribute => $values))) {
throw new LdapException(sprintf('Could not add values to entry "%s", attribute %s: %s.', $entry->getDn(), $attribute, ldap_error($con)));
}
}
/**
* Removes values from an entry's multi-valued attribute from the LDAP server.
*
* @throws NotBoundException
* @throws LdapException
*/
public function removeAttributeValues(Entry $entry, string $attribute, array $values)
{
$con = $this->getConnectionResource();
if (!@ldap_mod_del($con, $entry->getDn(), array($attribute => $values))) {
throw new LdapException(sprintf('Could not remove values from entry "%s", attribute %s: %s.', $entry->getDn(), $attribute, ldap_error($con)));
}
}
/**
* {@inheritdoc}
*/

View File

@ -1,6 +1,12 @@
CHANGELOG
=========
4.1.0
-----
* Added support for adding values to multi-valued attributes
* Added support for removing values from multi-valued attributes
4.0.0
-----

View File

@ -192,4 +192,50 @@ class LdapManagerTest extends LdapTestCase
$this->executeSearchQuery(1);
}
public function testLdapAddRemoveAttributeValues()
{
$entryManager = $this->adapter->getEntryManager();
$result = $this->executeSearchQuery(1);
$entry = $result[0];
$entryManager->addAttributeValues($entry, 'mail', array('fabpot@example.org', 'fabpot2@example.org'));
$result = $this->executeSearchQuery(1);
$newEntry = $result[0];
$this->assertCount(4, $newEntry->getAttribute('mail'));
$entryManager->removeAttributeValues($newEntry, 'mail', array('fabpot@example.org', 'fabpot2@example.org'));
$result = $this->executeSearchQuery(1);
$newNewEntry = $result[0];
$this->assertCount(2, $newNewEntry->getAttribute('mail'));
}
public function testLdapRemoveAttributeValuesError()
{
$entryManager = $this->adapter->getEntryManager();
$result = $this->executeSearchQuery(1);
$entry = $result[0];
$this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}(LdapException::class);
$entryManager->removeAttributeValues($entry, 'mail', array('fabpot@example.org'));
}
public function testLdapAddAttributeValuesError()
{
$entryManager = $this->adapter->getEntryManager();
$result = $this->executeSearchQuery(1);
$entry = $result[0];
$this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}(LdapException::class);
$entryManager->addAttributeValues($entry, 'mail', $entry->getAttribute('mail'));
}
}