Skip to content

Commit

Permalink
split find into find with required class name and findDocument for fi…
Browse files Browse the repository at this point in the history
…nding any document
  • Loading branch information
dbu committed Jan 12, 2024
1 parent 917fc65 commit 43fc2b5
Show file tree
Hide file tree
Showing 33 changed files with 248 additions and 206 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ Changelog
* Removed deprecated methods HierarchyInterface::getParent/setParent.
Use getParentDocument/setParentDocument instead.

* ``DocumentManager::find`` requires to specify the class name. To find any
document without restricting the class name, use the new
``DocumentManager::findDocument`` method.

* DocumentManager::flush no longer saves the PHPCR session if there are no changes
on the ODM layer.

Expand Down
2 changes: 1 addition & 1 deletion docs/en/reference/association-mapping.rst
Original file line number Diff line number Diff line change
Expand Up @@ -572,7 +572,7 @@ empty ``ArrayCollection`` in your documents constructor::
Now the following code will be working even if the Document hasn't
been associated with a DocumentManager yet::

$group = $documentManager->find(null, $groupId);
$group = $documentManager->findDocument($groupId);
$user = new User();
$user->getGroups()->add($group);

Expand Down
2 changes: 1 addition & 1 deletion docs/en/reference/basic-mapping.rst
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,7 @@ the assigned id if either is missing.
To create a new document, you do something like this::

$doc = new Document();
$doc->setParent($dm->find(null, '/test'));
$doc->setParent($dm->findDocument('/test'));
$doc->setNodename('mynode');
// document is persisted with id /test/mynode

Expand Down
16 changes: 8 additions & 8 deletions docs/en/reference/introduction.rst
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ We write a simple PHP script to generate some sample data::
require_once '../bootstrap.php';

// get the root node to add our data to it
$rootDocument = $documentManager->find(null, '/');
$rootDocument = $documentManager->findDocument('/');

// create a new document
$doc = new \Demo\Document();
Expand Down Expand Up @@ -297,14 +297,14 @@ This script will simply echo the data to the console::

require_once '../bootstrap.php';

$doc = $documentManager->find(null, '/doc');
$doc = $documentManager->findDocument('/doc');

echo 'Found '.$doc->getId() ."\n";
echo 'Title: '.$doc->getTitle()."\n";
echo 'Content: '.$doc->getContent()."\n";

The DocumentManager will automatically determine the document class when
you pass ``null`` as first argument to ``find()``.
you call ``findDocument()`` instead of ``find()``.

Tree traversal
--------------
Expand All @@ -319,7 +319,7 @@ we can traverse them::

use Demo\MyDocument;

$doc = $documentManager->find(null, '/doc');
$doc = $documentManager->findDocument('/doc');

