I've got entity type of:
/**
* #ORM\Table(name="entity")
*/
class Entity
{
/**
* #var integer
*
* #ORM\Column(type="integer", nullable=true)
*/
private $value1;
/**
* #var integer
*
* #ORM\Column(type="integer", nullable=true)
*/
private $value2;
}
How to check with validation that $value1 is less than $value2?
You can use Expression constraint in your entity
use Symfony\Component\Validator\Constraints as Assert;
/**
* #ORM\Table(name="entity")
*/
class Entity
{
/**
* #var integer
* #Assert\Expression(
* "this.getValue2() < this.getValue1()",
* message="Value 1 should be less than value 2"
* )
* #ORM\Column(type="integer", nullable=true)
*/
private $value2;
}
Basically, as the cookbook explains extensively, you'll probably want to add the following to your entity:
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
class Entity
{
//the values stay the same
/**
* #Assert\Callback
*/
public function validate(ExecutionContextInterface $context)
{
if ($this->value1 >= $this->value2)
{
$context->buildViolation('Value1 should be less than value2')
->atPath('value1')
->addViolation();
}
}
}
Related
I use Knp\DoctrineBehaviors for Translation and StofDoctrineExtensionsBundle for Sluggable. How to make checking the uniqueness of slug by the sluggable and locale? I want to get the slug look like this:
for EN: /contacts
for PT: /pt/contacts
for PT (if duplicate): /pt/contacts-1
for ES: /es/contacts
But now, i have this database filter_node_translation
Entity\FilterNode.php:
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Knp\DoctrineBehaviors\Model as ORMBehaviors;
/**
* #ORM\Table(name="filter_node")
* #ORM\Entity()
*/
class FilterNode
{
use ORMBehaviors\Translatable\Translatable;
/**
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
* #ORM\Column(name="id", type="integer")
*/
protected $id;
/**
* #return mixed
*/
public function getId()
{
return $this->id;
}
}
FilterNodeTranslation:
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Knp\DoctrineBehaviors\Model as ORMBehaviors;
use Gedmo\Mapping\Annotation as Gedmo;
/**
* #ORM\Table(name="filter_node_translation")
* #ORM\Entity()
*/
class FilterNodeTranslation
{
use ORMBehaviors\Translatable\Translation;
/**
* #var string
*
* #ORM\Column(type="string", nullable=true)
*/
protected $sluggable;
/**
* #var string
*
* #Gedmo\Slug(fields={"sluggable"})
* #ORM\Column(type="string", nullable=true)
*/
protected $slug;
/**
* #return string
*/
public function getSluggable()
{
return $this->sluggable;
}
/**
* #param string $sluggable
*/
public function setSluggable($sluggable)
{
$this->sluggable = $sluggable;
}
}
I found solution. Gedmo sluggable have other configuration option "unique_base".
It looks like this:
class FilterNodeTranslation
{
/**
* #var string
*
* #Gedmo\Slug(updatable=true, unique=true, unique_base="locale", fields={"sluggable"})
* #ORM\Column(type="string")
*/
protected $slug;
}
I'm unsure how to get all hotel types that have "at least one" hotel? As the relation is ManyToMany.
So with queryBuilder, I assumed I can do something like:
$qb = $this->em->createQueryBuilder();
$qb->select('t')
->from(HotelType::class, 't', 't.id')
->join('t.hotels', 'm');
But this doesn't seem to work? I'm not sure what I must do. Here are my two entities:
HotelType entity :
use Doctrine\ORM\Mapping as ORM;
/**
* HotelType
*
* #ORM\Table(name="hotel_type")
* #ORM\Entity
*/
class HotelType
{
/**
* #var string
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var string
*
* #ORM\ManyToMany(targetEntity="Hotel", cascade={"persist"}, mappedBy="mType")
*/
private $hotels;
}
Hotel entity :
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
/**
* Hotel
*
* #ORM\Table(name="hotel")
* #ORM\Entity(repositoryClass="Application\Repository\HotelRepository")
*/
class Hotel
{
/**
* #var string
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\ManyToMany(targetEntity="HotelType", inversedBy="hotels", cascade={"persist"})
* #ORM\JoinTable(name="hotel_hoteltype",
* joinColumns={#ORM\JoinColumn(name="hotel_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="hoteltype_id", referencedColumnName="id")}
* )
*/
private $mType;
public function __construct()
{
$this->mType = new ArrayCollection();
}
public function getMType()
{
return $this->mType;
}
public function addMType($mtype)
{
if (!$this->mType->contains($mtype) && is_object($mtype)) {
$this->mType->add($mtype);
}
return $this;
}
public function removeMType($mtype)
{
if ($this->mType->contains($mtype) && is_object($mtype)) {
$this->mType->removeElement($mtype);
}
return $this;
}
public function clearMType()
{
$this->mType->clear();
return $this;
}
}
Does anyone know why the Doctrine query below creates a separate join for the StandardDedescribed entity?
As you can see below this query pulls the information from the master entity 'EquipmentUK' and two related tables: 'SchemaInfo' and 'StandardDescribed'. It works well for the SchemaInfo, but creates another query for StandardDescribed. The relations in the Entities seem to be coded extactly the same, so I don't understand why it behaves differently for StandardDescribed?
$qb->select('e')
->from('\Lookup\Entity\Fullhistory\EquipmentUK', 'e')
->leftJoin(
'\Lookup\Entity\Fullhistory\SchemaInfo',
'si',
Expr\Join::WITH,
'e.schema_id = si.schema_id AND si.parent_schema_id != si.schema_id'
)
->leftJoin(
'\Lookup\Entity\Intelligence\StandardDescribedUK',
'sd',
Expr\Join::WITH,
'e.schema_id = sd.schema_id'
)
->where($qb->expr()->eq('e.vehicle_id', '?1'))
->setParameter(1, $jatoid);
Here are the Entities:
EquipmentUK:
namespace Lookup\Entity\Fullhistory;
use Doctrine\ORM\Mapping as ORM;
/**
* EquipmentUK
*
* #ORM\Table(name="equipment",
* uniqueConstraints={
* #ORM\UniqueConstraint(name="search_idx", columns={"vehicle_id", "option_id", "record_id", "schema_id"})
* }
* )
* #ORM\Entity
*/
class EquipmentUK
{
/**
* #var integer
*
* #ORM\Id
* #ORM\Column(type="integer")
*/
private $vehicle_id;
/**
* #var integer
*
* #ORM\Id
* #ORM\Column(type="integer")
*/
private $schema_id;
/**
* #var integer
*
* #ORM\Id
* #ORM\Column(type="integer")
*/
private $option_id;
/**
* #var integer
*
* #ORM\Id
* #ORM\Column(type="integer")
*/
private $record_id;
/**
* #var string
*
* #ORM\Column(type="string")
*/
private $location;
/**
* #ORM\ManyToOne(targetEntity="Lookup\Entity\Fullhistory\SchemaInfo", cascade={"all"}, fetch="EAGER")
* #ORM\JoinColumn(name="schema_id", referencedColumnName="schema_id")
*/
private $schemaInfo;
/**
* #ORM\ManyToOne(targetEntity="Lookup\Entity\Intelligence\StandardDescribedUK", cascade={"all"}, fetch="EAGER")
* #ORM\JoinColumn(name="schema_id", referencedColumnName="schema_id")
*/
private $standardDescribed;
/**
* #var string
*
* #ORM\Column(type="string")
*/
private $data_value;
public function getVehicleId()
{
return $this->vehicle_id;
}
public function getSchemaId()
{
return $this->schema_id;
}
public function getOptionId()
{
return $this->option_id;
}
public function getRecordId()
{
return $this->record_id;
}
public function getLocation()
{
return $this->location;
}
public function getSchemaInfo()
{
return $this->schemaInfo;
}
public function getStandardDescribed()
{
return $this->standardDescribed;
}
public function getDataValue()
{
return $this->data_value;
}
}
SchemaInfo:
namespace Lookup\Entity\Fullhistory;
use Doctrine\ORM\Mapping as ORM;
/**
* SchemaInfo
*
* #ORM\Table(name="schema_info")
* #ORM\Entity
*/
class SchemaInfo
{
/**
* #var integer
*
* #ORM\Column(name="schema_id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $schema_id;
/**
* #var integer
*
* #ORM\Column(name="parent_schema_id", type="integer", nullable=true)
*/
private $parent_schema_id;
/**
* #var integer
*
* #ORM\Column(name="location_schema_id", type="integer", nullable=true)
*/
private $locationSchemaId;
/**
* #var integer
*
* #ORM\Column(name="scale_of_data", type="smallint", nullable=true)
*/
private $scaleOfData;
/**
* #var integer
*
* #ORM\Column(name="data_type", type="smallint", nullable=true)
*/
private $dataType;
public function getSchemaId()
{
return $this->schema_id;
}
public function getParentSchemaId()
{
return $this->parent_schema_id;
}
}
StandardDescribedUK
namespace Lookup\Entity\Intelligence;
use Doctrine\ORM\Mapping as ORM;
/**
* StandardDescribedUK
*
* #ORM\Table(name="jato_uk_intelligence.standard_described")
* #ORM\Entity
*/
class StandardDescribedUK
{
/**
* #var integer
*
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $schema_id;
/**
* #var string
*
* #ORM\Column(name="category", type="string", nullable=true)
*/
private $category;
public function getCategory()
{
return $this->category;
}
}
Your joins should use Doctrine's own relational schema: your EquipmentUK has declared its relation with SchemaInfo via the property $schemaInfo, and it has also declared its relation with StandardDescribedUK via $standardDescribed. So:
$qb->select('e')
->from('\Lookup\Entity\Fullhistory\EquipmentUK', 'e')
->leftJoin(
'e.schemaInfo',
'si'
//we don't need that third param as the relation is already known
)
->leftJoin(
'e.standardDescribed',
'sd'
//same here, no need for explicit relation
)
->where($qb->expr()->eq('e.vehicle_id', ':vehicle'))
//this here is a restriction, should be in WHERE instead of ON
->andWhere($qb->expr()->neq('si.parent_schema_id', 'si.schema_id'))
->setParameter('vehicle', $jatoid);
Hope this helps!
I've been playing around with Zend and Doctrine incorporated into it for the past week or so. I've gotten the hang of basic inserts and selects, and can also use DQL to select from joined tables. The problem I'm having is persisting associated entities. Error I'm getting is this: (path)htdocs\vendor\doctrine\common\lib\Doctrine\Common\Persistence\Mapping\MappingException.php:96 with the message 'Class "" does not exist'.
My code is below...
Here is the main entity (the one on the "many" side)
namespace Project\Entity;
use Doctrine\ORM\Mapping as ORM;
use Zend\InputFilter\Factory as InputFactory;
/**
* ClientUser
*
* #ORM\Table()
* #ORM\Entity
*/
class ClientUser extends SystemUser
{
/**
* #var integer
*
* #ORM\OneToOne(targetEntity="SystemUser", cascade={"persist", "remove"})
* #ORM\JoinColumn(name="id", referencedColumnName="id")
*/
private $id;
/**
* #var integer
*
* #ORM\ManyToOne(targetEntity="Client", cascade={"persist", "remove"})
* #ORM\JoinColumn(name="client", referencedColumnName="id")
*/
private $client;
protected $_inputFilter;
//Other stuff here...
}
Here is the "Client" associated entity...
namespace Project\Entity;
use Doctrine\ORM\Mapping as ORM;
use Zend\InputFilter\InputFilter;
use Zend\InputFilter\Factory as InputFactory;
use Zend\InputFilter\InputFilterAwareInterface;
use Zend\InputFilter\InputFilterInterface;
/**
* Client
*
* #ORM\Table()
* #ORM\Entity
*/
class Client implements InputFilterAwareInterface
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="client_name", type="string", length=255)
*/
private $clientName;
/**
* #var integer
*
* #ORM\Column(name="loggable_hours", type="integer")
*/
private $loggableHours;
/**
* #var float
*
* #ORM\Column(name="normal_rate", type="decimal", scale=2)
*/
private $normalRate;
/**
* #var float
*
* #ORM\Column(name="critical_rate", type="decimal", scale=2)
*/
private $criticalRate;
/**
* #var string
*
* #ORM\Column(name="start_date", type="string")
*/
private $startDate;
/**
* #var boolean
*
* #ORM\Column(name="enabled", type="boolean")
*/
private $enabled;
/**
* #var integer
*
* #ORM\Column(name="critical_hours", type="integer")
*/
private $criticalHours;
/**
*
* #var type
*/
protected $_inputFilter;
//Other stuff (getters,setters, etc)
}
The ClientUser has a one-to-one relationship with the following:
namespace Project\Entity;
use Doctrine\ORM\Mapping as ORM;
use Zend\InputFilter\InputFilter;
use Zend\InputFilter\Factory as InputFactory;
use Zend\InputFilter\InputFilterAwareInterface;
use Zend\InputFilter\InputFilterInterface;
/**
* SystemUser
*
* #ORM\Table()
* #ORM\Entity
* #ORM\InheritanceType("JOINED")
* #ORM\DiscriminatorColumn(name="user_type", type="integer")
* #ORM\DiscriminatorMap({1 = "DeveloperUser", 2 = "ClientUser"})
*
*/
class SystemUser implements InputFilterAwareInterface {
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="username", type="string", length=100, unique=true)
*/
private $username;
/**
* #var string
*
* #ORM\Column(name="password", type="string", length=255)
*/
private $password;
/**
* #var string
*
* #ORM\Column(name="user_first_name", type="string", length=255)
*/
private $userFirstName;
/**
* #var string
*
* #ORM\Column(name="user_surname", type="string", length=255)
*/
private $userSurname;
/**
* #ORM\Column(type="string", length=32)
*/
private $salt;
/**
* #var \DateTime
*
* #ORM\Column(name="last_login", type="datetime")
*/
private $lastLogin = '0000-00-00 00:00:00';
/**
* #var bool
*
* #ORM\Column(name="enabled", type="boolean", options={"default" = 1})
*/
private $enabled = 1;
/**
* For the input filter...
*
* #var InputFilter
*/
protected $_inputFilter;
//The rest...
}
I have absolutely no idea what could be wrong here... Just for completeness, here is the controller "add" action...
public function addAction() {
//To add clients
$form = new ClientUserForm($this->getServiceLocator()
->get('Doctrine\ORM\EntityManager'));
$form->get('submit')->setValue('Add');
$request = $this->getRequest();
if ($request->isPost()) {
$clientUser = new ClientUser();
$form->setInputFilter($clientUser->getInputFilter());
$form->setData($request->getPost());
if ($form->isValid()) {
$clientUser->populate($form->getData());
/**
*This bottom line is where I get the exception!
*/
$this->getEntityManager()->persist($clientUser);
$this->getEntityManager()->flush();
//Redirect
return $this->redirect()->toRoute('client_user');
}
}
return array ('form' => $form);
}
Any help would be awesome! If I just knew which class "" is supposed to be, I'd probably be in a better place than I am now!
Thanks ladies and gents, you guys rock!
EDIT-
Forgot to add these 2 PHP warnings...
Warning: spl_object_hash() expects parameter 1 to be object, integer given in (path)\htdocs\vendor\doctrine\orm\lib\Doctrine\ORM\UnitOfWork.php on line 1588
Warning: get_class() expects parameter 1 to be object, integer given in (path)\vendor\doctrine\orm\lib\Doctrine\ORM\UnitOfWork.php on line 1596
Im not sure of what could be happening, but i find something that i dont understand. When you states the inheritance, you use:
* #ORM\DiscriminatorColumn(name="user_type", type="integer")
* #ORM\DiscriminatorMap({1 = "DeveloperUser", 2 = "ClientUser"})
but
there isnt a class called DeveloperUser
and also
are you sure that in the database, all user_type are just 1 or 2? (no null, not 0, etc)
I have a Doctrine entity that has been translated using the Translatable Doctrine extension:
<?php
namespace Myapp\ProductBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
use Gedmo\Translatable\Translatable;
/**
* #ORM\Table(name="product_property")
* #ORM\Entity()
* #Gedmo\TranslationEntity()
*/
class Property implements Translatable
{
/**
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #Gedmo\Translatable
* #ORM\Column(name="name", type="string", length=255)
*/
private $name;
/**
* #ORM\OneToMany(
* targetEntity="PropertyTranslation",
* mappedBy="object",
* cascade={"persist", "remove"}
* )
*/
private $translations;
/**
* #Gedmo\Locale
* Used locale to override Translation listener`s locale
* this is not a mapped field of entity metadata, just a simple property
*/
private $locale;
public function setTranslatableLocale($locale)
{
$this->locale = $locale;
}
public function getTranslations()
{
return $this->translations;
}
public function addTranslation(PropertyTranslation $t)
{
if (!$this->translations->contains($t)) {
$this->translations[] = $t;
$t->setObject($this);
}
}
}
Now, I'd like to render a form with an input field for the "name" property in each of the languages available in my translation.
How is that best done?
It seems that the following bundle is able to do exactly what I was looking for: https://github.com/a2lix/TranslationFormBundle