[MODM-56] @PreUpdate & EmbedMany Created: 22/Aug/10  Updated: 24/Aug/10  Resolved: 24/Aug/10

Status: Resolved
Project: Doctrine MongoDB ODM
Component/s: Persister
Affects Version/s: 1.0.0ALPHA2
Fix Version/s: 1.0.0BETA2

Type: Bug Priority: Major
Reporter: D Ashwood Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None
Environment:

PHP 5.3.2+, Mongodb, recent (varies by developer but all experiencing the same issue)



 Description   
Unable to find source-code formatter for language: php. Available languages are: actionscript, html, java, javascript, none, sql, xhtml, xml
// Article
namespace Bundle\ArticleBundle\Document;

use Bundle\CommentBundle\Document\Comment;
use Bundle\ExerciseCommonBundle\Document\Repository;

/**
 * @Document(
 *   collection="article",
 *   indexes={
 *     @Index(keys={"createdAt"="asc"})
 *   },
 *   repositoryClass="Bundle\ArticleBundle\Document\ArticleRepository"
 * )
 * @HasLifecycleCallbacks
 */
class Article
{
    /**
     * @Id
     */
    protected $id;
    /**
     * @ReferenceOne(targetDocument="Bundle\AccountBundle\Document\User")
     */
    protected $user;
    /**
     * @ReferenceOne(targetDocument="Bundle\ArticleBundle\Document\ArticleCategory")
     * @Validation({
     *      @NotBlank (message="Please select a category.")
     * })
     */
    protected $category;
    /**
     * @Field(type="string")
     */
    protected $slug;
    /**
     * @Field(type="string")
     * @Validation({
     *      @NotBlank (message="You forgot a Title?"),
     *      @MinLength(limit=4, message="Just a little too short.")
     * })
     */
    protected $title;
    /**
     * @Field(type="string")
     * @Validation({
     *      @NotBlank (message="Please summarize your article."),
     *      @MinLength(limit=100, message="Not long enough!"),
     *      @MaxLength(limit=200, message="A wee bit too long.")
     * })
     */
    protected $summary;
    /**
     * @Field(type="string")
     * @Validation({
     *      @NotBlank (message="Where's the beef?")
     * })
     */
    protected $body;
    
	/** 
	 * @EmbedMany(targetDocument="Bundle\CommentBundle\Document\Comment") 
	 * */
	protected $comments = array();
	
    /**
     * @Field(type="boolean")
     */
    protected $published = false;
    /**
     * @Field(type="date", nullable=false)
     */
    protected $createdAt;
    /**
     * @Field(type="date", nullable=false)
     */
    protected $updatedAt;

    public function getId()
    {
        return $this->id;
    }

    public function isNew() {
        return empty($this->id);
    }

    public function getUser()
    {
        return $this->user;
    }

    public function getCategory()
    {
        return $this->category;
    }

    public function getSlug()
    {
        return $this->slug;
    }

    public function setSlug($slug)
    {
        $this->slug = $slug;
    }

    public function setUniqueSlug()
    {
        $this->slug = Repository::Slugify($this->title);
    }

    public function isPublished()
    {
        if($this->published) {
            return true;
        }
        return false;
    }

    public function publish()
    {
        $this->published = true;
    }

    public function unpublish()
    {
        $this->published = false;
    }

    public function getSummary()
    {
        return $this->summary;
    }

    public function setSummary($summary)
    {
        $this->summary = $summary;
    }

    public function getTitle()
    {
        return $this->title;
    }

    public function setTitle($title)
    {
        $this->title = $title;
    }

    public function getBody()
    {
        return $this->body;
    }



    public function setBody($body)
    {
        $this->body = $body;
    }

    public function setUser($user) {
        $this->user = $user;
    }

    public function setCategory($category) {
        $this->category = $category;
    }

    public function getCreatedAt()
    {
        return $this->createdAt;
    }

    /**
     * It can be useful when writing fixtures
     * @param \DateTime $date
     * @return void
     */
    public function setCreatedAt(\DateTime $date)
    {
        $this->createdAt = $date;
    }

    public function getUpdatedAt()
    {
        return $this->updatedAt;
    }

    public function __toString()
    {
        return $this->title();
    }
    
    
	/**
	 * @return the $comments
	 */
	public function getComments() {
		return $this->comments;
	}    
    
	/**
	 * @param $comments the $comments to set
	 */
	public function setComments($comments) {
		$this->comments = $comments;
	}
    /** @PrePersist */
    public function incrementCreatedAt()
    {
        if(null === $this->createdAt) {
            $this->createdAt = new \DateTime();
        }
        $this->updatedAt = new \DateTime();
    }

