Symfony / Doctrine - OneToMany too many queries - symfony

is there a way to lower lower one to many queries?
I have self-referenced one to many entity(category tree). I'm trying to get all children like this:
private function getChildren(string $category): array
{
$em = $this->getDoctrine();
$category = $em->getRepository(Category::class)->getByUrl($category);
$children = $category->getChildren();
$childrenArr = [];
if (!empty($children)) {
foreach ($children as $child) {
$childrenArr[] = $child->getId();
if (!empty($child->getChildren())) {
$this->getChildren($child->getUrl(), $childrenArr);
}
}
}
return $childrenArr;
}
Here is my repository:
public function getByUrl(string $url)
{
$qb = $this->createQueryBuilder('c');
$qb->where('c.url = :url');
$qb->setParameter('url', $url);
return $qb->getQuery()->useQueryCache(true)->getSingleResult();
}
Problem is, if it finds 5 children, it creates 57 queries... It's ridiculous.
UPDATE:
Entity structure:
/**
* One Category has Many Subcategories.
* #ORM\OneToMany(targetEntity="Category", mappedBy="parent", cascade={"persist"}, fetch="EAGER"))
*/
private $children;
/**
* Many Subcategories have One Category.
* #ORM\ManyToOne(targetEntity="Category", inversedBy="children", cascade={"persist"}, fetch="EAGER")
* #ORM\JoinColumn(name="parent_id", referencedColumnName="id")
*/
private $parent;
/**
* Add child
*
* #param \App\Entity\Product\Category $child
*
* #return Category
*/
public function addChild(\App\Entity\Product\Category $child): Category
{
$this->children[] = $child;
return $this;
}
/**
* Remove child
*
* #param \App\Entity\Product\Category $child
*/
public function removeChild(\App\Entity\Product\Category $child)
{
$this->children->removeElement($child);
}
/**
* Get children
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getChildren(): Collection
{
return $this->children;
}
/**
* Set parent
*
* #param \App\Entity\Product\Category $parent
*
* #return Category
*/
public function setParent(\App\Entity\Product\Category $parent = null): Category
{
$this->parent = $parent;
return $this;
}
/**
* Get parent
*
* #return \App\Entity\Product\Category
*/
public function getParent()
{
return $this->parent;
}
/**
* Add products
*
* #param \App\Entity\Product\Product $products
*
* #return Category
*/
public function addProducts(\App\Entity\Product\Product $products)
{
$this->products[] = $products;
return $this;
}
/**
* Remove products
*
* #param \App\Entity\Product\Product $products
*/
public function removeProducts(\App\Entity\Product\Product $products)
{
$this->products->removeElement($products);
}
/**
* Get products
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getProducts()
{
return $this->products;
}
Used fetch=EAGER it removed 2 queries(was 57 now its 55)

To avoid too many queries when I request all children, I do a fetch="EAGER" on my entity, it will automatically do a innerJoin from children table.
Ex:
/**
* #ORM\OneToMany(targetEntity="CoreBundle\Entity\Category", mappedBy="parent", cascade={"persist", "remove"}, fetch="EAGER")
*/
private $children;

Related

Doctrine Query Builder, between Product and Comment [symfony2]

