Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

Already on GitHub? Sign in to your account

add chapter on working with objects #24

Merged
merged 7 commits into from Apr 24, 2013

Conversation

Projects
None yet
4 participants
Member

dbu commented Apr 19, 2013

No description provided.

@dbu dbu and 1 other commented on an outdated diff Apr 19, 2013

en/reference/working-with-objects.rst
+ the cascade element value MERGE or ALL (see "Transitive
+ Persistence").
+- For all documents Y referenced by relationships from X having the
+ cascade element value MERGE or ALL, Y is merged recursively as Y'.
+ For all such Y referenced by X, X' is set to reference Y'. (Note
+ that if X is managed then X is the same object as X'.)
+- If X is an document merged to X', with a reference to another
+ document Y, where cascade=MERGE or cascade=ALL is not specified, then
+ navigation of the same association from X' yields a reference to a
+ managed object Y' with the same persistent identity as Y.
+
+The ``merge`` operation will throw an ``OptimisticLockException``
+if the document being merged uses optimistic locking through a
+version field and the versions of the document being merged and the
+managed copy don't match. This usually means that the document has
+been modified while being detached.
@dbu

dbu Apr 19, 2013

Member

does this apply to phpcr-odm as well? i find no mention of "optimistic" in the codebase

@lsmith77

lsmith77 Apr 22, 2013

Member

we do not have OptimisticLockException in the PHPCR ODM (we also do not have optimistic locking support)

@dantleech dantleech commented on an outdated diff Apr 19, 2013

en/reference/introduction.rst
-TODO: explain @ReferenceOne and @ReferenceMany and @Referrers
+You can move a document to a different path with the ``move`` method.
+Alternatively, you can assign a different Parent and/or Nodename to move
+by assignment. The later is for example handy with Symfony2 forms.
@dantleech

dantleech Apr 19, 2013

Contributor

s/later/latter

@dantleech

dantleech Apr 19, 2013

Contributor
     2. Of two things, the one mentioned second.
        [1913 Webster]

              The difference between reason and revelation, and in
              what sense the latter is superior.    --I. Watts.

@dantleech dantleech commented on an outdated diff Apr 19, 2013

en/reference/working-with-objects.rst
@@ -0,0 +1,804 @@
+Working with Objects
+====================
+
+This chapter explains you how to work with the ``DocumentManager`` and the
@dantleech

dantleech Apr 19, 2013

Contributor

explains how to work

@dantleech dantleech commented on an outdated diff Apr 19, 2013

en/reference/working-with-objects.rst
@@ -0,0 +1,804 @@
+Working with Objects
+====================
+
+This chapter explains you how to work with the ``DocumentManager`` and the
+``UnitOfWork``. The UnitOfWork encapsulates the information to be written
@dantleech

dantleech Apr 19, 2013

Contributor

Second UnitOfWork should quoted in double backticks?

@dantleech dantleech and 1 other commented on an outdated diff Apr 19, 2013

en/reference/working-with-objects.rst
+
+.. note::
+
+ It is very important to understand that only
+ ``DocumentManager#flush()`` ever causes write operations against the
+ database to be executed. Any other methods such as
+ ``DocumentManager#persist($document)`` or
+ ``DocumentManager#remove($document)`` only notify the UnitOfWork to
+ perform these operations during flush.
+
+ Not calling ``DocumentManager#flush()`` will lead to all changes
+ during that request being lost.
+
+.. hint::
+ The DocumentManager is very similar to the Doctrine ORM EntityManager.
+ This chapter is shortened compared to the `corresponding ORM chapter <https://doctrine-orm.readthedocs.org/en/latest/reference/working-with-objects.html>`_
@dantleech

dantleech Apr 19, 2013

Contributor

This chapter is short compared to / This chapter is less comprehensive than

@dbu

dbu Apr 22, 2013

Member

actually this turned out a lie in the end, i did not remove much.

@dantleech dantleech and 1 other commented on an outdated diff Apr 19, 2013

en/reference/working-with-objects.rst
+
+ Not calling ``DocumentManager#flush()`` will lead to all changes
+ during that request being lost.
+
+.. hint::
+ The DocumentManager is very similar to the Doctrine ORM EntityManager.
+ This chapter is shortened compared to the `corresponding ORM chapter <https://doctrine-orm.readthedocs.org/en/latest/reference/working-with-objects.html>`_
+ We try to highlight the places where PHPCR-ODM is different from the ORM.
+
+
+Documents and the Identity Map
+------------------------------
+
+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':
@dantleech

dantleech Apr 19, 2013

Contributor

I have been generally putting paths in double backticks, what do we prefer? @wouterj

@wouterj

wouterj Apr 19, 2013

I'm +1 for paths in literals

@dantleech dantleech and 1 other commented on an outdated diff Apr 19, 2013

en/reference/working-with-objects.rst
+
+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':
+
+.. code-block:: php
+
+ <?php
+ $article = $documentManager->find(null, '/cms/article/hello-world');
+ $article->setHeadline('Hello World dude!');
+
+ $article2 = $documentManager->find(null, '/cms/article/hello-world');
+ echo $article2->getHeadline();
+
+.. note::
+ The first argument to ``find()`` is the document class name. While the ORM
@dantleech

dantleech Apr 19, 2013

Contributor

As an aside, does it make any sense to have the classname as the first argument? I have personally never specified it.

@dbu

dbu Apr 22, 2013

Member

there was a lot of arguing about this but in the end we dropped the topic: doctrine/phpcr-odm#145

problem is the consistency with doctrine orm that we want to keep.

@dantleech dantleech commented on the diff Apr 19, 2013

en/reference/working-with-objects.rst
+
+Documents and the Identity Map
+------------------------------
+
+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':
+
+.. code-block:: php
+
+ <?php
+ $article = $documentManager->find(null, '/cms/article/hello-world');
+ $article->setHeadline('Hello World dude!');
+
+ $article2 = $documentManager->find(null, '/cms/article/hello-world');
+ echo $article2->getHeadline();
@dantleech

dantleech Apr 19, 2013

Contributor

Maybe show the output in a comment e.g.

echo$article2->getHeadling(); // Hello World dude!
@dbu

dbu Apr 22, 2013

Member

fixed

@dantleech dantleech commented on an outdated diff Apr 19, 2013

en/reference/working-with-objects.rst
+ 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.
+
+In this case, the Article is accessed from the document manager twice,
+but modified in between. Doctrine 2 realizes that it is the same ID and will only
+ever give you access to one instance of the Article with ID '/cms/article/hello-world',
+no matter how often do you retrieve it from the DocumentManager and
+even no matter what kind of Query method you are using (find,
+Repository Finder or DQL). This is called "Identity Map" pattern,
+which means Doctrine keeps a map of each document and ids that have
+been retrieved per PHP request and keeps returning you the same
+instances.
+
@dantleech

dantleech Apr 19, 2013

Contributor

Maybe "In this case the article is retrieved from the document manager, modified, then retrieved again and assigned to a new variable. Doctrine realizes ..."

"... means Doctrine keeps a map of documents and IDs that have been retrieved in the current PHP request ..."

Also, I think we should talk about article either as a class, in which case its Article or as a subject in which case its just "article" with no formatting.

@dantleech dantleech and 1 other commented on an outdated diff Apr 19, 2013

en/reference/working-with-objects.rst
+ /** @Document */
+ class Article
+ {
+ /** @Id */
+ private $id;
+
+ /** @String */
+ private $headline;
+
+ /** @ReferenceOne */
+ private $author;
+
+ /** @Referrers(referrerDocument="Comment", referencedBy="article") */
+ private $comments;
+
+ public function __construct {
@dantleech

dantleech Apr 19, 2013

Contributor

We should probably apply normal symfony coding conventions here.

Also, I always prefer the following syntax for annotations

/**
 * @Id
 * /

And have done that in, for example, the annotations documentation. Would be good to standardize .. @wouterj

@wouterj

wouterj Apr 19, 2013

I agree with the annotations. If it should be a standard, it should get placed inside the CS. /cc @fabpot

@dantleech dantleech commented on an outdated diff Apr 19, 2013

en/reference/working-with-objects.rst
+
+ public function __construct {
+ $this->comments = new ArrayCollection();
+ }
+
+ public function getAuthor() { return $this->author; }
+ public function getComments() { return $this->comments; }
+ }
+
+ $article = $em->find(null, '/cms/article/hello-world');
+
+This code retrieves the ``Article`` instance with ID '/cms/article/hello-world'
+executing a single getNode statement against the repository. You can still
+access the associated properties author and comments and the associated objects
+they contain.
+
@dantleech

dantleech Apr 19, 2013

Contributor

"This code retrieves an Article instance with ID '/cms/article/hello-world', in doing so it executes a single getNode operation on the repository, retrieving only the data required for the specified article, you can however still access ..."

@dantleech dantleech commented on an outdated diff Apr 19, 2013

en/reference/working-with-objects.rst
+
+ $article = $em->find(null, '/cms/article/hello-world');
+
+This code retrieves the ``Article`` instance with ID '/cms/article/hello-world'
+executing a single getNode statement against the repository. You can still
+access the associated properties author and comments and the associated objects
+they contain.
+
+This works by utilizing the lazy loading pattern. Instead of
+passing you back a real Author instance and a collection of
+comments, Doctrine will create proxy instances for you. Only if you
+access these proxies for the first time they will go through the
+DocumentManager and load their state from the repository.
+
+This lazy-loading process happens behind the scenes, hidden from
+your code. See the following code:
@dantleech

dantleech Apr 19, 2013

Contributor
See the following example / Have a look at the following example::

    <?php
    // ...

We should use the shorthand syntax with PHP examples as per the coding standard.

@dantleech dantleech commented on an outdated diff Apr 19, 2013

en/reference/working-with-objects.rst
+DocumentManager and load their state from the repository.
+
+This lazy-loading process happens behind the scenes, hidden from
+your code. See the following code:
+
+.. code-block:: php
+
+ <?php
+ $article = $em->find(null, '/cms/article/hello-world');
+
+ // accessing a method of the user instance triggers the lazy-load
+ echo "Author: " . $article->getAuthor()->getName() . "\n";
+
+ // Lazy Loading Proxies pass instanceof tests:
+ if ($article->getAuthor() instanceof User) {
+ // a User Proxy is a generated "UserProxy" class
@dantleech

dantleech Apr 19, 2013

Contributor

// Lazy loading proxies will pass instanceof tests

// getAuthor returns a proxy class which is an instance of the target class (???)

@dantleech dantleech commented on an outdated diff Apr 19, 2013

en/reference/working-with-objects.rst
+ // retrieving ALL the comments of this article from the database
+ // using a single SELECT statement
+ foreach ($article->getComments() AS $comment) {
+ echo $comment->getText() . "\n\n";
+ }
+
+ // Article::$comments passes instanceof tests for the Collection interface
+ // But it will NOT pass for the ArrayCollection interface
+ if ($article->getComments() instanceof \Doctrine\Common\Collections\Collection) {
+ echo "This will always be true!";
+ }
+
+A slice of the generated proxy classes code looks like the
+following piece of code. A real proxy class override ALL public
+methods along the lines of the ``getName()`` method shown below:
+
@dantleech

dantleech Apr 19, 2013

Contributor

.. looks like the following example ... .. Real proxy classes override all public methods ...

@dantleech dantleech commented on an outdated diff Apr 19, 2013

en/reference/working-with-objects.rst
+ }
+
+ public function getName()
+ {
+ $this->_load();
+ return parent::getName();
+ }
+ // .. other public methods of User
+ }
+
+.. warning::
+
+ Traversing the object graph for parts that are lazy-loaded will
+ easily trigger lots of repository lookups and will perform badly if used
+ too heavily. If you often use child documents for example, look into
+ the `fetchDepth` configuration.
@dantleech

dantleech Apr 19, 2013

Contributor

Double backticks fetchDepth

@dantleech dantleech commented on an outdated diff Apr 19, 2013

en/reference/working-with-objects.rst
+You need to call ``DocumentManager#persist($document)`` to make the document
+MANAGED. You only need to do that on object instantiation. From now on,
+whenever you modify the object you loaded from the DocumentManager, it will
+automatically be synchronized with the repository when
+``DocumentManager#flush()`` is invoked.
+
+.. note::
+
+ Invoking the ``persist`` method for a document does NOT
+ cause an immediate addNode on the repository.
+ Doctrine applies a strategy called "transactional write-behind",
+ which means that it will delay most SQL commands until
+ ``DocumentManager#flush()`` is invoked which will then issue all
+ necessary PHPCR calls to synchronize your objects with the
+ repository in the most efficient way and a single, short transaction,
+ taking care of maintaining referential integrity.
@dantleech

dantleech Apr 19, 2013

Contributor

... in the most efficient way - a single short transaction - taking care of .... (i think thats better, not sure)

@dantleech dantleech commented on an outdated diff Apr 19, 2013

en/reference/working-with-objects.rst
+automatically be synchronized with the repository when
+``DocumentManager#flush()`` is invoked.
+
+.. note::
+
+ Invoking the ``persist`` method for a document does NOT
+ cause an immediate addNode on the repository.
+ Doctrine applies a strategy called "transactional write-behind",
+ which means that it will delay most SQL commands until
+ ``DocumentManager#flush()`` is invoked which will then issue all
+ necessary PHPCR calls to synchronize your objects with the
+ repository in the most efficient way and a single, short transaction,
+ taking care of maintaining referential integrity.
+
+
+Example:
@dantleech

dantleech Apr 19, 2013

Contributor

Use shorthand notation for php examples..

@dantleech dantleech commented on an outdated diff Apr 19, 2013

en/reference/working-with-objects.rst
+ <?php
+ $user = new User;
+ $user->setName('Mr.Right');
+ $dm->persist($user);
+ $dm->flush();
+
+.. note::
+
+ Generated document identifiers / primary keys are
+ guaranteed to be available after the next successful flush
+ operation that involves the document in question. You can not rely on
+ a generated identifier to be available directly after invoking
+ ``persist``. The inverse is also true. You can not rely on a
+ generated identifier being not available after a failed flush
+ operation.
+
@dantleech

dantleech Apr 19, 2013

Contributor

s/can not/cannot

I think the double negative is a bit confusing in the lsat sentance, and I am not quite sure of the meaning. Do you mean "You cannot rely on a generated identifier being available after a failed flush operation" ?

@dantleech dantleech and 1 other commented on an outdated diff Apr 19, 2013

en/reference/working-with-objects.rst
+
+
+The semantics of the persist operation, applied on an document X, are
+as follows:
+
+
+- If X is a new document, it becomes managed. The document X will be
+ entered into the repository as a result of the flush operation.
+- If X is a preexisting managed document, it is ignored by the
+ persist operation. However, the persist operation is cascaded to
+ documents referenced by X, if the relationships from X to these
+ other documents are mapped with cascade=PERSIST or cascade=ALL (see
+ "Transitive Persistence").
+- If X is a removed document, it becomes managed.
+- If X is a detached document, an exception will be thrown on
+ flush.
@dantleech

dantleech Apr 19, 2013

Contributor
-  ...
- If X is a pre-existing ...  However, the persist operation is cascaded to documents referenced by X if the ... (no comma)
@dbu

dbu Apr 22, 2013

Member

fixed

Contributor

dantleech commented Apr 19, 2013

Hmm.. this is taking me forever as my computer is really slow and for some reason all the JS on this page doesn't help. Shall I wait until you have addressed what I have suggested then just make a PR?

@wouterj wouterj commented on the diff Apr 19, 2013

en/reference/introduction.rst
Children need not be of the same document class as their parents. Be careful when reading
children to be sure they are of the expected class.
+Even if children are not mapped, you can use the document manager to get all
+flushed children of a document.
+
+.. code-block:: php
+
+ <?php
+
+ $children = $documentManager->getChildren($parent);
+
+.. note:: *Difference from ORM*
@wouterj

wouterj Apr 19, 2013

note directives can't have a title.

@dbu

dbu Apr 22, 2013

Member

fixed

@wouterj wouterj commented on the diff Apr 19, 2013

en/reference/introduction.rst
Children need not be of the same document class as their parents. Be careful when reading
children to be sure they are of the expected class.
+Even if children are not mapped, you can use the document manager to get all
+flushed children of a document.
+
+.. code-block:: php
+
+ <?php
+
+ $children = $documentManager->getChildren($parent);
+
+.. note:: *Difference from ORM*
+ While with the ORM, the natural thing to get data is to query, with
@wouterj

wouterj Apr 19, 2013

you are missing an empty line before this

@dbu

dbu Apr 22, 2013

Member

fixed

@wouterj wouterj commented on an outdated diff Apr 19, 2013

en/reference/introduction.rst
-One more script to show some basic operations you can do with the document manager.
+To delete a document, call the ``remove`` method on the DocumentManager.
@wouterj

wouterj Apr 19, 2013

I prefer a literal for class names

@wouterj wouterj and 1 other commented on an outdated diff Apr 19, 2013

en/reference/working-with-objects.rst
@@ -0,0 +1,804 @@
+Working with Objects
+====================
+
+This chapter explains you how to work with the ``DocumentManager`` and the
+``UnitOfWork``. The UnitOfWork encapsulates the information to be written
+to PHPCR when you call ``DocumentManager#flush()``.
+
+A UnitOfWork can be manually closed by calling ``DocumentManager#close()``.
+Any changes to objects within this UnitOfWork that have not yet been
+persisted are lost.
+
+.. note::
+
+ It is very important to understand that only
+ ``DocumentManager#flush()`` ever causes write operations against the
@wouterj

wouterj Apr 19, 2013

The # character to devide the classname and method is some ruby-alike thing, we use :: in the core docs

@dbu

dbu Apr 22, 2013

Member

seems doctrine orm (where i copied this from) is not consistent here. in the phpcr-odm doc we have a complete mixup. fixed it to :: for the documents i touch in this PR.

@wouterj wouterj commented on an outdated diff Apr 19, 2013

en/reference/working-with-objects.rst
+------------------------------
+
+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':
+
+.. code-block:: php
+
+ <?php
+ $article = $documentManager->find(null, '/cms/article/hello-world');
+ $article->setHeadline('Hello World dude!');
+
+ $article2 = $documentManager->find(null, '/cms/article/hello-world');
+ echo $article2->getHeadline();
+
+.. note::
@wouterj

wouterj Apr 19, 2013

missing empty line after this one

@wouterj wouterj and 1 other commented on an outdated diff Apr 19, 2013

en/reference/working-with-objects.rst
+In this case, the Article is accessed from the document manager twice,
+but modified in between. Doctrine 2 realizes that it is the same ID and will only
+ever give you access to one instance of the Article with ID '/cms/article/hello-world',
+no matter how often do you retrieve it from the DocumentManager and
+even no matter what kind of Query method you are using (find,
+Repository Finder or DQL). This is called "Identity Map" pattern,
+which means Doctrine keeps a map of each document and ids that have
+been retrieved per PHP request and keeps returning you the same
+instances.
+
+In the previous example the ``echo`` prints "Hello World dude!" to the
+screen. You can even verify that ``$article`` and ``$article2`` are
+indeed pointing to the same instance by running the following
+code:
+
+.. code-block:: php
@wouterj

wouterj Apr 19, 2013

use the :: shortcut

@dbu

dbu Apr 22, 2013

Member

do we have that enabled in the doctrine documentation?

@wouterj

wouterj Apr 22, 2013

@dbu it's a feature of Sphinx. If you have set the default domain to PHP, you are good to go.

@dbu

dbu Apr 22, 2013

Member

ah. ok. i enabled that for the doctrine documentation now, it was not
active at all. (guess that made :: do python)

Member

dbu commented Apr 22, 2013

thanks for all the feedback. we have the question of whether Example:: works in the doctrine doc, and the question about optimistic locking.

@dantleech dantleech and 1 other commented on an outdated diff Apr 22, 2013

en/reference/working-with-objects.rst
+Example:
+
+.. code-block:: php
+
+ <?php
+ $dm->remove($user);
+ $dm->flush();
+
+The semantics of the remove operation, applied to an document X are
+as follows:
+
+
+- If X is a new document, it is ignored by the remove operation.
+ However, the remove operation is cascaded to documents referenced by
+ X, if the relationship from X to these other documents is mapped
+ with cascade=REMOVE or cascade=ALL (see "Transitive Persistence").
@dantleech

dantleech Apr 22, 2013

Contributor

According to standards all list items should be terminated with ; with the exception of the last item, which should end in .

@dantleech

dantleech Apr 22, 2013

Contributor

Also, I think lists should be

* Foo
* Bar

I.e. asterix and one space. @wouterj

@dbu

dbu Apr 22, 2013

Member

well this is doctrine doc, not symfony. but i agree we should follow the same logic. fixing this here.

@dantleech dantleech commented on an outdated diff Apr 22, 2013

en/reference/working-with-objects.rst
+ $dm->flush();
+
+The semantics of the remove operation, applied to an document X are
+as follows:
+
+
+- If X is a new document, it is ignored by the remove operation.
+ However, the remove operation is cascaded to documents referenced by
+ X, if the relationship from X to these other documents is mapped
+ with cascade=REMOVE or cascade=ALL (see "Transitive Persistence").
+- If X is a managed document, the remove operation causes it to
+ become removed. The remove operation is cascaded to documents
+ referenced by X, if the relationships from X to these other
+ documents is mapped with cascade=REMOVE or cascade=ALL (see
+ "Transitive Persistence").
+- If X is a detached document, an InvalidArgumentException will be
@dantleech

dantleech Apr 22, 2013

Contributor

Class name should be in literals

@dantleech dantleech commented on an outdated diff Apr 22, 2013

en/reference/working-with-objects.rst
+ However, the remove operation is cascaded to documents referenced by
+ X, if the relationship from X to these other documents is mapped
+ with cascade=REMOVE or cascade=ALL (see "Transitive Persistence").
+- If X is a managed document, the remove operation causes it to
+ become removed. The remove operation is cascaded to documents
+ referenced by X, if the relationships from X to these other
+ documents is mapped with cascade=REMOVE or cascade=ALL (see
+ "Transitive Persistence").
+- If X is a detached document, an InvalidArgumentException will be
+ thrown.
+- If X is a removed document, it is ignored by the remove operation.
+- A removed document X will be removed from the repository as a result
+ of the flush operation.
+
+After a document has been removed, its in-memory state is the same as
+before the removal, except for generated identifiers.
@dantleech

dantleech Apr 22, 2013

Contributor

Not sure I understand .. should this read: "except that the identifiers will have been set to null" ?

@dantleech dantleech commented on the diff Apr 22, 2013

en/reference/working-with-objects.rst
+After a document has been removed, its in-memory state is the same as
+before the removal, except for generated identifiers.
+
+Removing a document will also **automatically delete any children** of it.
+Note that no events will be triggered for the removed children, only for
+the document explicitly removed.
+
+Deleting an object with all its references and referring objects can be
+achieved by cascading removal on the association mapping. If an association
+is marked as ``CASCADE=REMOVE``, PHPCR-ODM will fetch this association. If
+its a Single association it will pass this document to
+``DocumentManager::remove()``. If the association is a collection, Doctrine
+will loop over all its elements and pass them to``DocumentManager::remove()``.
+In both cases the cascade remove semantics are applied recursively.
+For large object graphs this removal strategy can be very costly.
+
@dantleech

dantleech Apr 22, 2013

Contributor

Are the previous two paragraphs describing two different ways of handling the same thing? I.e. does the first paragraph describe the default behavior (CASCADE=NONE?), purging all the node and its children and not triggering events, and the other describes the CASCADE behavior, where events are triggered for children?

Also maybe we should choose to either talk about documents or objects and not fix the terminology?

@dbu

dbu Apr 22, 2013

Member

one talks about children, the other about references. tried to make it
more understandable.

objects vs documents is a huge mess indeed. its a mess for the orm as
well, i just replaced "document" with "entity" but left "object". will
clean this up here.

@dantleech dantleech commented on an outdated diff Apr 22, 2013

en/reference/working-with-objects.rst
+
+ Contrary to the ORM, the PHPCR query language knows no DELETE statement.
+ If you expect to remove large object graphs, try to model them in a way
+ that you can simply remove the parent, as children removal is as cheap
+ as having a relational database cascade removal through foreign keys.
+
+Detaching documents
+-------------------
+
+A document is detached from an DocumentManager and thus no longer
+managed by invoking the ``DocumentManager::detach($document)`` method on
+it or by cascading the detach operation to it. Changes made to the
+detached document, including removal of the document, will not
+be synchronized to the repository after the document has been
+detached.
+
@dantleech

dantleech Apr 22, 2013

Contributor

Hmm, not sure.

When you detach a document from the ``UnitOfWork`` you effectively erase Doctrines in-memory reference to this object - and
it will no longer be managed by Doctrine.

You can detach a document from the ``UnitOfWork`` by invoking .. 

or

.. You can make Doctrine forget about a document by detaching it from the ``UnitOfWork``. You can achieve this by invoking the ``DocumentManager::detach($document)`` method ...

@dantleech dantleech commented on the diff Apr 22, 2013

en/reference/working-with-objects.rst
+be synchronized to the repository after the document has been
+detached.
+
+Doctrine will not hold on to any references to a detached document.
+
+Example:
+
+.. code-block:: php
+
+ <?php
+ $dm->detach($document);
+
+The semantics of the detach operation, applied to a document X are
+as follows:
+
+
@dantleech

dantleech Apr 22, 2013

Contributor

Extra new line

@dbu

dbu Apr 24, 2013

Member

fixed

@dantleech dantleech and 1 other commented on an outdated diff Apr 22, 2013

en/reference/working-with-objects.rst
+
+Example:
+
+.. code-block:: php
+
+ <?php
+ $dm->detach($document);
+
+The semantics of the detach operation, applied to a document X are
+as follows:
+
+
+- If X is a managed document, the detach operation causes it to
+ become detached. The detach operation is cascaded to documents
+ referenced by X, if the relationships from X to these other
+ documents is mapped with cascade=DETACH or cascade=ALL (see
@dantleech

dantleech Apr 22, 2013

Contributor

Should cascade=x be in literals? If so should the value be quoted? @wouterj

@dbu

dbu Apr 22, 2013

Member

agreed, changed. i think quotes are not needed, at least not in annotations

@dantleech dantleech commented on the diff Apr 22, 2013

en/reference/working-with-objects.rst
+ referenced by X, if the relationships from X to these other
+ documents is mapped with cascade=DETACH or cascade=ALL (see
+ "Transitive Persistence"). Documents which previously referenced X
+ will continue to reference X.
+- If X is a new or detached document, it is ignored by the detach
+ operation.
+- If X is a removed document, the detach operation is cascaded to
+ documents referenced by X, if the relationships from X to these
+ other documents is mapped with cascade=DETACH or cascade=ALL (see
+ "Transitive Persistence"). Documents which previously referenced X
+ will continue to reference X.
+
+There are several situations in which a document will become detached
+automatically without invoking the ``detach`` method:
+
+
@dantleech

dantleech Apr 22, 2013

Contributor

One new line too many..

@dbu

dbu Apr 24, 2013

Member

fixed

@dantleech dantleech and 1 other commented on an outdated diff Apr 22, 2013

en/reference/working-with-objects.rst
+ unserialization will be detached (This is the case for all documents
+ that are serialized and stored in some cache).
+
+The ``detach`` operation is usually not as frequently needed and
+used as ``persist`` and ``remove``.
+
+Merging documents
+-----------------
+
+Merging documents refers to the merging of (usually detached)
+documents into the context of a DocumentManager so that they become
+managed again. To merge the state of an document into an
+DocumentManager use the ``DocumentManager::merge($document)`` method. The
+state of the passed document will be merged into a managed copy of
+this document and this copy will subsequently be returned.
+
@dantleech

dantleech Apr 22, 2013

Contributor

Should be "a DocumentManager" not "an".
Just googled it: You use "a" before words that start with a consonant sound and "an" before words that start with a vowel sound ...

@dbu

dbu Apr 22, 2013

Member

yep, i knew that one :-) problem of string replace "entity" with
"document". i checked what i replaced but meant to replace "an d" with
"a d" afterwards but apparently forgot

@dantleech dantleech and 1 other commented on an outdated diff Apr 22, 2013

en/reference/working-with-objects.rst
+as follows:
+
+
+- If X is a detached document, the state of X is copied onto a
+ pre-existing managed document instance X' of the same identity.
+- If X is a new document instance, a new managed copy X' will be
+ created and the state of X is copied onto this managed instance.
+- If X is a removed document instance, an InvalidArgumentException
+ will be thrown.
+- If X is a managed document, it is ignored by the merge operation,
+ however, the merge operation is cascaded to documents referenced by
+ relationships from X if these relationships have been mapped with
+ the cascade element value MERGE or ALL (see "Transitive
+ Persistence").
+- For all documents Y referenced by relationships from X having the
+ cascade element value MERGE or ALL, Y is merged recursively as Y'.
@dantleech

dantleech Apr 22, 2013

Contributor

Is the apostrophe after the last Y a typo? Or is that notation?

@dbu

dbu Apr 22, 2013

Member

seems a matematician wrote that stuff. this would read as "Y is merged
as Y prime"

@dantleech dantleech commented on an outdated diff Apr 22, 2013

en/reference/working-with-objects.rst
+ however, the merge operation is cascaded to documents referenced by
+ relationships from X if these relationships have been mapped with
+ the cascade element value MERGE or ALL (see "Transitive
+ Persistence").
+- For all documents Y referenced by relationships from X having the
+ cascade element value MERGE or ALL, Y is merged recursively as Y'.
+ For all such Y referenced by X, X' is set to reference Y'. (Note
+ that if X is managed then X is the same object as X'.)
+- If X is an document merged to X', with a reference to another
+ document Y, where cascade=MERGE or cascade=ALL is not specified, then
+ navigation of the same association from X' yields a reference to a
+ managed object Y' with the same persistent identity as Y.
+
+The ``merge`` operation is usually not as frequently needed and
+used as ``persist`` and ``remove``. The most common scenario for
+the ``merge`` operation is to reattach documents to an DocumentManager
@dantleech

dantleech Apr 22, 2013

Contributor

DocumentManager in literals

@dantleech dantleech commented on the diff Apr 22, 2013

en/reference/working-with-objects.rst
+ not need to persist or delete them or otherwise make use of them
+ without the need for persistence services there is no need to use
+ ``merge``. I.e. you can simply pass detached objects from a cache
+ directly to the view.
+
+
+Synchronization with the Repository
+-----------------------------------
+
+The state of persistent documents is synchronized with the repository
+on flush of an ``DocumentManager`` which commits the underlying
+``UnitOfWork``. The synchronization involves writing any updates to
+persistent documents and their relationships to the repository.
+Thereby bidirectional relationships are persisted based on the
+references held by the owning side of the relationship as explained
+in the Association Mapping chapter.
@dantleech

dantleech Apr 22, 2013

Contributor

The state [...] repository when the flush method of the DocumentManager is invoked, this commits the underlying [...] ??

@dantleech dantleech commented on an outdated diff Apr 22, 2013

en/reference/working-with-objects.rst
+
+Synchronization with the Repository
+-----------------------------------
+
+The state of persistent documents is synchronized with the repository
+on flush of an ``DocumentManager`` which commits the underlying
+``UnitOfWork``. The synchronization involves writing any updates to
+persistent documents and their relationships to the repository.
+Thereby bidirectional relationships are persisted based on the
+references held by the owning side of the relationship as explained
+in the Association Mapping chapter.
+
+When ``DocumentManager::flush()`` is called, Doctrine inspects all
+managed, new and removed documents and will perform the following
+operations.
+
@dantleech

dantleech Apr 22, 2013

Contributor

Missing list of operations?

Contributor

dantleech commented Apr 22, 2013

I'm on about line 484 on the review (turns out Chrome is very much faster than firefox) but have to go now. Will try and finish my review off later, if not I can make a PR later on.

Member

dbu commented Apr 22, 2013

thanks a lot dan, fixed most of the things you found, commented on the
others.

@dantleech dantleech commented on an outdated diff Apr 24, 2013

en/reference/working-with-objects.rst
+
+As soon as you begin to change the state of documents, call persist or remove the
+contents of the UnitOfWork and the repository will get out of sync. They can
+only be synchronized by calling ``DocumentManager::flush()``. This section
+describes the effects of repository and UnitOfWork being out of sync.
+
+* Documents that are scheduled for removal can still be queried from the repository.
+ They are returned from queries, calls to getReferrers and getChildren and
+ stay visible in collections;
+* Documents that are passed to ``DocumentManager::persist`` do not turn up in query
+ results and do not appear in collections;
+* Documents that have changed will not be overwritten with the state from the repository.
+ This is because the identity map will detect the construction of an already existing
+ document and assumes its the most up to date version.
+
+``DocumentManager::flush()`` is never called implicitly by Doctrine. You always have to trigger it manually.
@dantleech

dantleech Apr 24, 2013

Contributor

Line too long

@dantleech dantleech commented on the diff Apr 24, 2013

en/reference/working-with-objects.rst
+ stay visible in collections;
+* Documents that are passed to ``DocumentManager::persist`` do not turn up in query
+ results and do not appear in collections;
+* Documents that have changed will not be overwritten with the state from the repository.
+ This is because the identity map will detect the construction of an already existing
+ document and assumes its the most up to date version.
+
+``DocumentManager::flush()`` is never called implicitly by Doctrine. You always have to trigger it manually.
+
+Synchronizing New and Managed Documents
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The flush operation applies to a managed document with the following
+semantics:
+
+
@dantleech

dantleech Apr 24, 2013

Contributor

Extra line

@dbu

dbu Apr 24, 2013

Member

fixed

@dantleech dantleech and 1 other commented on an outdated diff Apr 24, 2013

en/reference/working-with-objects.rst
+``DocumentManager::flush()`` is never called implicitly by Doctrine. You always have to trigger it manually.
+
+Synchronizing New and Managed Documents
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The flush operation applies to a managed document with the following
+semantics:
+
+
+* The document itself is synchronized to the repository using PHPCR
+ API calls, only if at least one persistent field has changed;
+* No PHPCR API calls are executed if the document did not change.
+
+The flush operation applies to a new document with the following
+semantics: The document itself is synchronized to the repository using
+PHPCR API calls.
@dantleech

dantleech Apr 24, 2013

Contributor

I wonder if "semantic" is the best word to use here. The word seems to apply to the meaning of words.

For consitency I think the "semantic" should be in a list, i.e.

* The document it....
@dbu

dbu Apr 24, 2013

Member

i made it consistent. semantics is a word for "the meaning of something" - be it a word or a program function

@dantleech dantleech commented on an outdated diff Apr 24, 2013

en/reference/working-with-objects.rst
+
+For all (initialized) relationships of the new or managed document
+the following semantics apply to each associated document X:
+
+
+* If X is new and persist operations are configured to cascade on
+ the relationship, X will be persisted;
+* If X is new and no persist operations are configured to cascade
+ on the relationship, an exception will be thrown as this indicates
+ a programming error;
+* If X is removed and persist operations are configured to cascade
+ on the relationship, an exception will be thrown as this indicates
+ a programming error (X would be re-persisted by the cascade);
+* If X is detached and persist operations are configured to
+ cascade on the relationship, an exception will be thrown (This is
+ semantically the same as passing X to persist()).
@dantleech

dantleech Apr 24, 2013

Contributor

.. the same as passing X to DocumentManager::persist()

@dantleech dantleech commented on the diff Apr 24, 2013

en/reference/working-with-objects.rst
+executed during ``DocumentManager::remove($document)``.
+
+The size of a Unit of Work
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The size of a Unit of Work mainly depends on the number of managed
+documents at a particular point in time.
+
+The cost of flushing
+~~~~~~~~~~~~~~~~~~~~
+
+How costly a flush operation is, mainly depends on two factors:
+
+
+* The size of the document manager's current Unit of Work;
+* The configured change tracking policies
@dantleech

dantleech Apr 24, 2013

Contributor

Missing full stop

@dbu

dbu Apr 24, 2013

Member

fixed

@dantleech dantleech and 1 other commented on an outdated diff Apr 24, 2013

en/reference/working-with-objects.rst
+.. note::
+
+ Do not invoke ``flush`` after every change to a document
+ or every single invocation of persist/remove/merge/... This is an
+ anti-pattern and unnecessarily reduces the performance of your
+ application. Instead, form units of work that operate on your
+ documents and call ``flush`` when you are done. While serving a
+ single HTTP request there should be usually no need for invoking
+ ``flush`` more than 0-2 times.
+
+
+Direct access to a Unit of Work
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+You can get direct access to the Unit of Work by calling
+``DocumentManager::getUnitOfWork()``. This will return the UnitOfWork
@dantleech

dantleech Apr 24, 2013

Contributor

UnitOfWork in literals

@dbu

dbu Apr 24, 2013

Member

i changed that to a word with spaces instead of a class name. think this is more readable.

@dantleech dantleech commented on an outdated diff Apr 24, 2013

en/reference/working-with-objects.rst
+to change tracking (see "Change Tracking Policies") and, of course,
+memory consumption, so you may want to check it from time to time
+during development.
+
+.. note::
+
+ Do not invoke ``flush`` after every change to a document
+ or every single invocation of persist/remove/merge/... This is an
+ anti-pattern and unnecessarily reduces the performance of your
+ application. Instead, form units of work that operate on your
+ documents and call ``flush`` when you are done. While serving a
+ single HTTP request there should be usually no need for invoking
+ ``flush`` more than 0-2 times.
+
+
+Direct access to a Unit of Work
@dantleech

dantleech Apr 24, 2013

Contributor

But I think this should read:

Direct Access to a Unit of Work

Apparently this is known as "Title Case": http://en.wikipedia.org/wiki/Title_case#Headings_and_publication_titles

@dantleech dantleech commented on an outdated diff Apr 24, 2013

en/reference/working-with-objects.rst
+underlying ``UnitOfWork``::
+
+ <?php
+ switch ($dm->getUnitOfWork()->getDocumentState($document)) {
+ case UnitOfWork::STATE_MANAGED:
+ ...
+ case UnitOfWork::STATE_REMOVED:
+ ...
+ case UnitOfWork::STATE_DETACHED:
+ ...
+ case UnitOfWork::STATE_NEW:
+ ...
+ }
+
+A document is in MANAGED state if it is associated with an
+``DocumentManager`` and it is not REMOVED.
@dantleech

dantleech Apr 24, 2013

Contributor

"a" not "an" document manager

@dantleech dantleech commented on an outdated diff Apr 24, 2013

en/reference/working-with-objects.rst
+A document is in MANAGED state if it is associated with an
+``DocumentManager`` and it is not REMOVED.
+
+A document is in REMOVED state after it has been passed to
+``DocumentManager::remove()`` until the next flush operation of the
+same ``DocumentManager``. A REMOVED document is still associated with an
+``DocumentManager`` until the next flush operation.
+
+A document is in DETACHED state if it has persistent state and
+identity but is currently not associated with an
+``DocumentManager``.
+
+A document is in NEW state if has no persistent state and identity
+and is not associated with a ``DocumentManager`` (for example those
+just created via the "new" operator).
+
@dantleech

dantleech Apr 24, 2013

Contributor

This section should probably be a definition list::

States apply to documents as follows:

* **MANAGED**: if it is asso...
* **REMOVED**: After it has ..
* **DETACHED** : If it has ..

Or similar..

@dantleech dantleech commented on an outdated diff Apr 24, 2013

en/reference/working-with-objects.rst
+
+ <?php
+ /** @var $dm DocumentManager */
+
+ // All users that are 20 years old
+ $users = $dm->getRepository('MyProject\Domain\User')->findBy(array('age' => 20));
+
+ // All users that are 20 years old and have a surname of 'Miller'
+ $users = $dm->getRepository('MyProject\Domain\User')->findBy(array('age' => 20, 'surname' => 'Miller'));
+
+ // A single user by its nickname
+ $user = $dm->getRepository('MyProject\Domain\User')->findOneBy(array('nickname' => 'romanb'));
+
+.. warning::
+
+ Note that due to the nature of PHPCR, the primary id is no field.
@dantleech

dantleech Apr 24, 2013

Contributor

.. of PHPCR the primary identifier is not a field.

No comma. Is no > Is not a. and I think either identifier or ID

@dantleech dantleech commented on an outdated diff Apr 24, 2013

en/reference/working-with-objects.rst
+ /** @var $dm DocumentManager */
+
+ // All users that are 20 years old
+ $users = $dm->getRepository('MyProject\Domain\User')->findBy(array('age' => 20));
+
+ // All users that are 20 years old and have a surname of 'Miller'
+ $users = $dm->getRepository('MyProject\Domain\User')->findBy(array('age' => 20, 'surname' => 'Miller'));
+
+ // A single user by its nickname
+ $user = $dm->getRepository('MyProject\Domain\User')->findOneBy(array('nickname' => 'romanb'));
+
+.. warning::
+
+ Note that due to the nature of PHPCR, the primary id is no field.
+ You can thus not use ``findBy(array('id' => '/my/path'))`` but should
+ pass the id into the ``find`` method. There is also findMany if you
@dantleech

dantleech Apr 24, 2013

Contributor

In fact we should probably just %s/id/ID/g the whole doc.

@dantleech dantleech commented on an outdated diff Apr 24, 2013

en/reference/working-with-objects.rst
+ $users = $dm->getRepository('MyProject\Domain\User')->findBy(array('age' => 20));
+
+ // All users that are 20 years old and have a surname of 'Miller'
+ $users = $dm->getRepository('MyProject\Domain\User')->findBy(array('age' => 20, 'surname' => 'Miller'));
+
+ // A single user by its nickname
+ $user = $dm->getRepository('MyProject\Domain\User')->findOneBy(array('nickname' => 'romanb'));
+
+.. warning::
+
+ Note that due to the nature of PHPCR, the primary id is no field.
+ You can thus not use ``findBy(array('id' => '/my/path'))`` but should
+ pass the id into the ``find`` method. There is also findMany if you
+ need to fetch several documents.
+
+You can also load by owning side associations through the repository::
@dantleech

dantleech Apr 24, 2013

Contributor

Hmm, mayme: You can also query via a documents relationship to another document::

@dantleech dantleech commented on the diff Apr 24, 2013

en/reference/working-with-objects.rst
+
+.. warning::
+
+ Note that due to the nature of PHPCR, the primary id is no field.
+ You can thus not use ``findBy(array('id' => '/my/path'))`` but should
+ pass the id into the ``find`` method. There is also findMany if you
+ need to fetch several documents.
+
+You can also load by owning side associations through the repository::
+
+ <?php
+ $number = $dm->find('MyProject\Domain\Phonenumber', '/path/to/phone/number');
+ $user = $dm->getRepository('MyProject\Domain\User')->findOneBy(array('phone' => $number->getUuid()));
+
+Be careful that this only works by passing the uuid of the associated
+document, not yet by passing the associated document itself.
@dantleech

dantleech Apr 24, 2013

Contributor

I guess this would be quite an easy thing to do for 1.0?

@dbu

dbu Apr 24, 2013

Member

orm seems not to support it either. if somebody wants to implement it, i have no objection.

@dantleech

dantleech Apr 24, 2013

Contributor

Oh yeah, your right. Probably better to not push the boat out in that
case.

On Wed, Apr 24, 2013 at 06:34:55AM -0700, David Buchmann wrote:

In en/reference/working-with-objects.rst:

+.. warning::
+

  • Note that due to the nature of PHPCR, the primary id is no field.
  • You can thus not use findBy(array('id' => '/my/path')) but should
  • pass the id into the find method. There is also findMany if you
  • need to fetch several documents.

+You can also load by owning side associations through the repository::
+

  • $number = $dm->find('MyProject\Domain\Phonenumber', '/path/to/phone/number');
  • $user = $dm->getRepository('MyProject\Domain\User')->findOneBy(array('phone' => $number->getUuid()));

+Be careful that this only works by passing the uuid of the associated
+document, not yet by passing the associated document itself.

orm seems not to support it either. if somebody wants to implement it, i
have no objection.


Reply to this email directly or [1]view it on GitHub.

References

Visible links

  1. https://github.com/doctrine/phpcr-odm-documentation/pull/24/files#r3936567

@dantleech dantleech and 1 other commented on an outdated diff Apr 24, 2013

en/reference/working-with-objects.rst
+limit and offset as second to fourth parameters::
+
+ <?php
+ $tenUsers = $dm
+ ->getRepository('MyProject\Domain\User')
+ ->findBy(array('age' => 20), array('name' => 'ASC'), 10, 0);
+
+If you pass an array of values, Doctrine will convert the query into a WHERE
+field IN (..) query automatically::
+
+ <?php
+ $users = $dm
+ ->getRepository('MyProject\Domain\User')
+ ->findBy(array('age' => array(20, 30, 40)));
+
+TODO: __call is not implemented yet
@dantleech

dantleech Apr 24, 2013

Contributor

I actually wonder if we should implement this at all. It doesn't add much value IMO and I sometimes try to do things like findOneByNickNameAndFoobar which doesn't work.. at least with the array syntax you can be sure of the semantics. But I guess its all about being consistent with the ORM.

@dbu

dbu Apr 24, 2013

Member

imo its quite expressive and allows a nice upgrade path if you need to implement a more specific method.

@dantleech dantleech commented on an outdated diff Apr 24, 2013

en/reference/working-with-objects.rst
+
+You can create your SQL2 query by calling ``DocumentManager::createPhpcrQuery``
+with the query as string, or get the phpcr-utils query builder by calling
+``DocumentManager::createPhpcrQueryBuilder``. You can either execute that query
+to get raw PHPCR nodes, or pass a PHPCR query to
+``DocumentManager::getDocumentsByPhpcrQuery`` to get documents.
+
+
+Custom Repositories
+~~~~~~~~~~~~~~~~~~~
+
+By default the ``DocumentManager`` returns a default implementation of
+``Doctrine\ODM\PHPCR\DocumentRepository`` when you call
+``DocumentManager::getRepository($documentClass)``. You can overwrite
+this behaviour by specifying the class name of your own Document
+Repository in the Annotation, XML or YAML metadata. In large,
@dantleech

dantleech Apr 24, 2013

Contributor

s/In large,/In large - no comma

@dantleech dantleech commented on an outdated diff Apr 24, 2013

en/reference/working-with-objects.rst
+to get raw PHPCR nodes, or pass a PHPCR query to
+``DocumentManager::getDocumentsByPhpcrQuery`` to get documents.
+
+
+Custom Repositories
+~~~~~~~~~~~~~~~~~~~
+
+By default the ``DocumentManager`` returns a default implementation of
+``Doctrine\ODM\PHPCR\DocumentRepository`` when you call
+``DocumentManager::getRepository($documentClass)``. You can overwrite
+this behaviour by specifying the class name of your own Document
+Repository in the Annotation, XML or YAML metadata. In large,
+applications that require lots of specialized queries using a
+custom repository is one recommended way of grouping these queries
+in a central location::
+
@dantleech

dantleech Apr 24, 2013

Contributor

.. In large applications that require lots of specialized queries, using a custom repository is *the recommended way to group these queries in a *

Contributor

dantleech commented Apr 24, 2013

Finished - globally there are lots of double-new-lines and all instances of "id" should be replaced with "ID".

@dbu dbu added a commit that referenced this pull request Apr 24, 2013

@dbu dbu Merge pull request #24 from doctrine/working-with-objects
add chapter on working with objects
ef748e5

@dbu dbu merged commit ef748e5 into master Apr 24, 2013

@dbu dbu deleted the working-with-objects branch Apr 24, 2013

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment