Doctrine Optimistic Locking - php

I am having a problem with doctrine optimistic locking.
I have mapped my entity like the documentation says (I guess I think so), and my optimistic locking version doesn't increment. It always stays as null inside the database.
Part of my entity and it's mapping:
Entity:
/** #var AccountID */
private $accountID;
/** #var ClientID */
private $clientID;
/** #var Money */
private $money;
/** #var array|Transfer[] */
private $transfers;
/** #var bool Account status - active not active */
private $active;
/** #var int */
private $version = 1;
Mapping:
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
https://raw.github.com/doctrine/doctrine2/master/doctrine-mapping.xsd">
<entity name="Madkom\ES\Banking\Domain\Account\Account" table="account">
<indexes>
<index name="client_id_idx" columns="client_id"/>
</indexes>
<embedded name="accountID" class="Madkom\ES\Banking\Domain\Account\AccountID" />
<embedded name="clientID" class="Madkom\ES\Banking\Domain\Account\ClientID" />
<embedded name="money" class="Madkom\ES\Banking\Domain\Money" />
<field name="transfers" column="transfers" type="jsonb"/>
<field name="active" column="active" type="boolean" length="32" unique="true" />
<field name="version" type="integer" version="true"/>
</entity>
Whenever I added new record, version is always the same, null.
I am using Postgresql 9.4 and Doctrine 2.5.1.
The jsonb type comes from outside library.

Related

Doctrine orm mapping returns error Undefined index

I'm trying to write a code that maps two to entities but in the result,
I get an error Undefined index: filterId
So without doctrine, the query is simple SELECT * FROM filter f INNER JOIN filter_options fo ON f.id = fo.filter_id WHERE f = 1;
So I need to get the same results as this query would give.
tables example:
filter
id|status
---------
1|active
2|active
3|active
filter_options:
id|filter_id|text
---------
1|1|lorem
2|1|ipsum
3|3|and
4|2|etc
Entity classes :
class Filter
{
private $id;
private $status;
/**
* #var FilterOption[]
*/
private $options;
}
class FilterOption
{
private $id;
private $filterId;
private $text;
}
Filter.orm.xml:
<id name="id" column="id" type="integer">
<generator strategy="AUTO" />
</id>
<field name="status" column="status"/>
<one-to-many field="options" target-entity="FilterOption" mapped-by="filterId"/>
FilterOption.orm.xml:
<id name="id" column="id" type="integer">
<generator strategy="AUTO" />
</id>
<field name="text" column="text"/>
<field name="filterId" column="filter_id"/>
What I'm doing wrong. I want to get Filter entity in which property $options in an array with all other filterOptions entities.
You need to think about relation in Doctrine as of relation between objects, not as relation into database. Because of this you should not think about database columns like filter_id as plain properties, they needs to be replaced with actual entity associations instead.
In your case you need to replace plain filterId property into FilterOption entity with inverse side of Many-to-One association. Please refer Doctrine documentation for details.
Your code may look something like this:
Filter.php
class Filter
{
/**
* #var int
*/
private $id;
/**
* #var string
*/
private $status;
/**
* #var FilterOption[]
*/
private $options;
}
FilterOption.php
class FilterOption
{
/**
* #var int
*/
private $id;
/**
* #var Filter
*/
private $filter;
/**
* #var string
*/
private $text;
}
Filter.orm.xml:
<doctrine-mapping>
<entity name="Filter" table="filter">
<id name="id" column="id" type="integer">
<generator strategy="AUTO" />
</id>
<field name="status" column="status"/>
<one-to-many field="options" target-entity="FilterOption" mapped-by="filter"/>
</entity>
<doctrine-mapping>
FilterOption.orm.xml:
<doctrine-mapping>
<entity name="FilterOption" table="filter_option">
<id name="id" column="id" type="integer">
<generator strategy="AUTO" />
</id>
<field name="text" column="text"/>
<many-to-one field="filter" target-entity="Filter" inversed-by="options">
<join-column name="filter_id" referenced-column-name="id" />
</many-to-one>
</entity>
<doctrine-mapping>

Association entity related - change by hand

