0
votes

I'm new in Symfony2. I've a task to create blog. One of the necessary is displaying most popular posts. So I think that the best varient is create listener. It will be call, when visiter will read post. And listener will increment onе of the fild in database(MySQL). I create method in repository, which makes selection by this field. And also create Action, which renders posts by this selection. But when I try to read post, a have error:

FatalErrorException: Error: Call to a member function getId() on a non-object in /var/www/blo/src/Blog/Bundle/BlogBundle/EventListener/PostVisitedListener.php line 20.

Please, help me.

This my Entity (Post):

namespace Blog\Bundle\BlogBundle\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use Gedmo\Mapping\Annotation as Gedmo;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * Post
 *
 * @ORM\Table(name="post")
 * @ORM\Entity(repositoryClass="Blog\Bundle\BlogBundle\Entity\PostRepository")
 */
class Post
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

/**
 * @var string
 *
 * @ORM\Column(name="title", type="string", length=255)
 * @Assert\NotBlank
 * @Assert\Length(min="13", max="255")
 */
 private $title;

    /**
     * @var string
     *
     * @ORM\Column(name="author", type="string", length=100)
     * @Assert\NotBlank
     * @Assert\Length(min="13", max="100")
     */
 private $author;

/**
 * @var string
 *
 * @ORM\Column(name="post", type="text")
 * @Assert\NotBlank
 * @Assert\Length(min="100")
 */
private $post;

/**
 * @var string
 *
 * @ORM\Column(name="image", type="string", length=100)
 */
private $image;

/**
 * @Gedmo\Timestampable(on="create")
 * @ORM\Column(name="createdAt", type="datetime")
 *
 */
private $createdAt;

/**
 *
 * @ORM\Column(name="tags", type="text")
 */
private $tags;

/**
 * @ORM\ManyToOne(targetEntity="Category", inversedBy="posts")
 */
private $category;

/**
 * @ORM\OneToMany(targetEntity="Comment", mappedBy="post")
 */
private $comments;


/**
 * @var integer
 *
 * @ORM\Column(name="visitedIncrement", type="integer")
 */

private $visitedIncrement;


public function __construct()
{
    $this->comments = new ArrayCollection();
}
/**
 * Get id
 *
 * @return integer
 */
public function getId()
{
    return $this->id;
}

/**
 * Set title
 *
 * @param string $title
 * @return Post
 */
public function setTitle($title)
{
    $this->title = $title;

    return $this;
}

/**
 * Get title
 *
 * @return string
 */
public function getTitle()
{
    return $this->title;
}

/**
 * Set author
 *
 * @param string $author
 * @return Post
 */
public function setAuthor($author)
{
    $this->author = $author;

    return $this;
}

/**
 * Get author
 *
 * @return string
 */
public function getAuthor()
{
    return $this->author;
}

/**
 * Set post
 *
 * @param string $post
 * @return Post
 */
public function setPost($post)
{
    $this->post = $post;

    return $this;
}

/**
 * Get post
 *
 * @return string
 */
public function getPost()
{
    return $this->post;
}

/**
 * Set image
 *
 * @param string $image
 * @return Post
 */
public function setImage($image)
{
    $this->image = $image;

    return $this;
}

/**
 * Get image
 *
 * @return string
 */
public function getImage()
{
    return $this->image;
}

/**
 * Set tags
 *
 * @param string $tags
 * @return Post
 */
public function setTags($tags)
{
    $this->tags = $tags;

    return $this;
}

/**
 * Get tags
 *
 * @return string
 */
public function getTags()
{
    return $this->tags;
}

/**
 * Set category
 *
 * @param $category
 * @return $this
 */
public function setCategory($category)
{
    $this->category = $category;

    return $this;
}

/**
 *  Get category
 *
 * @return integer
 */
public function getCategory()
{
    return $this->category;
}

/**
 * Set comments
 *
 * @param string $comments
 * @return Post
 */
public function setComments($comments)
{
    $this->comments = $comments;

    return $this;
}