foreach($doc->getChildren() as $child) {
if ($child instanceof MyDocument) {
Expand Down Expand Up @@ -394,7 +394,7 @@ Lets look at an example of document ``A`` referencing ``B``::

We can now create a reference with the following code::

$parent = $dm->find(null, '/');
$parent = $dm->findDocument('/');
$a = new A();
$a->setParent($parent);
$a->setNodename('a');
Expand All @@ -408,7 +408,7 @@ We can now create a reference with the following code::
$dm->flush();
$dm->clear();

$b = $dm->find(null, '/b');
$b = $dm->findDocument('/b');

// output Demo\A
var_dump(get_class($b->getReferrers()));
Expand All @@ -429,7 +429,7 @@ To delete a document, call the ``remove`` method on the ``DocumentManager``::
require_once '../bootstrap.php';

// remove a document
$doc = $documentManager->find(null, '/doc');
$doc = $documentManager->findDocument('/doc');
$documentManager->remove($doc);

// persist all operations
Expand All @@ -448,7 +448,7 @@ by assignment. The latter is for example handy with Symfony forms::
require_once '../bootstrap.php';

// we move a node
$child = $documentManager->find(null, '/doc/child');
$child = $documentManager->findDocument('/doc/child');
$documentManager->move($child, '/newpath');

// persist all operations
Expand Down
4 changes: 2 additions & 2 deletions docs/en/reference/multilang.rst
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ have a translator strategy and a Locale field.
Interacting with translations
-----------------------------

When reading, ``DocumentManager::find()`` uses the default locale (see below how to set that). This means
When reading, the ``DocumentManager::find*`` methods use the default locale (see below how to set that). This means
your reading code does not need to be aware of content translations happening.

If you need to access a document with an explicit locale that might be different from the default locale,
Expand Down Expand Up @@ -271,7 +271,7 @@ Full Example
// Get the document in default language
// (English if you bootstrapped as in the example)
$doc = $dm->find(null, '/my_test_node');
$doc = $dm->findDocument('/my_test_node');
// Get the document in French
$doc = $dm->findTranslation(null, '/my_test_node', 'fr');
Expand Down
4 changes: 2 additions & 2 deletions docs/en/reference/versioning.rst
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ See the Phpdoc for full details on those methods.

**Reading**:

- ``DocumentManager::find()`` works as normal, always gives you the current latest version.
- ``DocumentManager::find*`` methods work as normal, always giving you the current latest version.
- ``DocumentManager::getAllLinearVersions($document)`` returns an array with all version names for this document,
ordered from most recent to oldest version. You can specify an optional limit to only get that many most recent versions.
- ``DocumentManager::findVersionByName($id, $versionName)`` get a detached read-only document for a specific version.
Expand Down Expand Up @@ -184,7 +184,7 @@ Full Example
echo $oldVersion->topic; // "Test"
// find the head version
$article = $dm->find('/test');
$article = $dm->findDocument('/test');
echo $article->topic; // "Newvalue"
// restore the head to the old version
Expand Down
35 changes: 20 additions & 15 deletions docs/en/reference/working-with-objects.rst
Original file line number Diff line number Diff line change
Expand Up @@ -37,20 +37,22 @@ Every document has an identifier, which is its PHPCR path. The path is unique
inside the workspace. Take the following example, where you find an article
with the headline "Hello World" with the ID ``/cms/article/hello-world``::

$article = $documentManager->find(null, '/cms/article/hello-world');
$article = $documentManager->findDocument('/cms/article/hello-world');
$article->setHeadline('Hello World dude!');

$article2 = $documentManager->find(null, '/cms/article/hello-world');
$article2 = $documentManager->findDocument('/cms/article/hello-world');
echo $article2->getHeadline(); // Hello World dude!

.. note::

The first argument to ``find()`` is the document class name. While the ORM
has a table per class and thus always needs the document class name,
PHPCR-ODM has one tree for all documents. The above call will find you
whatever document is at that path. Note that you may optionally specify
the class name to have PHPCR-ODM detect if the document is not of the
expected type.
The first argument to ``find()`` is the document class name. Since PHPCR-ODM
2.0, the class name is required. But while the ORM has a table per class and
thus always needs the document class name, PHPCR-ODM uses one tree for all
documents. ``findDocument()`` finds you whatever document is at the specified
path. If you want to only get the document if it is of your expected type,
e.g. for type safety, use the ``find()`` method with its class name argument.
When using ``find``, PHPCR-ODM will return null if the path exists but the
document is not of the requested class.

In this case, the article is retrieved from the document manager twice,
but modified in between. Doctrine 2 realizes that it is the same ID and will
Expand Down Expand Up @@ -131,7 +133,7 @@ from newly opened DocumentManager::
}
}

$article = $em->find(null, '/cms/article/hello-world');
$article = $em->findDocument('/cms/article/hello-world');

This code retrieves an ``Article`` instance with ID
``/cms/article/hello-world``, executing a single ``getNode()`` operation
Expand All @@ -154,7 +156,7 @@ access these proxies for the first time they will go through the
This lazy-loading process happens behind the scenes, hidden from
your code. Have a look at the following example::

$article = $em->find(null, '/cms/article/hello-world');
$article = $em->findDocument('/cms/article/hello-world');

// accessing a method of the user instance triggers the lazy-load
echo "Author: " . $article->getAuthor()->getName() . "\n";
Expand Down Expand Up @@ -612,23 +614,26 @@ By Primary Key

The most basic way to query for a persisted document is by its
identifier (PHPCR path) using the
``DocumentManager::find(null, $id)`` method. Here is an
``DocumentManager::find($className, $id)`` method. Here is an
example::

/** @var $em DocumentManager */
$user = $em->find(User::class, $id);

The return value is either the found document instance or null if no
instance could be found with the given identifier.
instance of the specified class can be found with the given identifier.