    /** @PreUpdate */
    public function incrementUpdatedAt() {
        $this->updatedAt = new \DateTime();
    }

    public function fromArray(array $array)
    {
        foreach($array as $property => $value) {
            $this->$property = $value;
        }
    }
}
Unable to find source-code formatter for language: php. Available languages are: actionscript, html, java, javascript, none, sql, xhtml, xml
// Comment
<?php

namespace Bundle\CommentBundle\Document;

/**
 * @EmbeddedDocument
 */
class Comment
{
	
	/**
     * @Id
     */
    protected $id;
	
    /**
     * @Field(type="date", nullable=true)
     */
    protected $createdAt;

    /**
     * @Field(type="string", nullable=true)
     */
    protected $message;

    /**
     * @ReferenceOne(targetDocument="Bundle\AccountBundle\Document\User")
     */
    protected $user;

    /**
     * @return the $createdAt
     */
    public function getCreatedAt() {
        return $this->createdAt;
    }

    /**
     * @return the $message
     */
    public function getMessage() {
        return $this->message;
    }

    /**
     * @return the $user
     */
    public function getUser() {
        return $this->user;
    }

    /**
     * @param $createdAt the $createdAt to set
     */
    public function setCreatedAt($createdAt) {
        $this->createdAt = $createdAt;
    }

//    /** @PrePersist */
//    public function incrementCreatedAt()
//    {
//        if(null === $this->createdAt) {
//            $this->createdAt = new \DateTime();
//        }
//        $this->updatedAt = new \DateTime();
//    }
//
//    /** @PreUpdate */
//    public function incrementUpdatedAt() {
//        $this->updatedAt = new \DateTime();
//    }

    /**
     * @param $message the $message to set
     */
    public function setMessage($message) {
        $this->message = $message;
    }

    /**
     * @param $by_user_id the $by_user_id to set
     */
    public function setUser($user) {
        $this->user = $user;
    }
}
Unable to find source-code formatter for language: php. Available languages are: actionscript, html, java, javascript, none, sql, xhtml, xml
                $article = $this->odm->getRepository('Bundle\ArticleBundle\Document\Article')->find("someID");

		$newComment = new Comment();
		$newComment->setUser($user);
		$newComment->setMessage("PPPPOOOOOPPPP");
		$newComment->setCreatedAt(new \DateTime());
		
		$comments = $article->getComments();
		$comments[] = $newComment;
		$article->setComments($comments);
		
		$this->odm->persist($article);
                // With or without the args to flush
		$this->odm->flush(array('safe' => true));

With the above - no exception or error is thrown. It appears that the comment is added - but checking the collection in mongo and there's nothing added to the document.
Removing the PreUpdate on the Article method allows the embedded document to be saved into Article.



 Comments   
Comment by Jonathan H. Wage [ 23/Aug/10 ]

Hi, can you provide a consolidated PHPUnit test case?

Comment by D Ashwood [ 23/Aug/10 ]

Just to clarify:

$parent = new ParentDocument();
$odm->persist($parent);
$odm->flush();

// count(parent->getChildren() ) = 0

// Add some children
$childOne = new childEmbededDocument();

$children = $parent->getChildren();
$children[] = $childOne;
$parent->setChildren($children);
$odm->persist($parent);

$childTwo = new childEmbededDocument();

$children = $parent->getChildren();
$children[] = $childTwo;
$parent->setChildren($children);
$odm->persist($parent);

// Results
// When $parent has lifeCycle callbacks - specifically @PreUpdate - count(parent->getChildren() ) = 0
// When $parent doesn't have lifeCycle callbacks - count(parent->getChildren() ) = 2

So the issue isn't so much about lifeCycle cascading to the children - it's that the parent lifeCycle callback @PreUpdate affects adding embedded children.

Comment by Jonathan H. Wage [ 23/Aug/10 ]

I am still not clear on what the problem is Jay said you were trying to use lifecycle callbacks on embedded documents which is not supported. You all seem to be talking about 2 different things?

Comment by Jonathan H. Wage [ 23/Aug/10 ]

Fixed by http://github.com/doctrine/mongodb-odm/commit/faf85a281b1562d184b44261a6e4dcdb13e03c5e

Comment by Jonathan H. Wage [ 24/Aug/10 ]

The callbacks will also work on embedded documents now.

Generated at Mon Sep 22 00:15:49 UTC 2014 using JIRA 6.2.3#6260-sha1:63ef1d6dac3f4f4d7db4c1effd405ba38ccdc558.