/**
 * Get comments
 *
 * @return string
 */
public function getComments()
{
    return $this->comments;
}

/**
 * @param \DateTime $createdAt
 */
public function setCreatedAt($createdAt)
{
    $this->createdAt = $createdAt;

    return $this;
}

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

/**
 * @param int $visitedIncrement
 */
public function setVisitedIncrement($visitedIncrement)
{
    $this->visitedIncrement = $visitedIncrement;

    return $this;
}

/**
 * @return int
 */
public function getVisitedIncrement()
{
    return $this->visitedIncrement;
}

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

}

This is my PostRepository

public function visitedIncrement($id)
{
    $query = $this->getEntityManager()
        ->createQuery(
            'UPDATE BlogBlogBundle:Post p
             SET p.visitedIncrement = p.visitedIncrement + 1
             WHERE p.id = :post_id')
        ->setParameter(':post_id', $id);

    $query->execute();

This is my PostVisitedEvent

namespace Blog\Bundle\BlogBundle\Event;

use Blog\Bundle\BlogBundle\Entity\Post; use Symfony\Component\EventDispatcher\Event;

class PostVisitedEvent extends Event { protected $post;

/**
 * @param Post $post
 */
public function setPost(Post $post)
{
    return $this->post;
}


/**
 * @return Post
 */
public function getPost()
{
    return $this->post;
}

} 

This is my PostVisitedListener

namespace Blog\Bundle\BlogBundle\EventListener;

use Blog\Bundle\BlogBundle\Entity\PostRepository;
use Doctrine\ORM\EntityManager;
use Blog\Bundle\BlogBundle\Event\PostVisitedEvent;

class PostVisitedListener
{
protected $repository;

public function __construct(PostRepository $repository)
{
    $this->repository = $repository;
}

public function onPostVisited(PostVisitedEvent $event)
{
    $this->repository->visitedIncrement($event->getPost()->getId());
}

This is my Action (it opens post and gives a opportunity to create comment): public function showPostAction($id) { $postRepository = $this->container->get('blog_blog_bundle.post.repository'); $post = $postRepository->find($id);

    if (!$post) {
        throw $this->createNotFoundException('The post is not found!');
    }
    $commentRepository = $this->container->get('blog_blog_bundle.comment.repository');
    $comments = $commentRepository->findCommentForPost($post->getId());

    $event = new PostVisitedEvent();
    $event->setPost($post);

    $eventDispatcher = $this->get('event_dispatcher');
    $eventDispatcher->dispatch('blog_blog_bundle.post_visited', $event);

    return $this->render('BlogBlogBundle:Default:showPost.html.twig', array(
        'post' => $post,
        'comments' => $comments,
    ));
}

Yuo can see, that I also create services for repositories and listener. There are:

service id="blog_blog_bundle.post.repository"  class="Blog\Bundle\BlogBundle\Entity\PostRepository" factory-service="doctrine.orm.entity_manager" factory-method="getRepository"
        argument>BlogBlogBundle:Post argument
    service

    service id="blog_blog_bundle.comment.repository"       class="Blog\Bundle\BlogBundle\Entity\CommentRepository" factory-service="doctrine.orm.entity_manager" factory-method="getRepository"
        argument BlogBlogBundle:Comment argument
    service

    service id="blog_blog_bundle.post_visited_listener" class="Blog\Bundle\BlogBundle\EventListener\PostVisitedListener"
        argument type="service" id="blog_blog_bundle.post.repository" 
        tag name="kernel.event_listener" event="blog_blog_bundle.post_visited" method="onPostVisited" 
    service

Please, help me.

1

1 Answers

0
votes
public function onPostVisited(PostVisitedEvent $event)
{
    if (!($event->getPost() instanceof PostInterface)) return;
    $this->repository->visitedIncrement($event->getPost()->getId());
}

PostInterface is not a symfony interface. You have to code it. Asking for interface is better than asking for a concrete instance because symfony sometimes uses proxy classes instead of concrete classes.