Doctrine DiscriminatorMap clause Where - doctrine-orm

I need to perform a query with the doctrine in an entity of the type DiscriminatorMap, where my condition where is within the inheritance class
Order
<?php
namespace App\Domain;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="OrderRepository")
* #ORM\Table(name="orders")
* #ORM\HasLifecycleCallbacks()
*/
class Order
{
/**
* #ORM\OneToOne(targetEntity="Customer", mappedBy="orders", cascade={"persist"})
* #ORM\JoinColumn(name="fk_cliente", referencedColumnName="id_cliente")
* #JMS\Groups ({"list", "details"})
* #var Customer
*/
private $customer;
/**
* #return Person|Company
*/
public function getCustomer(): Customer
{
return $this->customer;
}
....
Customer
<?php
namespace App\Domain;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="CustomerRepository")
* #ORM\HasLifecycleCallbacks()
* #ORM\InheritanceType("JOINED")
* #ORM\DiscriminatorColumn(name="tipo", type="string")
* #ORM\DiscriminatorMap({"customer" = "Customer", "F" = "Person", "J" = "Company"})
* #ORM\Table(name="clientes")
*/
class Customer
{
use TimestampableTrait;
....
expect
$query = $qb->select('p')
->from(\App\Domain\Order::class, 'p')
->leftJoin('p.customer', 'c')
->setMaxResults((int)$params['limit'])
->setFirstResult((int)$params['offset']);
$query->andWhere($qb->expr()->isNotNull('c.document'));
I need to return all sales where the customers are person or company type the document is not null

Related

Symfony create new object many to one error call undefined method

I have set up a many to one relation and want to add a new product-object linked to its category. Related to this I have 2 questions:
I get stuck on saving the category object to the new product. Tried different options and read related questions here. At this moment I am getting the error:
Attempted to call an undefined method named "getCategory" of class "AppBundle\Controller\ProductController".
I do have the method getCategory in my Product class.
What am I missing here?
Another thing I would like to know is do I need to pass the category-id in the url to get the related products for that category?
I have a category class:
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #ORM\Entity
* #ORM\Table(name="category")
*/
class Category
{
/**
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
* #ORM\Column(type="integer")
*/
private $cat_id;
...
/**
* #ORM\OneToMany(targetEntity="Product", mappedBy="category")
*/
private $products; ...
public function __construct()
{
$this->products = new ArrayCollection();
}
and product class:
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use AppBundle\Entity\Category;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #ORM\Entity
* #ORM\Table(name="product")
*/
class Product
{
/**
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
* #ORM\Column(type="integer")
*/
private $prd_id;
/**
* #var Category
*
* #ORM\ManyToOne(targetEntity="Category", inversedBy="products")
* #ORM\JoinColumn(name="cat_id", referencedColumnName="cat_id", nullable=false)
*/
private $category;
....
/**
* Set category
*
* #param \AppBundle\Entity\Category $category
*
* #return Product
*/
public function setCategory(\AppBundle\Entity\Category $category)
{
$this->category = $category;
return $this;
}
/**
* Get category
*
* #return \AppBundle\Entity\Category
*/
public function getCategory()
{
return $this->category;
}
From my list of categories "/categories" I link the categories to the productlist "/cat1/product" (<-- do I need to pass the category-id here?). There I want to add a new product and call the following action in my ProductController:
namespace AppBundle\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Response;
use AppBundle\Entity\Product;
use AppBundle\Form\ProductType;
use Symfony\Component\HttpFoundation\Request;
class ProductController extends Controller
{
/**
* #Route("/cat{cat_id}/product/new", name="newproduct")
*/
public function newAction(Request $request, $cat_id)
{
$product = new Product();
$form = $this->createForm(ProductType::class, $product);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$category = $this->getCategory();
$product->setCategory($category);
$em = $this->getDoctrine()->getManager();
$em->persist($product);
$em->flush();
return $this->redirectToRoute('productlist');
}
return $this->render('product/new.html.twig', array(
'form' => $form->createView(),
'cat_id' => $cat_id,
));
}
Suggestions appreciated!
when you do :
$category = $this->getCategory();
$this represent your productController, it is the reason of the undefined method error. to get the category object you must do :
$categoryRepository = $this->getDoctrine()->getRepository('AppBundle:Category');
$product->setCategory($categoryRepository->find($cat_id));
hope that may help you.

Doctrine 2 Association Mapping (ManyToOne and OneToMany)

I am new with Doctrine2 and need some help.
I have 2 Entities: LocationEntity and RatingEntity
RatingEntity
<?php
use Doctrine\ORM\Mapping as ORM;
/**
* Rating
*
* #ORM\Entity
* #ORM\Table(name="`RATING`")
*/
class RatingEntity {
/**
*
* #var int
* #ORM\Id
* #ORM\Column(name="`ID`", type="integer", nullable=false)
* #ORM\GeneratedValue(strategy="SEQUENCE")
* #ORM\SequenceGenerator(sequenceName="RATING_ID_SEQ", initialValue=1, allocationSize=1)
*/
protected $id;
/**
*
* #var int
* #ORM\Column(name="`LOCATION_ID`", type="integer")
*/
protected $locationId;
/**
* #var LocationEntity
* #ORM\ManyToOne(targetEntity="LocationEntity", inversedBy="ratings")
* #ORM\JoinColumn(name="`LOCATION_ID`", referencedColumnName="`ID`")
*/
protected $location;
/**
* #return the $location
*/
public function getLocation() {
return $this->location;
}
/**
* #param field_type $location
*/
public function setLocation($location) {
$this->location = $location;
}
and LocationEntity
<?php
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
/**
* Location
*
* #ORM\Entity
* #ORM\Table(name="`LOCATION`")
*/
class LocationEntity {
/**
*
* #var int
* #ORM\Id
* #ORM\Column(name="`ID`", type="integer", nullable=false)
* #ORM\GeneratedValue(strategy="SEQUENCE")
* #ORM\SequenceGenerator(sequenceName="LOCATION_ID_SEQ", initialValue=1, allocationSize=1)
*/
protected $id;
/**
*
* #var ArrayCollection
* #ORM\OneToMany(targetEntity="RatingEntity", mappedBy="location", cascade={"persist"}, fetch="LAZY")
*/
protected $ratings;
/**
* #return the $ratings
*/
public function getRatings() {
return $this->ratings;
}
/**
* #param \Doctrine\Common\Collections\ArrayCollection $ratings
*/
public function setRatings($ratings) {
$this->ratings = $ratings;
}
/**
* Never forget to initialize all your collections!
*/
public function __construct() {
$this->ratings = new ArrayCollection();
}
If I get locations, i get ratings for location as Array,
but if I want to get Rating and Location for it, I get NULL only in getLocation().
Can somebody help?
I don't think that you need the locationId property in your Rating entity as the column is already mapped using the location property. Try removing the locationId section and see if it doesn't work as expected.

Doctrine2: Many-To-Many with extra columns in reference table (add record)

Spoiler: I think I found the answer but I'm not 100% sure ;)
I've been looking at this question for a while but I cannot manage to make it work. So I've create dummies Entities to test the relation and here they are:
A Product can be in many Cart
A Cart can contains several Product
The Product in a Cart are order by a position
Product
<?php
namespace Acme\DemoBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\Validator\Constraints as Assert;
/**
* #ORM\Entity
* #ORM\Table(name="demo_product")
*/
class Product
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\OneToMany(targetEntity="CartHasProduct", mappedBy="product", cascade={"all"})
*/
protected $productCarts;
/**
* Constructor
*/
public function __construct()
{
$this->productCarts = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Add productCarts
*
* #param \Acme\DemoBundle\Entity\CartHasProduct $productCarts
* #return Product
*/
public function addProductCart(\Acme\DemoBundle\Entity\CartHasProduct $productCarts)
{
$this->productCarts[] = $productCarts;
return $this;
}
/**
* Remove productCarts
*
* #param \Acme\DemoBundle\Entity\CartHasProduct $productCarts
*/
public function removeProductCart(\Acme\DemoBundle\Entity\CartHasProduct $productCarts)
{
$this->productCarts->removeElement($productCarts);
}
/**
* Get productCarts
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getProductCarts()
{
return $this->productCarts;
}
}
Cart
<?php
namespace Acme\DemoBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\Validator\Constraints as Assert;
/**
* #ORM\Entity
* #ORM\Table(name="demo_cart")
*/
class Cart
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\OneToMany(targetEntity="CartHasProduct", mappedBy="cart", cascade={"all"})
*/
protected $cartProducts;
/**
* Constructor
*/
public function __construct()
{
$this->cartProducts = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Add cartProducts
*
* #param \Acme\DemoBundle\Entity\CartHasProduct $cartProducts
* #return Cart
*/
public function addCartProduct(\Acme\DemoBundle\Entity\CartHasProduct $cartProducts)
{
$this->cartProducts[] = $cartProducts;
return $this;
}
/**
* Remove cartProducts
*
* #param \Acme\DemoBundle\Entity\CartHasProduct $cartProducts
*/
public function removeCartProduct(\Acme\DemoBundle\Entity\CartHasProduct $cartProducts)
{
$this->cartProducts->removeElement($cartProducts);
}
/**
* Get cartProducts
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getCartProducts()
{
return $this->cartProducts;
}
}
and finally CartHasProduct reference table
<?php
namespace Acme\DemoBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\Validator\Constraints as Assert;
/**
* #ORM\Entity
* #ORM\Table(name="demo_cartHasProduct")
*/
class CartHasProduct
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\ManyToOne(targetEntity="Cart", inversedBy="productCarts")
*/
protected $cart;
/**
* #ORM\ManyToOne(targetEntity="Product", inversedBy="cartProducts")
*/
protected $product;
/**
* #ORM\Column(type="integer")
*/
protected $position;
public function __construct(Cart $cart, Product $product, $position=0) {
$this->cart = $cart;
$this->product = $product;
$this->setPosition($position);
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set position
*
* #param integer $position
* #return CartHasProduct
*/
public function setPosition($position)
{
$this->position = $position;
return $this;
}
/**
* Get position
*
* #return integer
*/
public function getPosition()
{
return $this->position;
}
/**
* Set cart
*
* #param \Acme\DemoBundle\Entity\Cart $cart
* #return CartHasProduct
*/
public function setCart(\Acme\DemoBundle\Entity\Cart $cart = null)
{
$this->cart = $cart;
return $this;
}
/**
* Get cart
*
* #return \Acme\DemoBundle\Entity\Cart
*/
public function getCart()
{
return $this->cart;
}
/**
* Set product
*
* #param \Acme\DemoBundle\Entity\Product $product
* #return CartHasProduct
*/
public function setProduct(\Acme\DemoBundle\Entity\Product $product = null)
{
$this->product = $product;
return $this;
}
/**
* Get product
*
* #return \Acme\DemoBundle\Entity\Product
*/
public function getProduct()
{
return $this->product;
}
}
I've created the Entities manually, adding the #ORM annotations to setup the relationship and then I've used app/console generate:doctrine:entities AcmeDemoBundle to populate the getter, setter and __construct
Now I a controller I have to following code:
<?php
namespace Acme\DemoBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class WelcomeController extends Controller
{
public function indexAction()
{
// Create a Cart Entity
$cart = new \Acme\DemoBundle\Entity\Cart();
// Create a Product Entity
$product = new \Acme\DemoBundle\Entity\Product();
// Add the Product into the Cart
$cart->getCartProducts()->add($product);
// Save the Cart
$em = $this->getDoctrine()->getManager();
$em->persist($cart);
$em->flush();
return $this->render('AcmeDemoBundle:Welcome:index.html.twig');
}
}
Doing so I have the following error coming up:
Found entity of type Acme\DemoBundle\Entity\Product on association Acme\DemoBundle\Entity\Cart#cartProducts, but expecting Acme\DemoBundle\Entity\CartHasProduct
So my question is how to add a Product into a Cart? Do I need to create the relation Object manually (CartHasProduct)? I would think Doctrine would have done it. I looked everywhere on Doctrine documentation and I could not find an exemple of relationship with extra field.
I've also looked into the tests in the vendor, there is plenty of model (very interesting) but nothing with extra field in relationship.
I was thinking the create my own method in Cart like this:
public function addProduct(Product $product, $position=0) {
$relation = new CartHasProduct($this, $product, $position);
if (!$this->cartProducts->contains($relation)) {
$this->cartProducts->add($relation);
}
}
But I'd like to know if I need to implement it or if it's meant to be handled automatically?
#### UPDATE 1 ####
So I ended up adding this method addProduct. The problem is that contains() is not working as expected. So I tried to delete all Product from the Cart and add a new one.
Here is my function to delete the products:
/**
* Reset the product for the cart
*
* #return bool
*/
public function resetCart() {
foreach ($this->getCartProducts() as $relation) {
$relation->getProduct()->removeProductCart($relation);
$this->removeCartProducts($relation);
}
}
and here is how I call it:
$em = $this->getDoctrine()->getManager();
$cart->resetCart();
$em->persist($cart);
$em->flush();
But the records are not deleted in CartHasProduct table.
UPDATE 2
I found what was the problem, you need to add orphanRemoval=true in the OneTwoMany relation (on both side) if you want to delete the relationship between the 2 main Entity (Cart and Product):
/**
* #ORM\Entity
* #ORM\Table(name="demo_product")
*/
class Product
{
...
/**
* #ORM\OneToMany(targetEntity="CartHasProduct", mappedBy="product", cascade={"persist", "remove"}, orphanRemoval=true)
*/
protected $productCarts;
And
/**
* #ORM\Entity
* #ORM\Table(name="demo_cart")
*/
class Cart
{
...
/**
* #ORM\OneToMany(targetEntity="CartHasProduct", mappedBy="cart", cascade={"persist", "remove"}, orphanRemoval=true)
*/
protected $cartProducts;
...
/**
* Reset the product for the cart
*/
public function resetCart() {
$this->getCartProducts()->clear();
}
Cheers,
Maxime
Well many to many association with extra parameters can be implemented by using a third intermediate entity. You have the right approach, but wrong associations defined. Here's how it should be.
Taking your 3 entities Product, Cart, CartProducts
Cart should have a one-to-many relationship with CartProducts
CartProducts should have many-to-one relationship to Product and Many-to-one association with Cart
So you first initialize a Cart, and add products to Cart like this:
For every Product
initialize a CartProduct with the Product and Cart and other extra parameters you need.
Add it to the Cart

OneToMany invalid Mapping

i am trying to create a oneToMany relationship. Since Doctrine only offers ManyToOne Unidirectional im using that. Somehow the validation of the mapping fails and I am not able to spot my mistake:
Validation Error:
[Mapping] FAIL - The entity-class 'Strego\TippBundle\Entity\BetRound'
mapping is invalid:
* The association Strego\TippBundle\Entity\BetRound#userStatus refers to the owning side field
Strego\TippBundle\Entity\UserBetRoundStatus#betRound which does not
exist.
My First Entity (BetRound):
<?php
namespace Strego\TippBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\Collection as Collection;
use Strego\AppBundle\Entity\Base as BaseEntity;
/**
* Strego\TippBundle\Entity\BetRound
*
* #ORM\Table()
* #ORM\Entity
*/
class BetRound extends BaseEntity {
//......
/**
*
* #var Collection
* #ORM\OneToMany(targetEntity="UserBetRoundStatus", mappedBy="betRound", cascade={"all"})
*/
protected $userStatus;
}
My related Entity(UserBetRoundStatus)
<?php
namespace Strego\TippBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Strego\AppBundle\Entity\Base as BaseEntity;
/**
* Strego\TippBundle\Entity\Game
*
* #ORM\Table
* #ORM\Entity
* #UniqueEntity(fields={"user", "betRound"}, message="Unique Entity Validator Fails for UserStatus", groups="unique")
*
*/
class UserBetRoundStatus extends BaseEntity {
// .....
/*
* #var BetRound
* #ORM\ManyToOne(targetEntity="BetRound", inversedBy="userStatus")
* #ORM\JoinColumn(name="betround_id", referencedColumnName="id", nullable=false)
* #Assert\NotNull()
*/
protected $betRound;
}
I have found the issue:
/** <--------- you need two *
* #var BetRound
* #ORM\ManyToOne(targetEntity="BetRound", inversedBy="userStatus")
* #ORM\JoinColumn(name="betround_id", referencedColumnName="id", nullable=false)
* #Assert\NotNull()
*/
protected $betRound;

doctrine2 slugable and datafixtures

I'm trying to make a Field of a Object slugable.
Model looks like:
namespace myBundle\Bundles\BlogBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Gedmo\Mapping\Annotation as Gedmo;
/**
* myBundle\Bundles\BlogBundle\Entity\Category
*
* #ORM\Table()
* #ORM\Entity
*/
class Category
{
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string $title
*
* #Gedmo\Sluggable
* #ORM\Column(name="title", type="string", length=255)
*/
private $title;
/**
* #Gedmo\Slug(separator="-", updatable=false, unique=true)
* #ORM\Column(name="slug", type="string", length=255, unique=true)
*/
private $slug;
// other properties and methods
The Fixtures:
namespace myBundle\Bundles\BlogBundle\DataFixtures\ORM;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use tooMuch\Bundles\BlogBundle\Entity\Category;
class LoadCategoryData extends AbstractFixture implements OrderedFixtureInterface
{
public function load($manager)
{
$this->generateCategory($manager);
}
public function generateCategory($manager)
{
for ($i=0; $i < 10; $i++) {
$category = new Category();
$category->setTitle('Category '.$i);
$manager->persist($category);
$manager->flush();
$this->addReference('category'.$i, $category);
unset($category);
}
}
schema create:
# sf doctrine:schema:create
ATTENTION: This operation should not be executed in a production environment.
Creating database schema...
Database schema created successfully!
but then when I'm trying to add the fixtures:
# sf doctrine:fixtures:load
> purging database
> loading myBundle\Bundles\BlogBundle\DataFixtures\ORM\LoadCategoryData
[PDOException]
SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'slug' cannot be null
doctrine:fixtures:load [--fixtures[="..."]] [--append] [--em="…"]
#
any ideas?
The problem isn't in the fixtures, it's in Slug generation itself. If it's properly set up, you should never have $slug as null
Are you sure you have Sluggable listener attached?