I'm a beginner on Symfony 2 and I have a problem with a DQL query : I'm trying to display a property that is an ArrayCollection.
Here's my case : Two classes joined together with a "ManyToOne" and "OneToMany"
DishGrade.php :
/**
* #var Dish $dish
*
* #ORM\ManyToOne(targetEntity="Dish", inversedBy="grades",
cascade={"persist", "remove", "merge"})
* #ORM\JoinColumn(name="dish_id", referencedColumnName="id", nullable=false)
*
*/
private $dish;
Dish.php :
/**
* #var \Doctrine\Common\Collections\Collection $grades
*
* #ORM\OneToMany(targetEntity="DishGrade", mappedBy="dish", cascade={"all"},
orphanRemoval=true)
*/
private $grades;
Then here's my controller which returns an array of objects "DishGrade"
/**
* Get grades dish.
*
*
* #ApiDoc(
* output = "Awadac\ApiBundle\Model\Dish",
* statusCodes = {
* 200 = "Returned when successful",
* 404 = "Returned when the dish is not found"
* }
* )
*
* #Get("/dishes/{id}")
*
* #param Request $request the request object
* #param int $id the dish id
*
* #return array
*
* #throws NotFoundHttpException when dish not exist
*/
public function getDishAction(Request $request, $id)
{
$dish = $this->getDishManager()->getRepository()->getGrades($id);
if (!$dish) {
throw $this->createNotFoundException('Dish does not exist.');
}
return $dish;
}
And here's my query that doesn't work :
DishRepository.php :
public function getGrades($id){
$qb = $this->_em->createQueryBuilder();
return $qb->select('d.grades')
->from('AwadacApiBundle:Dish', 'd')
->where('d.id = :id')
->setParameter('id', $id)
->getQuery()
->getResult();
}
the error code I get :
{"code":500,"message":"[Semantical Error] line 0, col 9 near 'grades FROM AwadacApiBundle:Dish': Error: Invalid PathExpression. Must be a StateFieldPathExpression.","errors":null}
And when I want to get all the properties from my object "Dish" it works, so I just wonder why I can't display this ArrayCollection alone.
Thank you for your time !
If you are already in the DishRepository you will be able to create the query builder by
$qb = $this->createQueryBuilder('d');
Further just remove the ->from() statement and I guess it should work properly:
return $qb->select('d.grades')
->where('d.id = :id')
->setParameter('id', $id)
->getQuery()
->getResult();
Related
I use an Entity X like this:
/**
* #Entity
* #Table(name="x")
*/
class X {
/**
* #Id
* #GeneratedValue
* #Column(type="smallint")
*/
private $id;
/**
* #ManyToOne(targetEntity="Y")
* #JoinColumn(name="y", referencedColumnName="id")
*/
private $myY;
}
The referenced class Y is an abstract base-class for multiple sub-classes. The $myY changes from time to time between instances of the sub-classes of Y.
/**
* #Entity
* #InheritanceType("SINGLE_TABLE")
* #DiscriminatorColumn(name="type", type="string")
* #DiscriminatorMap({"UPLOAD" = "Y1", "PROCESSED" = "Y2", "ERROR" = "Y3"})
* #Table(name="y")
*/
abstract class Y {
/**
* #Id
* #GeneratedValue
* #Column(type="smallint")
*/
protected $id;
/**
* #Column(type="datetime")
*/
protected $date;
}
/**
* #Entity
*/
class Y1 extends Y {
public function __construct() {
$this->date = new \DateTime();
}
}
Now I try to get all instances of X from the database which have an instance of Y1 as $myY:
$sql = array();
$sql[] = 'SELECT x';
$sql[] = 'FROM my\namespace\X x';
$sql[] = 'WHERE x.myY INSTANCE OF my\namespace\Y1';
$query = $this->em->createQuery(implode(' ', $sql));
$query->setFirstResult($offset);
$query->setMaxResults($maxResults);
return new Paginator($query);
But I get a QueryException, it seems not possible to use x.myY with INSTANCE OF. How I can solve that?
Some tests later:
$sql = array();
$sql[] = 'SELECT x';
$sql[] = 'FROM my\namespace\X x JOIN x.myY y';
$sql[] = 'WHERE y INSTANCE OF my\namespace\Y1';
$query = $this->em->createQuery(implode(' ', $sql));
$query->setFirstResult($offset);
$query->setMaxResults($maxResults);
return new Paginator($query);
Seems to work.
I've got Invoice entity, in which I'd like to generate subsequent numbers within a given month.
Entity code:
/**
* Class Invoice
* #package App\Entity
* #ORM\Entity()
* #ORM\HasLifecycleCallbacks()
*/
class Invoice
{
(...)
/**
* #var int
* #ORM\Column(type="integer")
*/
private $year;
/**
* #var int
* #ORM\Column(type="integer")
*/
private $month;
/**
* #var int
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="CUSTOM")
* #ORM\CustomIdGenerator(class="App\Helper\InvoiceNumberGenerator")
*/
private $counter;
(...)
/**
* #ORM\PrePersist
* #ORM\PreUpdate
*/
public function numberGenerator()
{
if ($this->getYear() === null) {
$this->setYear(date('Y'));
$this->setMonth(date('m'));
}
}
And App\Helper\InvoiceNumberGenerator code is:
<?php
namespace App\Helper;
use App\Entity\Invoice;
use Doctrine\Common\Persistence\ObjectRepository;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Id\AbstractIdGenerator;
use Exception;
class InvoiceNumberGenerator extends AbstractIdGenerator
{
/**
* Generates an invoice number
*
* #param EntityManager $em
* #param Invoice $entity
* #return mixed
* #throws Exception
*/
public function generate(EntityManager $em, $entity)
{
if (!$entity instanceof Invoice) {
throw new Exception('Generator służy tylko do generowania numerów faktur.');
}
/** #var ObjectRepository | EntityRepository $invoiceRepository */
$invoiceRepository = $em->getRepository(Invoice::class);
/** #var Invoice $lastInvoice */
$lastInvoice = $invoiceRepository->findOneBy(
array(
'year' => $entity->getYear(),
'month' => $entity->getMonth()
),
array(
'counter' => 'desc'
)
);
if (empty($lastInvoice)) {
return 1;
}
return $lastInvoice->getCounter() + 1;
}
}
When I dump $lastInvoice, it shows:
Invoice {#5522 ▼
-id: 1
-generated: false
-fileName: "example"
-year: 2019
-month: 11
-counter: 1
-name: "AG"
-company: "Gall"
-address: "Street 1"
-address2: "Gliwice"
-nip: "6314567890"
-reservation: Reservation {#5855 ▶}
-date: null
}
So it looks like the generator gets to selecting last one correctly, but nevertheless I got error when trying to create new Invoice:
SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'counter'
cannot be null
Any advise on what I'm doing wrong?
the #CustomIdGenerator annotation is only called when the column is also marked with #Id. From the docs:
This annotations allows you to specify a user-provided class to generate identifiers. This annotation only works when both #Id and #GeneratedValue(strategy="CUSTOM") are specified.
Ids are always a special kind of thing and thus must sometimes be perfect before inserting. To solve your problem - because the counter is not an id column -, you could use lifecycle events instead (prePersist, probably) and use the event's entity manager in an event listener/subscriber to run your query.
With this SQL-Statement, i can fetch the latest messages from all users:
SELECT m1.*
FROM message AS m1
INNER JOIN user
AS u1
ON m1.sender_id = u1.user_id
INNER JOIN (
SELECT sender_id,
MAX(dateSent) MaxDate
FROM message
WHERE receiver_id = 4
GROUP BY sender_id
) AS m2
ON m1.sender_id = m2.sender_id
AND m1.datesent = m2.MaxDate;
Those are my Entities in my Zend Framework 2 application:
First, i got the Message. A User can send a Message to another user.
/**
* #ORM\Entity
* #ORM\Table(name="message")
*/
class Message
{
/**
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="Application\Entities\User", inversedBy="messagesSent")
* #ORM\JoinColumn(referencedColumnName="user_id")
*/
private $sender;
/**
* #ORM\ManyToOne(targetEntity="Application\Entities\User", inversedBy="messagesReceived")
* #ORM\JoinColumn(referencedColumnName="user_id")
*/
private $receiver;
/**
* #ORM\Column(type="string", length=1024)
*/
private $message;
And the User entity here:
/**
* #ORM\Entity
* #ORM\Table(name="user")
*/
class User
{
/**
* #var int
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $user_id;
I tried to translate that SQL into DQL and got this:
SELECT m1.*
FROM Application\Entities\Message AS m1
INNER JOIN Application\Entities\User AS u1
WITH m1.sender_id = u1.user_id
INNER JOIN (
SELECT sender_id,
MAX(dateSent) MaxDate
FROM Application\Entities\Message
WHERE receiver_id = 4
GROUP BY sender_id
) AS m2
WITH m1.sender_id = m2.sender_id
AND m1.datesent = m2.MaxDate;
If i execute it, i get an error from Doctrine:
[Semantical Error] line 0, col 206 near '(
': Error: Class '(' is not defined.
What have i done wrong?
Subqueries are unavailable in doctrine(as far as I know) in DQL(from this). Can you write it query builder?
public function innerJoin($join, $alias = null, $conditionType = null, $condition = null);
See Reference
I've a problem with my many-to-many relation. I want to have access to the reference table for a querybuilder query. With a many-to-many relation I don't have access to my reference table, so I've set up two one-to-many relationships. My structure look likes:
User ---> UserUserCategory <--- UserCategory
The above structure has two one-to-many relationships and are working fine with the database. When I have a user with the following data in the database (in UserUserCategory):
Table User
ID | Name
1 | Bart
2 | Gerard
Table Category
ID | Name
1 | Officer
2 | Medic
Table UserUserCategory
User | Category
1 | 1
2 | 2
So Bart is an Officer and Gerard is a Medic. But when I want to retrieve the data, it said that Bart is the Medic, and Gerard has a "null" value in the category.
My User-entity:
/**
* Entity Class representing a post of our User module.
*
* #ORM\Entity
* #ORM\Table(name="user")
* #ORM\Entity(repositoryClass="User\Repository\UserRepository")
*
*/
class User extends zfcUser implements UserInterface
{
/**
* Categories from user
*
* #ORM\OneToMany(targetEntity="User\Entity\UserUserCategory", mappedBy="user_id", cascade={"remove", "persist"})
* #var UserUserCategory
* #access protected
*/
protected $user_usercategories;
//name & user_id comes here
/**
* Constructor to make a new ArrayCollection for addresses
*
*
*/
public function __construct()
{
$this->user_usercategories = new ArrayCollection();
}
/**
* #param Collection $categories
*/
public function addUserUserCategories(Collection $user_usercategories)
{
foreach ($user_usercategories as $user_usercategorie) {
$user_usercategorie->setUser($this);
$this->user_usercategories->add($user_usercategorie);
}
}
/**
* #param Collection $categories
*/
public function removeUserUserCategories(Collection $user_usercategories)
{
foreach ($user_usercategories as $user_usercategorie) {
$user_usercategorie->setUser(null);
$this->user_usercategories->removeElement($user_usercategorie);
}
}
/**
* #return Collection
*/
public function getUserUserCategories()
{
return $this->categories;
}
}
My UserCategory-entity:
/**
* A User category entity.
* #ORM\Entity
* #ORM\Table(uniqueConstraints={#ORM\UniqueConstraint(name="unique_name_parentId", columns={"name", "parent_id"})})
* #ORM\HasLifecycleCallbacks
*/
class UserCategory extends Category
{
/**
* User_usercategories
*
* #ORM\OneToMany(targetEntity="User\Entity\UserUserCategory", mappedBy="category_id")
* #var UserUserCategory
* #access protected
*/
protected $user_usercategories;
/**
* Constructor
*/
public function __construct()
{
$this->user_usercategories = new ArrayCollection();
}
/**
* #param Collection $categories
*/
public function addUserUserCategories(Collection $user_usercategories)
{
foreach ($user_usercategories as $user_usercategorie) {
$user_usercategorie->setCategory($this);
$this->user_usercategories->add($user_usercategorie);
}
}
/**
* #param Collection $categories
*/
public function removeUserUserCategories(Collection $user_usercategories)
{
foreach ($user_usercategories as $user_usercategorie) {
$user_usercategorie->setCategory(null);
$this->user_usercategories->removeElement($user_usercategorie);
}
}
/**
* #return Collection
*/
public function getUserUserCategories()
{
return $this->categories;
}
}
My UserUserCategory-entity:
/**
* Entity Class representing a post of our User_UserCategory entity.
*
* #ORM\Entity
* #ORM\Table(name="user_usercategory")
*
*/
class UserUserCategory
{
/**
* User with a category
*
* #ORM\ManyToOne(targetEntity="User\Entity\User", inversedBy="user_usercategories")
* #ORM\JoinColumn(name="user_id", referencedColumnName="user_id", nullable=false, onDelete="CASCADE")
* #ORM\Id
*
* #var User
* #access protected
*/
protected $user_id;
/**
* Category from user
*
* #ORM\ManyToOne(targetEntity="User\Entity\UserCategory", inversedBy="user_usercategories")
* #ORM\JoinColumn(name="category_id", referencedColumnName="id", nullable=false, onDelete="CASCADE")
* #ORM\Id
*
* #var Category
* #access protected
*/
protected $category_id;
public function getUser()
{
return $this->user;
}
/**
* Set User
*
* #param User $user
* #return User
*/
public function setUser(User $user = null)
{
//die('setUser');
$this->user = $user;
return $this;
}
public function getCategory()
{
return $this->category;
}
/**
* Set Category
*
* #param Category $category
* #return Category
*/
public function setCategory(Category $category = null)
{
$this->category = $category;
return $this;
}
}
When I execute the following line, it gives back the wrong result. The wrong category pops up:
\Doctrine\Common\Util\Debug::dump($this->getEntityManager()->find('User\Entity\User', '49')->user_usercategories);
die;
Result:
array(1) {
[0]=>
object(stdClass)#452 (3) {
["__CLASS__"]=>
string(28) "User\Entity\UserUserCategory"
["user_id"]=>
string(16) "User\Entity\User"
["category_id"]=>
string(24) "User\Entity\UserCategory"
}
}
In the category_id is the medic printed, I expect the officer to get back.
In my other user, (id=60) the category_id field is "null". So it look likes Doctrine skips the first input in my UserUserCategory, starts with the second and can't get the last category anymore.
No offence, but I find your code very hard to read. I would suggest you to do few corrections and that might even help you in solving the problem.
1: Naming: Instead of UserCategory, rename it to Category. If your Category will have different types, create new column "type" with values from constansts like
class Category
{
const TYPE_USER = 1 ;
....
2: Instead of addCategories(Collection $array), do singular version like
public function addCategory(Category $category)
{
$reference = new UserCategory() ;
$reference->setUser($this) ;
$reference->setCategory($category) ;
$this->user_categories->add($reference) ;
}
public function removeCategory(Category $category)
{
foreach($this->user_categories as $reference) {
if ( $reference->getCategory() === $category )
$this->user_categories->removeElement($reference) ;
}
}
Symfony2 automaticaly recognizes methods like this. Even if your relation is plural (like categories), s2 will find singularified addCategory and removeCategory methods.
To get array of categories, use this:
public function getCategories()
{
$categories = new ArrayCollection() ;
foreach($this->user_categories as $reference) {
$categories->add( $reference->getCategory() ) ;
}
return $categories ;
}
If you do it like this, you will probably solve the problem you have.
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