-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[Ldap] added Ldap entry rename for ExtLdap adapter #20390
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
fruitwasp
commented
Nov 2, 2016
•
edited
Loading
edited
Q | A |
---|---|
Branch? | "master" |
Bug fix? | no |
New feature? | yes |
BC breaks? | yes |
Deprecations? | no |
Tests pass? | yes |
Fixed tickets | - |
License | MIT |
Doc PR | - |
$result = $this->executeSearchQuery(1); | ||
$entry = $result[0]; | ||
|
||
$this->assertEquals($entry->getAttribute('cn'), 'Mr Robot'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Entry::getAttribute returns an array. So it should fail.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As mentioned in my line comment, I would actually move the rename
logic in the update
method. The goal of the add
is basically to copy / save a new object, whereas update
aims to provide means to update an existing object (which includes renaming an entry).
* | ||
* @throws LdapException | ||
*/ | ||
public function rename(Entry $entry, $newRdn, $newParent, $shouldDeleteOldRdn = true) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
More generally speaking, I'm not really fond of simply exposing the same API as the ldap
PHP extension. This would actually go against the goal of this component, which aims to provide a layer of abstraction on top of multiple implementations of Ldap (the PHP Ldap extension being the first available adapter).
Instead, I would improve the logic in the update()
method, and add more logic in the Entry
class in order to be able to compute a changeset, or simply flag the Entry instance as "dirty".
Currently, the logic for the update()
method is pretty poor, and does not check whether the attributes have changed or not, or if the DN has changed or not. This could be pretty much improved, for Symfony 3.3.
In short, 👍 on the intent of the PR, 👎 on the actual implementation, which should not reflect the implementation details. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for going back and forth between designs. I think you were right to add a new rename
method, but it needs a few tweaks.
Instead, I would do the following:
- The
update
method should be kept as is, and should be used only to update an existing entry's attributes. - A
rename
method should be added, to explicitly support renaming, taking only the old RDN, the new RDN, and an optional$deleteRdn
boolean argument to remove the old entry or not. The$deleteRdn
attribute should betrue
by default, as in most cases we expect the old object to disappear when renaming an entry (think about the OSmv
ormove
command, or anUPDATE
statement in SQL). - If you want to create a new entry from an existing one with altered attributes, I would actually recommend creating a new entry and passing the original entry's attributes through
$originalEntry->getAttributes()
and specifying a new DN in the new entry's constructor, perform further modifications, and then use theEntryManager::save()
method.
As I said before, I do not want the LDAP component to be a simple reflection of PHP's ldap
extension. We want something which is higher level, and eases developers' life.
With this design, no need to track the objects' changes, except just to prevent updating an entry if it not flagged as "dirty" (in the EntryManager::update()
method).
In this case, I would rename the $attributesState
property to $dirty
, and simply store a boolean
value instead (no need for class constants for something binary).
@csarrazi we need to track objects' changes anyway because now if you have only read access to some properties, you won't be able to change properties you have access to by changing entry object and persisting it. As example;
Won't work even if you have write access to uid property because it tries to update all properties this object have. I used this workaround:
It's not place for bug reports but it's connected to the topic :) |
@csarrazi I have implemented the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We're nearly there! :)
Could you just add one more test in LdapManagerTest, and fix the method argument in the interface class?
We should have an additional case with $removeOldRdn = false
for checking that the old entry has indeed is still there in this case.
Thanks a lot for that PR, and your patience, @fruitwasp!
|
||
$result = $this->executeSearchQuery(1); | ||
$entry = $result[0]; | ||
$this->assertEquals($entry->getAttribute('cn')[0], 'Kevin'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should also check that the old DN no longer exists.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The old DN no longer exists if there's only 1 entry. If more than 1 Entry is found, the assertCount
check will fail in executeSearchQuery
, therefore I don't think it necessary to have another check.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. I agree
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another thing. You should make sure that the test returns the directory in its original state. If you rename the entry, don't forget to rename it back to its original value after the test.
* @param string $newRdn | ||
* @param bool $deleteOldRdn | ||
*/ | ||
public function rename(Entry $entry, $newRdn, $deleteOldRdn = true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rename the $deleteOldRdn
to $removeOldRdn
so it is the same as in the implementation class.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't forget to reinitialise the directory to its original state. Tests should be independent from each other, and should have no impact. Thus, you should run rename()
again to restore the entry in the first test, and run remove()
to remove the newly created entry.
|
||
$result = $this->executeSearchQuery(1); | ||
$entry = $result[0]; | ||
$this->assertEquals($entry->getAttribute('cn')[0], 'Kevin'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another thing. You should make sure that the test returns the directory in its original state. If you rename the entry, don't forget to rename it back to its original value after the test.
$entryManager = $this->adapter->getEntryManager(); | ||
$entryManager->rename($entry, 'cn=Kevin', false); | ||
|
||
$this->executeSearchQuery(2); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same thing. Don't forget to make sure that the new entry is removed after checking that you have two of them.
We do not want tests to put the directory in a state which differs from the startup.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
somehow the test fails on this executeSearchQuery(2)
even though the old RDN shouldn't be removed. Any idea, @csarrazi?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe instead of $this->executeSearchQuery(2)
, try to copy part of the logic, and use something to print what you have in the test.
My guess is that there is something wrong with the parent DN or the RDN, which may not be set to the previous value.
I would recommend you try to run the tests locally (by using the csarrazi/symfony-ldap
docker image, for example), and check what you have in the LDAP directory using var_dump()
, for example.
FYI, the container can be run as follows:
docker run -d --name ldap -p 389:389 -v "/path/to/symfony/source/code/src/Symfony/Component/Ldap/Tests/Fixtures/data:/init-ldap.d" -e "LDAP_SUFFIX=dc=symfony,dc=com" -e "LDAP_ROOTDN=cn=admin,dc=symfony,dc=com" -e "LDAP_ROOTPW=symfony" csarrazi/symfony-ldap
Then you can run the tests as follows (from /path/to/symfony/source/code
):
LDAP_HOST=localhost LDAP_PORT=389 ./phpunit src/Symfony/Component/Ldap
Cheers!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@csarrazi Thanks for that. I misunderstood what not deleting the old RDN actually does. All tests pass now.
@fruitwasp you're welcome! 👍 |
* @param string $newRdn | ||
* @param bool $removeOldRdn | ||
*/ | ||
public function rename(Entry $entry, $newRdn, $removeOldRdn = true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we still consider the API of the LDAP component to be internal and subject to change? Otherwise, this change is a BC break.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The readme states that the component is stable since Symfony 3.1 (https://github.com/symfony/ldap/blob/3.2/README.md). So I guess this is a BC break.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hum, this interface should still actually be marked as private, and was only added in 3.2.
Write support is only in its infancy, and is not completely mature yet, so we may need to add new methods at later points (move(Entry $entry, $newRoot)
for example).
We could create another interface which extends the EntryManagerInterface or a separate interface for newer methods, which could be merged in the main interface for Symfony 4.0 (See what was done for LdapClientInterface
and LdapInterface
, for example).
On the other hand, the query part is stable, and should not change in the upcoming months.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe a MoveEntryInterface
would be a good solution?
interface MoveEntryInterface
{
public function move(Entry $entry, $newRoot);
}
Which should be merged in the main interface for Symfony 4.0.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup, I do think so. @xabbuh what do you think about this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
move()
instead of rename()
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
move()
is something else, and not related to rename()
.
So the correct interface would be something like RenameEntryInterface
. We could add MoveEntryInterface
at a later time, when we actually implement moving an entry to a new parent tree.
@fruitwasp I am not very familiar with LDAP, but my BC concerns have been addressed. |
use Symfony\Component\Ldap\Entry; | ||
|
||
/** | ||
* @author Kevin Schuurmans <kevin.schuurmans@freshheads.com> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe just add a mention that this interface will be deprecated for 4.0, and merged with EntryManagerInterface
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done that.
Thank you @fruitwasp. |
…uitwasp) This PR was merged into the 3.3-dev branch. Discussion ---------- [Ldap] added Ldap entry rename for ExtLdap adapter | Q | A | ------------- | --- | Branch? | "master" | Bug fix? | no | New feature? | yes | BC breaks? | yes | Deprecations? | no | Tests pass? | yes | Fixed tickets | - | License | MIT | Doc PR | - Commits ------- 2d8eeb2 [LDAP] implemented LDAP entry rename for ExtLdap adapter
…maid) This PR was merged into the 4.0-dev branch. Discussion ---------- [Ldap] Remove the RenameEntryInterface interface | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | no | BC breaks? | yes | Deprecations? | no | Tests pass? | yes | Fixed tickets | #20390 | License | MIT | Doc PR | / Commits ------- 5d35184 Remove the RenameEntryInterface interface
This PR was merged into the 3.3 branch. Discussion ---------- [Ldap] Fix deprecated message | Q | A | ------------- | --- | Branch? | 3.3 | Bug fix? | no | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #20390 #23402 | License | MIT | Doc PR | / ``RenameEntryInterface`` is **deprecated** in 3.3 and **removed/merged** in 4.0. Commits ------- bbd0c7f Fix deprecated message