symfony doctrine auto increment migrations insert column count mismatch - mysql

I'm trying to add inserts to a migration but it is complaining about column mismatch because I am not including the auto increment id field, it works if I ad the id column but it should be auto increment and I should not need to add it ?? any help greatly appreciated.
entity file
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
migration file
/**
* #param Schema $schema
*/
public function up(Schema $schema)
{
$this->addSql("INSERT INTO shipping_rates VALUES
(0,'Ground','2',5.64 )
");
}

Why not also provide the columns in the insert statement?
Something like this:
INSERT INTO table_name (column1, column2, column3, ...)
VALUES (value1, value2, value3, ...);
Hope this helps,
Alexandru Cosoi

Related

Doctrine - ManyToMany with custom primary key

I've a unidirectional ManyToMany relation:
class Account {
/* other attributes ... */
/**
* #ORM\ManyToMany(targetEntity="App\Entity\Item")
* #ORM\JoinTable("account_items",
* joinColumns={#ORM\JoinColumn(name="account_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="item_id", referencedColumnName="vnum")}
* )
*/
private $items;
}
What I want to do:
I would like to make the account possible to have one or more identical Item (the same identifier.). For example:
`account_id` 1, `item_id` 1
`account_id` 1, `item_id` 1
should've been allowed.
It's not possible when doctrine generates DDL query with two primary keys (account_id, item_id) and if I try to do it I got mysql duplciation entry error.
I customized migration that creates id as primary key (as only one), but I think it's not proper solution.
`id`: 1, account_id` 1, `item_id` 1
`id` : 2, account_id` 1, `item_id` 1
Do you have any?
Make a bi-directionnal OneToMany <=> ManyToOne relation between 3 entities.
src/AppBundle/Entity/Account.php
class Account {
/**
* #ORM\OneToMany(targetEntity="AppBundle\Entity\AccountItem", mappedBy="accounts")
*/
private $accountItems;
}
src/AppBundle/Entity/AccountItem.php
class AccountItem {
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\Account", inversedBy="accountItems")
*/
private $accounts;
/**
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\Item", inversedBy="itemAccounts")
*/
private $items;
}
src/AppBundle/Entity/Item.php
class Item {
/**
* #ORM\OneToMany(targetEntity="AppBundle\Entity\AccountItem", mappedBy="items")
*/
private $itemAccounts;
}
It's in fact a ManyToMany relation, but you can now add id, which will be unique, en still have duplicate entries.
Side now, you're referencing item.vnum in your annotation. Know that Symfony hate it when you don't use id.

Doctrine does not automatically load joined relation using GROUP BY

I have two Doctrine entity classes: Vertriebsschiene and Filiale:
/**
* Vertriebsschiene
*
* #ORM\Table(name="vertriebsschiene", indexes={
* #ORM\Index(columns={"name"}, flags={"fulltext"})
* }))
* #ORM\Entity(repositoryClass="CRMBundle\Repository\VertriebsschieneRepository")
*/
class Vertriebsschiene
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=100)
*/
private $name;
/**
* #var ArrayCollection
*
* #ORM\OneToMany(targetEntity="Filiale", mappedBy="vertriebsschiene", fetch="EAGER")
*/
private $filialen;
...
}
/**
* Filiale
*
* #ORM\Table(name="filiale")
* #ORM\Entity(repositoryClass="CRMBundle\Repository\FilialeRepository")
*/
class Filiale extends Lieferant
{
/**
* #var Vertriebsschiene
*
* #ORM\ManyToOne(targetEntity="CRMBundle\Entity\Vertriebsschiene", inversedBy="filialen", fetch="EAGER")
*/
private $vertriebsschiene;
...
}
The Vertriebsschine objects have a non-uniqe name. Now I try to display a list of Vertriebsschiene objects with their Filiale objects.
My findAllQuery method looks like this:
/**
* #param User $user
* #return \Doctrine\ORM\Query
*/
public function findAllQuery(User $user){
$qb = $this->createQueryBuilder('v')
->select('v as vertriebsschiene')
->addSelect('COUNT(f) as filial_num')
->leftJoin('v.filialen', 'f')
->groupBy('v.name');
$this->restrictAccess($user, $qb);
return $qb->getQuery();
}
/**
* #param User $user
* #param $qb
*/
protected function restrictAccess(User $user, QueryBuilder &$qb)
{
if ($user->hasRole(RoleVoter::AUSSENDIENST)) {
$qb ->leftJoin('f.vertreter', 'u')
->leftJoin('u.vertretungen', 'vx')
->andWhere($qb->expr()->orX(
'f.vertreter = :userid',
'f.vertreter IS NULL',
$qb->expr()->andX(
'vx.proxy = :userid',
$qb->expr()->between(':currentDate', 'vx.start', 'vx.end')
)
))
->setParameter('userid', $user->getId())
->setParameter('currentDate', new \DateTime(), \Doctrine\DBAL\Types\Type::DATETIME);
}
}
My problem is, that the Vertriebsschiene::$filiale array collection is not automatically loaded, but is loaded for every Vertriebsschiene resulting in many DB connections.
This also has the problem, that the WHERE statement is ignored when the Vertriebsschiene::$filiale is fetched.
The COUNT(f) returns the correct amount of Filiale objects.
I suspect this is an issue with the GROUP BY statement.
I think the problem is that you do not tell doctrine to select filiale fields.
Try to add the filiale alias in your select :
public function findAllQuery(User $user){
$qb = $this->createQueryBuilder('v')
->select('v as vertriebsschiene', 'f')
->addSelect('COUNT(f) as filial_num')
->leftJoin('v.filialen', 'f')
->groupBy('v.name');
$this->restrictAccess($user, $qb);
return $qb->getQuery();
}
If you check your query in the profiler, i think you'll see that doctrine add a LEFT JOIN fialiale f0_ ON v0_.id = f0_.vertriebsschiene_id (or something like this but does not add SELECT ... f0_.id, f0_.xxxx.
So every time you'll call $vertriebsschiene->getFieliale()->getXXX() doctrine will have to execute the corresponding query to get the filiale data.