I do have an entity in AppBundle/Entity which I generated me from database.
<?php
namespace AppBundle\Entity;
/*
*
* ExtensionSyliusShopUser
*/
class ExtensionSyliusShopUser
{/**
* Set user
*
* #param \AppBundle\Entity\SyliusShopUser $user
*
* #return ExtensionSyliusShopUser
*/
public function setUser(\AppBundle\Entity\SyliusShopUser $user = null)
{
$this->user = $user;
return $this;
}
/**
* Get user
*
* #return \AppBundle\Entity\SyliusShopUser
*/
public function getUser()
{
return $this->user;
}
Now I want to change the setUser() & getUser() to:
Sylius\Component\Core\Model\ShopUser
If I am going to change #parm and the value in braces e.g.:
public function setUser(\Sylius\Component\Core\Model\ShopUser $user = null)
I get the error:
Expected value of type "AppBundle\Entity\SyliusShopUser" for association field "AppBundle\Entity\ExtensionSyliusShopUser#$user", got "Sylius\Component\Core\Model\ShopUser" instead.
How can I change it?
<?xml version="1.0" encoding="utf-8"?>
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
<entity name="AppBundle\Entity\ExtensionSyliusShopUser" table="extension_sylius_shop_user">
<indexes>
<index name="user_id" columns="user_id"/>
</indexes>
<id name="id" type="integer" column="id">
<generator strategy="IDENTITY"/>
</id>
<field name="wishlist" type="text" column="wishlist" length="65535" nullable="true">
<options>
<option name="fixed"/>
</options>
</field>
<many-to-one field="user" target-entity="SyliusShopUser" fetch="LAZY">
<join-columns>
<join-column name="user_id" referenced-column-name="id"/>
</join-columns>
</many-to-one>
</entity>
</doctrine-mapping>
You need to change the definition of your $user property (column). which is not shown in a code sample you provided.
In case you use annotations is should look like this:
/**
* #ORM\ManyToOne(targetEntity="Sylius\Component\Core\Model\ShopUser")
*/
private $user;
In case of XML config:
<many-to-one field="user" target-entity="Sylius\Component\Core\Model\ShopUser">

How to build zend 2 forms automatically from doctrine 2 entity-classes?

Is there a way to automatically build a zend framework form by having a doctrine 2 entity-class?
Important Information: This is only a example and no productive setup.
E.g.
Users (Entity) class:
use Doctrine\ORM\Mapping as ORM;
/**
* Users
*/
class Users
{
/**
* #var string
*/
private $name;
/**
* #var integer
*/
private $id;
/**
* Set name
*
* #param string $name
* #return Users
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
}
Users xml mapping definition:
<?xml version="1.0" encoding="utf-8"?>
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
<entity name="Users" table="users">
<id name="id" type="integer" column="ID">
<generator strategy="IDENTITY"/>
</id>
<field name="name" type="string" column="name" length="50" nullable="true"/>
</entity>
</doctrine-mapping>
Now i would like to have a zend 2 form class, where i can inject this entity and the form itself builds a basic form and attaches validators to this form. Here in this example it would atach a StringLenght validator (max 50; see xml mapping above) to the users field.
Something like this is possible like i know in CakePHP. I would be really happy to have such feature in Zend framework 2, too;-)
For now i found one link: http://www.lewanscheck.de/2013/09/21/inject-doctrine-orm-entitymanager-in-zf2-form/ but no automatic creation of validation from the xml file.
Would be great to implement only a model/entity class with a xml/yml/annotation(even when i do not like annotations) configuration and build automatically a db schema-part (this works with doctrine 2) and a form class.

Symfony2/Doctrine2 model classes mappings for reusable bundle

I am currently trying to create a reusable bundle with Symfony2 using model classes but I am not able to register their mappings so Doctrine recognize them.
I read that using compiler pass could be the solution so I followed the guide in the Symfony Cookbook (http://symfony.com/doc/current/cookbook/doctrine/mapping_model_classes.html) and I also looked at the source code in the FOSUserBundle for some inspiration.
And here is what I've done so far :
class GPGoodsBundle extends Bundle{
public function build(ContainerBuilder $container)
{
parent::build($container);
$this->addRegisterMappingsPass($container);
}
/**
* #param ContainerBuilder $container
*/
private function addRegisterMappingsPass(ContainerBuilder $container)
{
$modelDir = realpath(__DIR__.'/Resources/config/doctrine/model');
$mappings = array(
$modelDir => 'GP\Bundle\GoodsBundle\Model',
);
$ormCompilerClass = 'Doctrine\Bundle\DoctrineBundle\DependencyInjection\Compiler\DoctrineOrmMappingsPass';
if (class_exists($ormCompilerClass)) {
$container->addCompilerPass(
DoctrineOrmMappingsPass::createXmlMappingDriver(
$mappings,
array('gp_goods.model_manager_name'),
'gp_goods.backend_type_orm'
)
);
}
}
}
But when trying to migrate my entity (just to see if it's working) here is the result :
$php app/console doctrine:migrations:diff
No mapping information to process.
My entities are stored under "GP\Bundle\GoodsBundle\Model" and their mappings under "GP\Bundle\GoodsBundle\Resources\config\doctrine\model"
So my question is : what is the good way to create a reusable bundle and how to register mappings of model classes?
If you need any additional information, do not hesitate to ask!
Thank you for your help!
Here is one of my model classes :
class Good implements GoodInterface{
/**
* #var integer
*/
private $id;
/**
* #var string
*/
protected $serial;
/**
* #var \DateTime
*/
protected $manufacturedAt;
/**
* #var \DateTime
*/
protected $deliveredAt;
/**
* #var \DateTime
*/
protected $expiredAt;
/**
* #var string
*/
protected $checkInterval;
/**
* #var string
*/
protected $status;
/**
* #var string
*/
protected $slug;
/**
* #var \DateTime
*/
protected $createdAt;
/**
* #var \DateTime
*/
protected $updatedAt;
/**
* #var \DateTime
*/
protected $deletedAt;
public function __construct(){
$this->createdAt = new \DateTime("now");
$this->status = 'good';
}
.... getters/setters .....
}
And the mappings :
<?xml version="1.0" encoding="utf-8"?>
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:gedmo="http://gediminasm.org/schemas/orm/doctrine-extensions-mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
<entity name="GP\Bundle\GoodsBundle\Model\Good" table="good">
<id name="id" type="integer" column="id">
<generator strategy="AUTO"/>
</id>
<field name="serial" type="string" column="serial" length="255"/>
<field name="manufacturedAt" type="date" column="manufactured_at"/>
<field name="deliveredAt" type="date" column="delivered_at"/>
<field name="expiredAt" type="date" column="expired_at"/>
<field name="checkInterval" type="string" column="check_interval" length="255" nullable="true"/>
<field name="status" type="string" column="status" length="255"/>
<field name="slug" type="string" column="slug" length="255">
<gedmo:slug fields="serial" unique="true" />
</field>
<field name="createdAt" type="datetime" column="created_at">
<gedmo:timestampable on="create"/>
</field>
<field name="updatedAt" type="datetime" column="updated_at" nullable="true">
<gedmo:timestampable on="update"/>
</field>
<field name="deletedAt" type="datetime" column="removed_at" nullable="true">
<gedmo:soft-deleteable field-name="deletedAt"/>
</field>
</entity>
</doctrine-mapping>
When you have entities outside of any bundle or that the location is not the usual one, you'll have to change the doctrine section in config.yml from
doctrine:
# ...
orm:
# ...
auto_mapping: true
to
doctrine:
# ...
orm:
# ...
mappings:
model: # replace `model` with whatever you want
type: annotation # could be xml, yml, ...
dir: %kernel.root_dir%/../path/to/your/model/directory
prefix: Prefix\Namespace # replace with your actual namespace
alias: Model # replace with the desired alias
is_bundle: false
The dir parameter informs Doctrine where to look for the mapping definitions. If you're using annotations, it will be your model directory. Otherwise, it will be the directory of your xml/yml files.
Entities's names — to access from Doctrine repositories — begin with Model in this case, for example, Model:User. It corresponds to the parameter alias.
When editing a configuration file, do not forget to clear the cache.
Moreover, in my question, I wrote that I changed something in my Bundle class but it was not useful as the bundle won't be reused by another project. So I removed everything.
See this answer for more details :
https://stackoverflow.com/a/10001019/2720307
Thanks to Elnur Abdurrakhimov!

Doctrine mapping a single entity class to multiple tables without inheritance

Is it possible somehow to map a single entity class to two different tables without inheritance?
Something like:
<entity name="Acme\Entity\Service" table="organization_service">
...
<many-to-one field="target" target-entity="Acme\Entity\Organization" inversed-by="services">
<join-columns>
<join-column name="target_id" referenced-column-name="id" />
</join-columns>
</many-to-one>
</entity>
<entity name="Acme\Entity\Service" table="person_service">
...
<many-to-one field="target" target-entity="Acme\Entity\Person" inversed-by="services">
<join-columns>
<join-column name="target_id" referenced-column-name="id" />
</join-columns>
</many-to-one>
</entity>
where entity classes could look like:
class Service
{
...
/**
* #var Person|Organization
*/
private $target;
}
class Person
{
...
/**
* #var Service[]
*/
private $services;
}
class Organization
{
...
/**
* #var Service[]
*/
private $services;
}
A workaround I've found so far is to create two classes PersonService and OrganizationService with the same content and map them to "person_service" and "organization_service" tables accordingly.

Categories