When i'm viewing www.example.com/product/10 this product is link to a User Id. Now i would like to show only Comment that is link to the User id of the product a i'm viewing.
The table Comment is link to the table User, so each comment have is user id. The table Product (Post) is also link to the table user , each product have is user id.
For now the table Comment and Product are not yet link , i think they should be so i can perform a query, but i'm not sure.
I'm using FosCommentBundle for the comment.
Controller:
public function productAction($id, Request $request)
{
$session = $this->getRequest()->getSession();
$em = $this->getDoctrine()->getManager();
$findEntities = $em->getRepository('FLYBookingsBundle:Post')->findBy(array('id' => $id));
$entities = $this->get('knp_paginator')->paginate($findEntities, $this->get('request')->query->get('page', 1), 9
);
if ($session->has('cart'))
$cart = $session->get('cart');
else
$cart = false;
if (!$entities) {
throw $this->createNotFoundException('Unable to find Post entity.');
}
$id = 'thread_id';
$thread = $this->container->get('fos_comment.manager.thread')->findThreadById($id);
if (null === $thread) {
$thread = $this->container->get('fos_comment.manager.thread')->createThread();
$thread->setId($id);
$thread->setPermalink($request->getUri());
// Add the thread
$this->container->get('fos_comment.manager.thread')->saveThread($thread);
}
$comments = $this->container->get('fos_comment.manager.comment')->findCommentTreeByThread($thread);
return $this->render('FLYBookingsBundle:Post:product.html.twig', array('entity' => $entities,
'cart' => $cart,'comments' => $comments,
'thread' => $thread));
}
Product.html.twig
<div id="fos_comment_thread" data-thread="{{ thread.id }}">
{% include 'FOSCommentBundle:Thread:async.html.twig' with {
'comments': comments,
'thread': thread
} %}
Comment.php
<?php
namespace Application\Sonata\CommentBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use FOS\CommentBundle\Entity\Comment as BaseComment;
use FOS\CommentBundle\Model\SignedCommentInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use Application\Sonata\UserBundle\Entity\User;
/**
* #ORM\Entity
* #ORM\ChangeTrackingPolicy("DEFERRED_EXPLICIT")
*/
class Comment extends BaseComment implements SignedCommentInterface
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\generatedValue(strategy="AUTO")
*/
protected $id;
/**
* Thread of this comment
*
* #var Thread
* #ORM\ManyToOne(targetEntity="Application\Sonata\CommentBundle\Entity\Thread")
*/
protected $thread;
/**
* Author of the comment
*
* #ORM\ManyToOne(targetEntity="Application\Sonata\UserBundle\Entity\User")
* #var User
*/
protected $author;
/**
* Sets the author of the Comment
*
* #param UserInterface $user
*/
public function setAuthor(UserInterface $author)
{
$this->author = $author;
}
/**
* Gets the author of the Comment
*
* #return UserInterface
*/
public function getAuthor()
{
return $this->author;
}
public function getAuthorName()
{
if (null === $this->getAuthor()) {
return 'Anonymous';
}
return $this->getAuthor()->getUsername();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
}
Post.php
<?php
namespace FLY\BookingsBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Application\Sonata\UserBundle\Entity\User;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
use JMS\SecurityExtraBundle\Annotation\Secure;
use Symfony\Component\Validator\Constraints as Assert;
use Vich\UploaderBundle\Form\Type\VichImageType;
use Symfony\Component\HttpFoundation\File\File;
use Vich\UploaderBundle\Mapping\Annotation as Vich;
use Symfony\Component\Form\Extension\Core\Type\FileType;
/**
* Post
*
* #ORM\Table(name="post")
* #ORM\Entity(repositoryClass="FLY\BookingsBundle\Entity\PostRepository")
* #Vich\Uploadable
*/
class Post
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #Assert\Length(min=2, max=20)
*
* #ORM\Column(name="username", type="string", length=45, nullable=true)
*/
private $username;
/**
* #var string
*
* #Assert\Regex("/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+#[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/")
*
* #ORM\Column(name="email", type="string", length=45, nullable=false)
*/
private $email;
/**
* #ORM\ManyToOne(targetEntity="FLY\BookingsBundle\Entity\Tva")
* #ORM\joinColumn(onDelete="SET NULL")
*/
private $tva;
/**
* #ORM\ManyToOne(targetEntity="FLY\BookingsBundle\Entity\Media")
* #ORM\joinColumn(onDelete="SET NULL")
*/
private $image;
/**
* #var string
*
* #Assert\Length(max=350)
*
* #ORM\Column(name="description", type="text" , length=125, nullable=true)
*/
private $description;
/**
* #var float
*
* #Assert\NotBlank()
*
*
* #Assert\Regex(
* pattern= "/^[1-9]\d{0,7}(?:\.\d{1,4})?$/",
* message= "The First number can't start with 0"
* )
*
* #ORM\Column(name="price", type="float")
*/
private $price;
/**
*
*
* #ORM\ManyToOne(targetEntity="Application\Sonata\UserBundle\Entity\User")
* #ORM\JoinColumn(onDelete="CASCADE")
* #Security("user.getId() == post.getUser()")
*/
private $user;
/**
* #ORM\OneToOne(targetEntity="Quantity", cascade={"remove"})
* #ORM\JoinColumn(name="sold_id", referencedColumnName="id")
*/
protected $sold;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set username
*
* #param string $username
*
* #return Post
*/
public function setUsername($username)
{
$this->username = $username;
return $this;
}
/**
* Get username
*
* #return string
*/
public function getUsername()
{
return $this->username;
}
/**
* Set email
*
* #param string $email
*
* #return Post
*/
public function setEmail($email)
{
$this->email = $email;
return $this;
}
/**
* Get email
*
* #return string
*/
public function getEmail()
{
return $this->email;
}
/**
* Set price
*
* #param float $price
* #return Post
*/
public function setPrice($price)
{
$this->price = $price;
return $this;
}
/**
* Get price
*
* #return float
*/
public function getPrice()
{
return $this->price;
}
/**
* #return User
*/
public function getUser()
{
return $this->user;
}
/*
* #param User $user
*/
public function setUser(User $user)
{
$this->user = $user;
return $this;
}
/**
* Set tva
*
* #param \FLY\BookingsBundle\Entity\Tva $tva
* #return Post
*/
public function setTva(\FLY\BookingsBundle\Entity\Tva $tva)
{
$this->tva = $tva;
return $this;
}
/**
* Get tva
*
* #return \FLY\BookingsBundle\Entity\Tva
*/
public function getTva()
{
return $this->tva;
}
/**
* Set image
*
* #param \FLY\BookingsBundle\Entity\Media $image
* #return Post
*/
public function setImage(\FLY\BookingsBundle\Entity\Media $image)
{
$this->image = $image;
return $this;
}
/**
* Get image
*
* #return \FLY\BookingsBundle\Entity\Media
*/
public function getImage()
{
return $this->image;
}
/**
* Set description
*
* #param string $description
* #return Post
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* Get description
*
* #return string
*/
public function getDescription()
{
return $this->description;
}
/**
* Set sold
*
* #param integer $sold
* #return Post
*/
public function setSold($sold)
{
$this->sold = $sold;
return $this;
}
/**
* Get sold
*
* #return integer
*/
public function getSold()
{
return $this->sold;
}
/**
* NOTE: This is not a mapped field of entity metadata, just a simple property.
*
* #Vich\UploadableField(mapping="product_image", fileNameProperty="imageName")
*
* #var File
*/
private $imageFile;
/**
* #ORM\Column(type="string", length=255)
*
* #var string
*/
private $imageName;
/**
* #ORM\Column(type="datetime")
*
* #var \DateTime
*/
private $updatedAt;
/**
* If manually uploading a file (i.e. not using Symfony Form) ensure an instance
* of 'UploadedFile' is injected into this setter to trigger the update. If this
* bundle's configuration parameter 'inject_on_load' is set to 'true' this setter
* must be able to accept an instance of 'File' as the bundle will inject one here
* during Doctrine hydration.
*
* #param File|\Symfony\Component\HttpFoundation\File\UploadedFile $image
*
* #return User
*/
public function setImageFile(File $image = null)
{
$this->imageFile = $image;
if ($image) {
// It is required that at least one field changes if you are using doctrine
// otherwise the event listeners won't be called and the file is lost
$this->updatedAt = new \DateTime('now');
}
return $this;
}
/**
* #return File
*/
public function getImageFile()
{
return $this->imageFile;
}
/**
* #param string $imageName
*
* #return User
*/
public function setImageName($imageName)
{
$this->imageName = $imageName;
return $this;
}
/**
* #return string
*/
public function getImageName()
{
return $this->imageName;
}
}
ADD:
<?php
namespace Application\Sonata\CommentBundle\Entity;
use FLY\BookingsBundle\Entity\Post;
use Application\Sonata\UserBundle\Entity\User;
use Doctrine\ORM\EntityRepository;
class CommentRepository extends EntityRepository
{
/**
* Get Comments for a single Product.
* #param Post $post
* #return mixed
*/
public function getCommentsForSinglePost(Post $post)
{
$qb = $this->createQueryBuilder('c')
->where('c.post = :postId')
->setParameter('postId', $post->getId());
$query = $qb->getQuery();
return $query->execute();
}
}
Relation from Comment to Post(Product):
/**
* #ORM\ManyToOne(targetEntity="FLY\BookingsBundle\Entity\Post")
* #ORM\JoinColumn(nullable=true)
*/
private $post;
/**
* Set post
*
* #param \FLY\BookingsBundle\Entity\Post $post
* #return Comment
*/
public function setUser(\FLY\BookingsBundle\Entity\Post $post = null)
{
$this->post = $post;
return $this;
}
/**
* Get post
*
* #return \FLY\BookingsBundle\Entity\Post
*/
public function getPost()
{
return $this->post;
}
modication in controller:
public function productAction($id, Request $request, $post)
{
$session = $this->getRequest()->getSession();
$em = $this->getDoctrine()->getManager();
$findEntities = $em->getRepository('FLYBookingsBundle:Post')->findBy(array('id' => $id));
$entities = $this->get('knp_paginator')->paginate($findEntities, $this->get('request')->query->get('page', 1), 9
);
if ($session->has('cart'))
$cart = $session->get('cart');
else
$cart = false;
if (!$entities) {
throw $this->createNotFoundException('Unable to find Post entity.');
}
$post = 'thread_id';
$thread = $em->getRepository('ApplicationSonataCommentBundle:Comment')->getCommentsForSinglePost($post);
if (null === $thread) {
$thread = $this->container->get('fos_comment.manager.thread')->createThread();
$thread->setId($post);
$thread->setPermalink($request->getUri());
// Add the thread
$this->container->get('fos_comment.manager.thread')->saveThread($thread);
}
$comments = $this->container->get('fos_comment.manager.comment')->findCommentTreeByThread($thread);
return $this->render('FLYBookingsBundle:Post:product.html.twig', array('entity' => $entities,
'cart' => $cart,'comments' => $comments,'post' => $post,
'thread' => $thread));
}
Error:
Controller
"FLY\BookingsBundle\Controller\PostController::productAction()"
requires that you provide a value for the "$post" argument (because
there is no default value or because there is a non optional argument
after this one).
Considering you have Many-To-One association from Comment to Product. Here is how you should write a new method in CommentRepository to get list of comments for a single product.
/**
* Get Comments for a single Product.
* #param Product $product
* #return mixed
*/
public function getCommentsForSingleProduct(Product $product)
{
$qb = $this->createQueryBuilder('c')
->where('c.product = :productId')
->setParameter('productId', $product->getId());
$query = $qb->getQuery();
return $query->execute();
}
You can add any other condition as per your requirement. or add sort, or pagination etc..
Note : I haven't added user association. Let me know if you need anything else.