If you do not want to specify the class, you can use the ``findDocument($id)``
method instead.

If you need several documents and know their paths, you can have a considerable
performance gain by using ``DocumentManager::findMany(null, $ids)`` as then
all those documents are loaded from the repository in one request.

You can also specify the class name instead of null to filter to only find
instances of that class. If you go through the repository for a document class
this is equivalent to calling find on the ``DocumentManager`` with that document
class.
instances of that class. If you call ``find`` on the repository of a document
class, this is equivalent to calling ``find`` on the ``DocumentManager`` with
that document class.


By Simple Conditions
Expand Down
5 changes: 5 additions & 0 deletions lib/Doctrine/ODM/PHPCR/Decorator/DocumentManagerDecorator.php
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,11 @@ public function isOpen(): bool
return $this->wrapped->isOpen();
}

public function findDocument(string $id): ?object
{
return $this->wrapped->findDocument($id);
}

public function findMany(?string $className, array $ids): Collection
{
return $this->wrapped->findMany($className, $ids);
Expand Down
28 changes: 22 additions & 6 deletions lib/Doctrine/ODM/PHPCR/DocumentManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,9 @@ public function getClassMetadata($className): ClassMetadata
*
* Will return null if the document was not found. A document is considered
* not found if the data at $id is not instance of of the specified
* $className. To get the document regardless of its class, pass null.
* $className.
*
* To get a document regardless of its class, use the ``findDocument`` method.
*
* If the document is translatable, then the language chooser strategy is
* used to load the best suited language for the translatable fields.
Expand All @@ -190,16 +192,30 @@ public function getClassMetadata($className): ClassMetadata
*
* @return object|null the document if found, otherwise null
*/
public function find($className, $id): ?object
public function find(string $className, mixed $id): ?object

Check failure on line 195 in lib/Doctrine/ODM/PHPCR/DocumentManager.php

View workflow job for this annotation

GitHub Actions / PHPStan

PHPDoc tag @param for parameter $className with type string|null is not subtype of native type string.
{
if (!is_string($id)) {
throw new \InvalidArgumentException('PHPCR-ODM ids must be of type string (either uuid or path), you passed '.gettype($id));
}

return $this->doFind($className, $id);
}

public function findDocument(string $id): ?object
{
return $this->doFind(null, $id);
}

private function doFind(?string $className, mixed $id): ?object
{
try {
if (UUIDHelper::isUUID($id)) {
try {
$id = $this->session->getNodeByIdentifier($id)->getPath();
} catch (ItemNotFoundException $e) {
} catch (ItemNotFoundException) {
return null;
}
} elseif (0 !== strpos($id, '/')) {
} elseif (!str_starts_with($id, '/')) {
$id = '/'.$id;
}

Expand All @@ -209,7 +225,7 @@ public function find($className, $id): ?object
$this->unitOfWork->validateClassName($document, $className);

return $document;
} catch (ClassMismatchException $e) {
} catch (ClassMismatchException) {
return null;
}
}
Expand All @@ -222,7 +238,7 @@ public function find($className, $id): ?object

try {
return $this->unitOfWork->getOrCreateDocument($className, $node, $hints);
} catch (ClassMismatchException $e) {
} catch (ClassMismatchException) {
return null;
}
}
Expand Down
12 changes: 12 additions & 0 deletions lib/Doctrine/ODM/PHPCR/DocumentManagerInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,18 @@ public function getConfiguration(): Configuration;
*/
public function isOpen(): bool;

/**
* Finds an object by its identifier.
*
* This is an alternative to ``find`` that does not require you to specify the class name.
* If the PHPCR node at $id does not have the PHPCR-ODM metadata, this method returns null.
*
* Apart from the class name, it has the same semantics as `find`.
*
* @param string $id the identity of the object to find
*/
public function findDocument(string $id): ?object;

/**
* Finds many documents by id.
*
Expand Down
2 changes: 1 addition & 1 deletion tests/Doctrine/Tests/ODM/PHPCR/DocumentManagerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public function testFind(): void

$dm = DocumentManager::create($session, $config);

$nonExistent = $dm->find(null, $fakeUuid);
$nonExistent = $dm->findDocument($fakeUuid);

$this->assertNull($nonExistent);
}
Expand Down
Loading

0 comments on commit 43fc2b5

Please sign in to comment.