Doctrine one-to-many association: Issues with composite primary key

I am trying to populate the below one-to-many doctrine association however I am hitting a problem because every Customer (primary key: id) has their visits (primary key: customer_id & visitday) captured in the Visit table (I am deriving visitday as the number of days since 1st Jan 2000 before persisting to the database (since datetime objects can not be in the primary key)):
Entities
class Customer
{
/**
* #ORM\Column(type="integer", options={"unsigned"=true})
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\OneToMany(targetEntity="Visit", mappedBy="visitday")
*/
protected $visits;
public function __construct()
{
$this->visits = new ArrayCollection();
}
/* -- */
}
Class Visit
{
/**
* #ORM\Column(name="customer_id", type="integer", options={"unsigned"=true})
* #ORM\JoinColumn(name="customer_id", referencedColumnName="id")
* #ORM\Id
*/
private $customer;
/**
* #ORM\Column(type="smallint")
* #ORM\ManyToOne(targetEntity="Customer", inversedBy="visits")
* #ORM\JoinColumn(name="visitday", referencedColumnName="id")
* #ORM\Id
*/
protected $visitday;
/* -- */
}
My problem is that my Customer objects are not getting populated with the customer's corresponding visits. I assume this is because doctrine can't see that it should also include its own customer ID in the lookup. Is there a way to fix this?
I would recommend you to change $visitday attribute to DateTime. It will be your visit date timestamp. Then customer attribute should be inversed with visits.
/**
* #ORM\Column(name="customer_id", type="integer", options={"unsigned"=true})
* #ORM\ManyToOne(targetEntity="Customer", inversedBy="visits")
* #ORM\Id
*/
private $customer;
And as an option you could change relation Customer to Visits as ManyToMany. So you wont have duplicate visit dates.

Wrong ID given in Doctrine2 OneToOne mapping