Pagination with KNP Paginator is not working at all

I tried very hard to get the KNP Paginator to work.
I only want to oder an Entity to the id, but the pagination accept all the params but does noting with it!
HereĀ“s my code:
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
The Controller class:
class StartController extends Controller
{
public function indexAction(Request $request)
{
$em = $this->getDoctrine()->getManager();
$dql = "SELECT a FROM MainArtBundle:Art a";
$query = $em->createQuery($dql);
$paginator = $this->get('knp_paginator');
$pagination = $paginator->paginate(
$query,
$request->query->get('page', 1) /*page number*/,
8 /*limit per page*/
);
$pagination->setUsedRoute('homepage');
if (!$pagination) {
throw $this->createNotFoundException('Unable to find Art entities.');
}
return $this->render('MainShowBundle:Default:index.html.twig', array(
'pagination' => $pagination,
));
}
The Twig Template:
<li>{{ knp_pagination_sortable(pagination, 'Oldest', 'a.id', {'direction': 'desc'}) }}</li>
<li>{{ knp_pagination_sortable(pagination, 'Newest', 'a.id', {'direction': 'asc'}) }}</li>
The ArtEntity (the entire Entity because perhaps the mistake is caused by the entity, can it be)
<?php
namespace Main\ArtBundle\Entity;
use Gedmo\Mapping\Annotation as Gedmo;
use Doctrine\ORM\Mapping as ORM;
use Main\LikeBundle\Entity\Thumb;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\HttpFoundation\Request;
/**
* Art
*
* #ORM\Table(name="art")
* #ORM\Entity(repositoryClass="Main\ArtBundle\Entity\ArtRepository")
*/
class Art
{
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string $locale
*
* #ORM\Column(name="locale", type="string", length=5, nullable=false)
*/
protected $locale;
/**
* #var arrayCollection $user
*
* #ORM\ManyToOne(targetEntity="Main\UserBundle\Entity\User", inversedBy="arts")
*
*/
protected $user;
/**
* #var \Doctrine\Common\Collections\ArrayCollection $visits
*
* #ORM\OneToMany(targetEntity="Main\ArtBundle\Entity\ArtVisit", mappedBy="art", fetch="EXTRA_LAZY")
*
*/
protected $visits;
/**
* #var \Doctrine\Common\Collections\ArrayCollection $tags
*
* #ORM\ManyToMany(targetEntity="Tags", inversedBy="arts", cascade={"persist"})
*/
protected $tags;
/**
* #var \Doctrine\Common\Collections\ArrayCollection $feature_partner
* #ORM\ManyToMany(targetEntity="Main\UserBundle\Entity\User", inversedBy="feature_partner")
*
*/
protected $feature_partner;
/**
* #var string $headline
*
* #Assert\NotBlank()
*
* #ORM\Column(type="string", length=255, unique=false, nullable=false)
*/
protected $headline;
/**
* #var \Main\StorageBundle\Entity\Image
*
* #ORM\OneToOne(targetEntity="Main\StorageBundle\Entity\Image")
* #ORM\Column(nullable=true)
*/
protected $image;
/**
* #var string $content
*
* #Assert\NotBlank()
*
* #ORM\Column(type="text", unique=false, nullable=false)
*/
protected $content;
/**
* #var string $description
*
* #ORM\Column(type="text", unique=false, nullable=true)
*/
protected $description;
/**
* #var datetime $created
*
* #Gedmo\Timestampable(on="create")
* #ORM\Column(type="datetime")
*/
private $created;
/**
* #var datetime $updated
*
* #Gedmo\Timestampable(on="update")
* #ORM\Column(type="datetime")
*/
private $updated;
/**
* #var datetime $contentChanged
*
* #ORM\Column(name="content_changed", type="datetime", nullable=true)
* #Gedmo\Timestampable(on="change", field={"headline", "content"})
*/
private $contentChanged;
/**
* #var integer $viewed
*
* #ORM\Column(name="viewed", type="integer", nullable=true)
*/
private $viewed;
/**
* #var object $CommentThread
*
*/
private $thread_id;
/**
* #var \Doctrine\Common\Collections\ArrayCollection $thumbs
*
* #ORM\OneToMany(targetEntity="Main\LikeBundle\Entity\Thumb", mappedBy="entity", fetch="EXTRA_LAZY")
*/
private $thumbs;
/**
* Constructor.
*/
public function __construct()
{
$this->tags = new \Doctrine\Common\Collections\ArrayCollection();
$this->feature_partner = new \Doctrine\Common\Collections\ArrayCollection();
$this->thumbs = new \Doctrine\Common\Collections\ArrayCollection();
$this->commentThread = new \Main\ArtBundle\Entity\CommentThread($this->getId());
/*$request = new Request();
$this->locale = $request->getLocale()*/;
}
/**
* #return string
*/
public function __toString()
{
return $this->getHeadline();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set user
*
* #param integer $userId
* #return Art
*/
public function setUserId($userId)
{
$this->user = $userId;
return $this;
}
/**
* Get user
*
* #return integer
*/
public function getUserId()
{
return $this->user;
}
/**
* Set tags
*
* #param integer $tags
* #return Art
*/
public function setTags($tags)
{
$this->tags = $tags;
return $this;
}
/**
* Get tags
*
* #return integer
*/
public function getTags()
{
return $this->tags;
}
/**
* Set headline
*
* #param string $headline
* #return Art
*/
public function setHeadline($headline)
{
$this->headline = $headline;
return $this;
}
/**
* Get headline
*
* #return string
*/
public function getHeadline()
{
return $this->headline;
}
/**
* Set content
*
* #param string $content
* #return Art
*/
public function setContent($content)
{
$this->content = $content;
return $this;
}
/**
* Get content
*
* #return string
*/
public function getContent()
{
return $this->content;
}
/**
* Set created
*
* #param \DateTime $created
* #return Art
*/
public function setCreated($created)
{
$this->created = $created;
return $this;
}
/**
* Get created
*
* #return \DateTime
*/
public function getCreated()
{
return $this->created;
}
/**
* Set updated
*
* #param \DateTime $updated
* #return Art
*/
public function setUpdated($updated)
{
$this->updated = $updated;
return $this;
}
/**
* Get updated
*
* #return \DateTime
*/
public function getUpdated()
{
return $this->updated;
}
/**
* Set contentChanged
*
* #param \DateTime $contentChanged
* #return Art
*/
public function setContentChanged($contentChanged)
{
$this->contentChanged = $contentChanged;
return $this;
}
/**
* Get contentChanged
*
* #return \DateTime
*/
public function getContentChanged()
{
return $this->contentChanged;
}
/**
* Set feature_partner
*
* #param integer $featurePartner
* #return Art
*/
public function setFeaturePartner($featurePartner)
{
$this->feature_partner = $featurePartner;
return $this;
}
/**
* Get feature_partner
*
* #return \Doctrine\Common\Collections\ArrayCollection
*/
public function getFeaturePartner()
{
return $this->feature_partner;
}
/**
* Add feature_partner
*
* #param \Main\UserBundle\Entity\User $featurePartner
* #return Art
*/
public function addFeaturePartner(\Main\UserBundle\Entity\User $featurePartner)
{
$this->feature_partner[] = $featurePartner;
return $this;
}
/**
* Remove feature_partner
*
* #param \Main\UserBundle\Entity\User $featurePartner
*/
public function removeFeaturePartner(\Main\UserBundle\Entity\User $featurePartner)
{
$this->feature_partner->removeElement($featurePartner);
}
/**
* Set description
*
* #param string $description
* #return Art
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* Get description
*
* #return string
*/
public function getDescription()
{
return $this->description;
}
/**
* Set user
*
* #param \Main\UserBundle\Entity\User $user
* #return Art
*/
public function setUser(\Main\UserBundle\Entity\User $user = null)
{
$this->user = $user;
return $this;
}
/**
* Get user
*
* #return \Main\UserBundle\Entity\User
*/
public function getUser()
{
return $this->user;
}
/**
* Add tags
*
* #param \Main\ArtBundle\Entity\Tags $tags
* #return Art
*/
public function addTag(\Main\ArtBundle\Entity\Tags $tags)
{
$this->tags[] = $tags;
return $this;
}
/**
* Remove tags
*
* #param \Main\ArtBundle\Entity\Tags $tags
*/
public function removeTag(\Main\ArtBundle\Entity\Tags $tags)
{
$this->tags->removeElement($tags);
}
/**
* Add visits
*
* #param \Main\ArtBundle\Entity\ArtVisit $visits
* #return Art
*/
public function addVisit(\Main\ArtBundle\Entity\ArtVisit $visits)
{
$this->visits[] = $visits;
return $this;
}
/**
* Remove visits
*
* #param \Main\ArtBundle\Entity\ArtVisit $visits
*/
public function removeVisit(\Main\ArtBundle\Entity\ArtVisit $visits)
{
$this->visits->removeElement($visits);
}
/**
* Get visits
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getVisits()
{
return $this->visits;
}
/**
* Set locale
*
* #param string $locale
* #return Art
*/
public function setLocale($locale)
{
$this->locale = $locale;
return $this;
}
/**
* Get locale
*
* #return string
*/
public function getLocale()
{
return $this->locale;
}
/**
* Set image
*
* #param \Main\StorageBundle\Entity\Image $image
* #return Art
*/
public function setImage(\Main\StorageBundle\Entity\Image $image = null)
{
$this->image = $image;
return $this;
}
/**
* Get image
*
* #return \Main\StorageBundle\Entity\Image
*/
public function getImage()
{
return $this->image;
}
/**
* Set viewed
*
* #param integer $viewed
* #return Art
*/
public function setViewed($viewed)
{
$this->viewed = $viewed;
return $this;
}
/**
* Get viewed
*
* #return integer
*/
public function getViewed()
{
return $this->viewed;
}
/**
* Set thumbs
*
* #param \Main\LikeBundle\Entity\Thumb $thumbs
* #return Art
*/
public function setThumbs(Thumb $thumbs = null)
{
$this->thumbs = $thumbs;
return $this;
}
/**
* Get thumbs
*
* #return \Doctrine\Common\Collections\ArrayCollection $thumbs
*/
public function getThumbs()
{
return $this->thumbs;
}
/**
* Add thumb
*
* #param \Main\LikeBundle\Entity\Thumb $thumb
* #return $this $thumbs
*/
public function addThumb(Thumb $thumb)
{
$this->thumbs[] = $thumb;
return $this;
}
/**
* Remove thumbs
*
* #param \Main\LikeBundle\Entity\Thumb $thumbs
*/
public function removeThumb(\Main\LikeBundle\Entity\Thumb $thumbs)
{
$this->thumbs->removeElement($thumbs);
}
/**
* Count all Thumbs of the piece of art.
*/
public function countAllThumbs() {
return $this->thumbs->count();
}
/**
* Check weather a user has thumbed a piece of art or not.
*/
public function isThumbed($user) {
// my first Closure :D
$p = function($key, $element) use ($user) {
return $element->getUser() == $user;
};
return $this->thumbs->exists($p);
}
/**
* Get the thumb object from a special user.
*/
public function getThumbFromUser ($user) {
$p = function($element) use ($user) {
return $element->getUser() == $user;
};
return $this->thumbs->filter($p);
}
}
The KNP Pagination Configuration (in config.yml)
knp_paginator:
page_range: 5 # default page range used in pagination control
default_options:
page_name: page # page query parameter name
sort_field_name: sort # sort field query parameter name
sort_direction_name: direction # sort direction query parameter name
distinct: true # ensure distinct results, useful when ORM queries are using GROUP BY statements
template:
pagination: ::Pagination\twitter_bootstrap_v3_pagination.html.twig # sliding pagination controls template
sortable: ::Pagination\sortable_link.html.twig # sort link template
I have dumped the pagination object in the controller and in the template as well. Everytime the params are there (direction= asc or desc) something like this is in the url:
?sort=a.id&direction=desc&page=1
but if I click on the link to change the direction: nothing change!!
I believe the knp pagination has a bug! Or I am very stupid ;)
If anyone can help me, I will be very happy!
Greetings Michael
For me, I created a new file knp_paginator.yaml and not knp_paginator.yml and I added this configuration and evrything works:
knp_paginator:
page_range: 5 # number of links shown in the pagination menu (e.g: you have 10 pages, a page_range of 3, on the 5th page you'll see links to page 4, 5, 6)
default_options:
page_name: page # page query parameter name
sort_field_name: sort # sort field query parameter name
sort_direction_name: direction # sort direction query parameter name
distinct: true # ensure distinct results, useful when ORM queries are using GROUP BY statements
filter_field_name: filterField # filter field query parameter name
filter_value_name: filterValue # filter value query parameter name
template:
pagination: '#KnpPaginator/Pagination/twitter_bootstrap_v4_pagination.html.twig' # sliding pagination controls template
sortable: '#KnpPaginator/Pagination/sortable_link.html.twig' # sort link template
filtration: '#KnpPaginator/Pagination/filtration.html.twig' # filters template

Symfony2 - Set related category to post dynamically

I'm new to Sf2/Doctrine2. I have a doctrine query that is retrieving related posts in the same category and excluding the current post that's being shown.
I need to figure out how to pass in category dynamically so I don't have to set this in the controller.
The show route is showing posts from different categories, and I'd like to only show posts related to that specific category without hardcoding it in the controller.
Can I get some help on how to fix this doctrine query?
Doctrine query
public function getRelatedPosts($exceptPost, $limit, $category) // Using Doctrine to exclude the shown post
{
return $this
->createQueryBuilder('post')
->leftJoin('post.category','category')
->where('post != :exceptPost')
->andWhere('category.title = :category')
->setParameter('category', $category)
->setMaxResults($limit)
->orderBy('post.createdAt', 'DESC')
->setParameter('exceptPost', $exceptPost)
->getQuery()
->execute();
}
Controller (setting category in controller -- How do I set this dynamically?)
/**
* Show action for post
*
* #param string $slug
* #throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
* #return array
*
* #Route("/{catslug}/{slug}", name="acme_demo_page_show")
* #Template("AcmeDemoBundle:Page:show.html.twig")
*/
public function showAction($slug)
{
$post = $this->getDoctrine()->getRepository('AcmeDemoBundle:Post')
->findOneBy(array(
'slug' => $slug
));
if (null === $post) {
throw $this->createNotFoundException('Post was not found');
}
$posts = $this->getDoctrine()->getRepository('AcmeDemoBundle:Post')
->getRelatedPosts($post, 4, 'articles');
return array(
'post' => $post,
'posts' => $posts
);
}
Category entity
class Category
{
/**
* #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)
*/
private $title;
/**
* #ORM\OneToMany(targetEntity="Post", mappedBy="category")
*/
protected $posts;
/**
* #var string
*
* #Gedmo\Slug(fields={"title"}, unique=false)
* #ORM\Column(length=255)
*/
private $catslug;
public function __construct()
{
$this->posts = new ArrayCollection();
}
public function __toString()
{
return $this->getTitle() ? $this->getTitle() : "";
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set title
*
* #param string $title
* #return Category
*/
public function setTitle($title)
{
$this->title = $title;
return $this;
}
/**
* Get title
*
* #return string
*/
public function getTitle()
{
return $this->title;
}
/**
* Add posts
*
* #param \Acme\DemoBundle\Entity\Post $posts
* #return Category
*/
public function addPost(\Acme\DemoBundle\Entity\Post $posts)
{
$this->posts[] = $posts;
return $this;
}
/**
* Remove posts
*
* #param \Acme\DemoBundle\Entity\Post $posts
*/
public function removePost(\Acme\DemoBundle\Entity\Post $posts)
{
$this->posts->removeElement($posts);
}
/**
* Get posts
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getPosts()
{
return $this->posts;
}
/**
* Set catslug
*
* #param string $catslug
* #return Category
*/
public function setCatSlug($catslug)
{
$this->slug = $catslug;
return $this;
}
/**
* Get slug
*
* #return string
*/
public function getCatSlug()
{
return $this->catslug;
}
}
Post entity
/**
* #ORM\ManyToOne(targetEntity="Category", inversedBy="posts")
* #ORM\JoinColumn(name="category_id", referencedColumnName="id")
*/
protected $category;
/**
* Set category
*
* #param \Acme\AcmeDemoBundle\Entity\Category $category
* #return Post
*/
public function setCategory(\Acme\AcmeDemoBundle\Entity\Category $category = null)
{
$this->category = $category;
return $this;
}
/**
* Get category
*
* #return \Acme\AcmeDemoBundle\Entity\Category
*/
public function getCategory()
{
return $this->category;
}
from you controller use $post->getCategory() to retrieve the post Category.
In you'r query, all you have to do is ->setParameter('category', $category)

Symfony2 - Select tags to bring up posts

I'm trying to setup selectable Tags to display/bring up Blogs that are linked to the tags.
What am I doing wrong? Is the problem with the doctrine query or how it's been setup on the entity side?
I'm getting the following error:
ContextErrorException: Notice: Undefined index: joinColumns in /.../vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php line 1665
This is the current query I am using:
public function tagAction($tag)
{
$em = $this->getDoctrine()->getManager();
$tags = $em->getRepository('AcmeBundle:Blog')
->findByTags($tag);
$blogs = $tags->getBlogs();
return array(
'blogs' => $blogs,
);
}
And my entity setup: (Setup as ManyToMany/ManyToMany)
Tag:
/**
* #ORM\ManyToMany(targetEntity="Blog", mappedBy="tags")
*/
protected $blogs;
public function __construct()
{
$this->blogs = new ArrayCollection();
}
/**
* Add blogs
*
* #param \AcmeBundle\Entity\Blog $blogs
* #return Tag
*/
public function addBlog(\AcmeBundle\Entity\Blog $blogs)
{
$this->blogs[] = $blogs;
return $this;
}
/**
* Remove blogs
*
* #param \AcmeBundle\Entity\Blog $blogs
*/
public function removeBlog(\AcmeBundle\Entity\Blog $blogs)
{
$this->blogs->removeElement($blogs);
}
/**
* Get blogs
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getBlogs()
{
return $this->blogs;
}
Blog:
/**
* #ORM\ManyToMany(targetEntity="Tag", inversedBy="blogs")
* #ORM\JoinColumn(name="tag_id", referencedColumnName="id")
*/
protected $tags;
public function __construct()
{
$this->tags = new ArrayCollection();
}
/**
* Add tags
*
* #param \AcmeBundle\Entity\Tag $tags
* #return Blog
*/
public function addTag(\AcmeBundle\Entity\Tag $tags)
{
$this->tags[] = $tags;
return $this;
}
/**
* Remove tags
*
* #param \AcmeBundle\Entity\Tag $tags
*/
public function removeTag(\AcmeBundle\Entity\Tag $tags)
{
$this->tags->removeElement($tags);
}
/**
* Get tags
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getTags()
{
return $this->tags;
}
Instead of querying for blog use tag.
$em = $this->getDoctrine()->getManager();
$tags = $em->getRepository('AcmeBundle:Tag')
->findOneByTag($tag);
$blogs = $tags->getBlogs();
return array(
'blogs' => $blogs,
);
I think this error happens because you have the wrong annotation for ManyToMany associations in:
/**
* #ORM\ManyToMany(targetEntity="Tag", inversedBy="blogs")
* #ORM\JoinColumn(name="tag_id", referencedColumnName="id")
*/
protected $tags;
For ManyToMany associations I use code as below:
/**
* #ManyToMany(targetEntity="Tag")
* #JoinTable(name="blogs_tags",
* joinColumns={#JoinColumn(name="blog_id", referencedColumnName="id")},
* inverseJoinColumns={#JoinColumn(name="tag_id", referencedColumnName="id")}
* )
*/
protected $tags;
This is the code as in the official documentation of Doctrine as you can see in http://docs.doctrine-project.org/en/2.0.x/reference/association-mapping.html

FindByTags with Symfony2?

I grab this kind of array.
This is a var_dump of my $tags variable.
array(2) { [0]=> string(1) "3" [1]=> string(1) "4" }
My entity
<?php
namespace Lan\CrmBundle\Entity;
use Doctrine\ORM\Mapping AS ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* #ORM\Entity
*/
class Link
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(type="string", length=255, nullable=false)
* #Assert\NotBlank()
*/
private $url;
/**
* #ORM\Column(type="text", nullable=true)
*/
private $description;
/**
* #ORM\Column(type="datetime", nullable=true)
*/
private $created_at;
/**
* #ORM\ManyToOne(targetEntity="Lan\SecurityBundle\Entity\User", inversedBy="links")
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
*/
private $user;
/**
* #ORM\ManyToMany(targetEntity="Lan\CrmBundle\Entity\LinkTag", inversedBy="links")
* #ORM\JoinTable(
* name="LinkTagToLink",
* joinColumns={#ORM\JoinColumn(name="link_id", referencedColumnName="id", nullable=false)},
* inverseJoinColumns={#ORM\JoinColumn(name="link_tag_id", referencedColumnName="id", nullable=false)}
* )
*/
private $tags;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set url
*
* #param string $url
* #return Link
*/
public function setUrl($url)
{
$this->url = $url;
return $this;
}
/**
* Get url
*
* #return string
*/
public function getUrl()
{
return $this->url;
}
/**
* Set description
*
* #param string $description
* #return Link
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* Get description
*
* #return string
*/
public function getDescription()
{
return $this->description;
}
/**
* Set created_at
*
* #param \DateTime $createdAt
* #return Link
*/
public function setCreatedAt($createdAt)
{
$this->created_at = $createdAt;
return $this;
}
/**
* Get created_at
*
* #return \DateTime
*/
public function getCreatedAt()
{
return $this->created_at;
}
/**
* Set user
*
* #param \Lan\SecurityBundle\Entity\User $user
* #return Link
*/
public function setUser(\Lan\SecurityBundle\Entity\User $user = null)
{
$this->user = $user;
return $this;
}
/**
* Get user
*
* #return \Lan\SecurityBundle\Entity\User
*/
public function getUser()
{
return $this->user;
}
/**
* Constructor
*/
public function __construct()
{
$this->tags = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Add tags
*
* #param \Lan\CrmBundle\Entity\LinkTag $tags
* #return Link
*/
public function addTag(\Lan\CrmBundle\Entity\LinkTag $tags)
{
$this->tags[] = $tags;
return $this;
}
/**
* Remove tags
*
* #param \Lan\CrmBundle\Entity\LinkTag $tags
*/
public function removeTag(\Lan\CrmBundle\Entity\LinkTag $tags)
{
$this->tags->removeElement($tags);
}
/**
* Get tags
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getTags()
{
return $this->tags;
}
}
My entire controller:
namespace Lan\CrmBundle\Controller;
use Lan\CrmBundle\Entity\Link;
use Lan\CrmBundle\Form\LinkType;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
class LinkController extends Controller {
public function indexAction(Request $request)
{
$em = $this->getDoctrine()->getManager();
$tags = $em->getRepository('LanCrmBundle:LinkTag')->findAll();
if($request->query->has('tags')) {
$tags = $request->query->get('tags');
//var_dump($tags); die();
$links = $em->getRepository('LanCrmBundle:Link')->findByTags($tags);
var_dump($links); die();
} else {
$links = $em->getRepository('LanCrmBundle:Link')->findBy(
array(),
array('id' => 'desc')
);
}
$paginator = $this->get('knp_paginator');
$pagination = $paginator->paginate(
$links,
$this->get('request')->query->get('page', 1),
4
);
return $this->render('LanCrmBundle:Link:index.html.twig', compact('pagination', 'tags'));
}
}
But I got this error:
ContextErrorException: Notice: Undefined index: joinColumns in ...
I think I can't use ->findByTags() like I want...
Thanks in advance!
I don't think you can findByTags because SF2 won't know if you want AND or OR for tags.
The only solution I can suggest you is that you need to query from link_tag table (use repository LanCrmBundle:LinkTag) manually to get all link.id then continue to retrieve link data using LanCrmBundle:Link.
I found a way but not really what I want :
public function findByUsersAndTags($users, $tags)
{
$queryBuilder = $this->createQueryBuilder('l')
->leftJoin('l.tags', 't')->addSelect('t')
->leftJoin('l.user', 'u')->addSelect('u')
->orderBy('l.id', 'desc');
if($users) {
foreach($users as $user_id) {
$queryBuilder->orHaving('u.id = :id')->setParameter('id', $user_id);
}
}
if($tags) {
foreach($tags as $tag_id) {
$queryBuilder->orHaving('t.id = :id')->setParameter('id', $tag_id);
}
}
return $queryBuilder->getQuery()->getResult();
}

Resources