I am seriously stack right now with the problem I have occurred with OneToOne mapping.
So let me show what I currently have:
OrderItem entity
/**
* OrderItem
*
* #ORM\Table(name="order_item")
* #ORM\Entity
*/
class OrderItem
{
/**
* #var integer
*
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
// ... //
/**
* #ORM\OneToOne(targetEntity="UserPricingOption", mappedBy="orderItem")
*/
private $userPricingOption;
/**
* #ORM\ManyToOne(targetEntity="Order", inversedBy="items")
* #ORM\JoinColumn(referencedColumnName="id")
*/
private $order;
// ... //
UserPricingOption entity
/**
* UserPricingOption
*
* #ORM\Table(name="user_pricing_option")
* #ORM\Entity
* #ExclusionPolicy("all")
*/
class UserPricingOption
{
/**
* #var integer
*
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
// ... //
/**
* #ORM\OneToOne(targetEntity="OrderItem", inversedBy="userPricingOption")
* #ORM\JoinColumn(referencedColumnName="id")
*/
private $orderItem;
// ... //
so generated tables look like this:
order_item table
* `id` 5
user_pricing_option table
* `id` 12
* `order_item_id` 5
So now I am trying to do the following:
echo $orderItem->getId(); // gives 5, `GOOD`
echo $orderItem->getUserPricingOption()->getId(); // gives 5 `BAD` (completely different user_pricing_option row), it should return 12.
I seriously have no idea why is that, please find the raw Doctrine query:
Keep in mind that query contains way more info than the showed examples above
SELECT t0.id AS id_1, t0.guid AS guid_2, t0.created_at AS created_at_3, t0.modified_at AS modified_at_4, t5.id AS id_6, t5.guid AS guid_7, t5.created_at AS created_at_8, t5.modified_at AS modified_at_9, t5.user_id AS user_id_10, t5.order_item_id AS order_item_id_11, t5.pricing_option_id AS pricing_option_id_12, t13.id AS id_14, t13.guid AS guid_15, t13.created_at AS created_at_16, t13.modified_at AS modified_at_17, t13.user_id AS user_id_18, t13.order_item_id AS order_item_id_19, t13.product_variant_id AS product_variant_id_20, t0.order_invoice_id AS order_invoice_id_21, t0.order_id AS order_id_22 FROM order_item t0 LEFT JOIN user_pricing_option t5 ON t5.order_item_id = t0.id LEFT JOIN user_product_variant t13 ON t13.order_item_id = t0.id WHERE t0.order_id = ? [131]
So basically $orderItem->getUserPricingOption()->getId() always returns the same ID as $orderItem->getId();
Anyone possibly see what is going on?
OneToOne bidireccional?
Try to define in joinColumn the name with column to reference id.
/**
* #ORM\OneToOne(targetEntity="OrderItem", inversedBy="userPricingOption")
* #ORM\JoinColumn(name="order_item_id", referencedColumnName="id")
*/
private $orderItem;
http://doctrine-orm.readthedocs.org/projects/doctrine-orm/en/latest/reference/association-mapping.html#one-to-one-bidirectional

Doctrine2 Query where Subquery would be needed

Let me first introduce the Entities used in this example:
Order (_order in mysql)
$id (primary key, auto increment)
OrderStatus (order_status in mysql)
$id (primary key, auto increment)
$order (storing the order object it is related to, named order_id in mysql)
$statuscode (Storing the integer code)
$created_at (Storing the datetime of creation)
The relationship is Order n:1 OrderStatus. For every status change, I create a new OrderStatus with the new statuscode. So for one Order there can be many OrderStatus. The actual OrderStatus can be figured out by looking at the OrderStatus with the latest created_at.
I now want to get all objects which have the status 0 right now. In SQL, my query would look like this:
SELECT o.id,os.statuscode,os.created_at
FROM `_order` o
LEFT JOIN `order_status` os ON o.id = os.order_id
WHERE os.created_at = (SELECT MAX(created_at)
FROM order_status
WHERE order_id = os.order_id);
Can I do such a query in DQL or do I have to work with objects? If so, would I need to read all OrderStatus objects and manually figure out which is the most current one or can I somehow preselect?
I figured out a way which is not quite what I was searching for, but it doesn't require any changes in my application, so it's ok as long as I don't find a better solution.
What I'll do is I'll store the actual status directly within the Order. Through LifecycleCallbacks I'll update the order as soon as a OrderStatus related to it is created.
So my Order-Object looks like this:
/**
* #ORM\Entity
* #ORM\Table(name="_order")
*/
class Order{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
//..
/**
* #ORM\Column(type="smallint", nullable=false)
*/
protected $status = -1;
// Getter and Setter!
}
My Order-Status will look like this:
/**
* #ORM\Entity
* #ORM\Table(name="order_status")
* #ORM\HasLifecycleCallbacks
*/
class OrderStatus{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\ManyToOne(targetEntity="Order", inversedBy="order_status", cascade={"persist"})
* #ORM\JoinColumn(name="order_id", referencedColumnName="id", nullable=false)
*/
protected $order;
/**
* #ORM\Column(type="smallint", nullable=false)
*/
protected $statuscode;
// ..
/**
* #ORM\prePersist
*/
public function prePersist(){
$this->order->setStatus($this->statuscode);
}
// Getter and Setter!
}
Mind the , cascade={"persist"} within the OrderStatus so the Order will also be persisted when the OrderStatus is persisted, otherwise the status will be set, but not stored!
On the plus side of this solution is that I now get the OrderStatus by calling $order->getStatus() instead of having to query the database for the status and that I'm able to do $repository->findByStatus(0). On the other hand, the moment the status field gets changed due to some error, the data will be inconsistent.
As said, if you got a solution where I don't need an extra field to store the status, post it! I'm very interested in a better solution!