I am trying to model the following table structure in Symfony 2.0 using annotations.
State
PK Code
Name
County
PK State_Code -> FK State.Code
PK Code
Name
Muni
PK State_Code -> FK.State.Code
PK County_Code -> FK County.Code
PK Code
Name
Modeling the fields and the state - county relationship is simple enough, but I cannot determine how to define the relationship for the Muni table.
States have one or more counties.
Counties have one or more Munis.
Munis belong to one or more Counties.
The table structure is legacy and cannot be modified.
Here you go. Tested with Symfony 2.0.5 (Doctrine 2.1):
State.php
namespace Acme\WhateverBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* State
*
* #ORM\Entity
*/
class State
{
/**
* #ORM\Id()
* #ORM\GeneratedValue(strategy="NONE")
* #ORM\Column(name="Code", type="integer")
*/
private $code;
/**
* #ORM\Column(name="Name", type="string")
*/
private $name;
/**
* #ORM\OneToMany(targetEntity="County", mappedBy="state_code")
*/
private $counties;
/**
* #ORM\OneToMany(targetEntity="Muni", mappedBy="state_code")
*/
private $munis;
}
County.php
namespace Acme\WhateverBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* County
*
* #ORM\Entity()
*/
class County
{
/**
* #ORM\Id
* #ORM\GeneratedValue(strategy="NONE")
* #ORM\Column(name="Code", type="integer")
*/
private $code;
/**
* #ORM\Column(name="Name", type="string")
*/
private $name;
/**
* #ORM\Id
* #ORM\GeneratedValue(strategy="NONE")
* #ORM\ManyToOne(targetEntity="State", inversedBy="counties")
* #ORM\JoinColumn(name="State_Code", referencedColumnName="Code")
*/
private $state_code;
/**
* #ORM\OneToMany(targetEntity="Muni", mappedBy="county_code")
*/
private $munis;
}
Muni.php
namespace Acme\WhateverBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Muni
*
* #ORM\Entity
*/
class Muni
{
/**
* #ORM\Id
* #ORM\GeneratedValue(strategy="NONE")
* #ORM\Column(name="Code", type="integer")
*/
private $code;
/**
* #ORM\Column(name="Name", type="string")
*/
private $name;
/**
* #ORM\Id
* #ORM\GeneratedValue(strategy="NONE")
* #ORM\ManyToOne(targetEntity="County", inversedBy="munis")
* #ORM\JoinColumn(name="County_Code", referencedColumnName="Code")
*/
private $county_code;
/**
* #ORM\Id
* #ORM\GeneratedValue(strategy="NONE")
* #ORM\ManyToOne(targetEntity="State", inversedBy="munis")
* #ORM\JoinColumn(name="State_Code", referencedColumnName="Code")
*/
private $state_code;
}
Don't forget to generate getters/setters. All relationships are bi-directional.
Related
I try to use #MappedSuperclass. It works well for simple variable (int, string...) and OneToMany/ManyToOne relationship. But OneToOne relationship doesn't work.
I have two MappedSuperclass with OneToOne relationship :
_SiteUser
/**
* #MappedSuperclass _SiteUser
*
* #ORM\Entity(repositoryClass="_SiteModule\_Repository\_SiteUserRepository")
* #ORM\Table(name="site_users")
*/
class _SiteUser
{
/**
* #var int
* #Groups("id")
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var string
* #Groups({"username"})
*
* #ORM\Column(name="username", type="string", length=255, unique=true)
*/
protected $username;
/**
* #var string
* #Groups({"password"})
*
* #ORM\Column(name="password", type="string", length=255)
*/
protected $password;
/**
* #var _SiteUserTo
*
* #ORM\OneToOne(targetEntity="_SiteModule\_Entity\_SiteUserTo", mappedBy="user")
* #Gedmo\Versioned()
*/
protected $user_to;
_SiteUserTo
/**
* #MappedSuperclass _SiteUserTo
*
* #ORM\Entity(repositoryClass="_SiteModule\_Repository\_SiteUserToRepository")
* #ORM\Table(name="users_to")
*/
class _SiteUserTo
{
/**
* #var int
* #Groups("id")
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var _SiteUser
*
* #ORM\OneToOne(targetEntity="_SiteModule\_Entity\_SiteUser", inversedBy="user_to")
* #JoinColumn(name="user_id", referencedColumnName="id")
*/
protected $user;
And this is my 2 class who extends these MappedSuperclass :
SiteUser
/**
* SiteUser
*
* #ORM\Entity(repositoryClass="SiteModule\Repository\SiteUserRepository")
* #ORM\Table(name="site_users")
*/
class SiteUser extends _SiteUser
{
}
SiteUserTo
/**
* SiteUserTo
*
* #ORM\Entity(repositoryClass="SiteModule\Repository\SiteUserToRepository")
* #ORM\Table(name="users_to")
*/
class SiteUserTo extends _SiteUserTo
{
}
When I generate entities from my MappedSuperclass (_SiteUser and _SiteUserTo), I got well a table named "users_to" with id and user_id. But when I generate entities from my others classes (SiteUser and SiteUserTo), it creates the table "users_to" with only id field. I don't know why...
If I update my SiteUser Class like this :
/**
* Class SiteUser
*
* #ORM\Entity(repositoryClass="SiteModule\Repository\SiteUserRepository")
* #ORM\Table(name="site_users")
*/
class SiteUser extends _SiteUser
{
/**
* #var boolean
*
* #ORM\Column(name="test", type="boolean")
*/
protected $test;
/**
* #var SiteUserTo
*
* #ORM\OneToOne(targetEntity="SiteModule\Entity\SiteUserTo", mappedBy="user")
*/
protected $user_to;
}
And SiteUserTo like this :
/**
* Class SiteUserTo
*
* #ORM\Entity(repositoryClass="SiteModule\Repository\SiteUserToRepository")
* #ORM\Table(name="users_to")
*/
class SiteUserTo extends _SiteUserTo
{
/**
* #var boolean
*
* #ORM\Column(name="test", type="boolean")
*/
protected $test;
/**
* #var SiteUser
*
* #ORM\OneToOne(targetEntity="SiteModule\Entity\SiteUser", inversedBy="user_to")
* #JoinColumn(name="user_id", referencedColumnName="id")
*/
protected $user;
}
I got the same problem, no field user_id in table users_to. But the field "test" is well created in the table site_users and in the table users_to...
A mapped superclass cannot be an entity, it is not query-able and
persistent relationships defined by a mapped superclass must be
unidirectional (with an owning side only). This means that One-To-Many
associations are not possible on a mapped superclass at all.
Furthermore Many-To-Many associations are only possible if the mapped
superclass is only used in exactly one entity at the moment. For
further support of inheritance, the single or joined table inheritance
features have to be used.
Simply said you can not have #MappedSuperClass and #ORM\Entity annotations at the same time, hence the unexpected results
https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/reference/inheritance-mapping.html
I'm trying to get a legacy database into the doctrine mappings.
All the tables have a combined primary key. One ID and one "optios id".
The problem is that Optios ID always has to be set but the OneToOne relation with the same columns causes the column "Optios ID" to be set to null. I'm not sure what I'm doing wrong or is there a way around it?
PS: The 'Pack' relation is optional.
<?php
namespace CalendarBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="CalendarBundle\Repository\CategoryRepository")
* #ORM\Table(name="Categories")
*/
class Category
{
/**
* #ORM\Id
* #ORM\Column(type="integer", name="Category_id")
*/
private $id;
/**
* #ORM\Column(type="integer", name="Optios_id")
* #ORM\Id
*/
private $optiosId;
/**
* #ORM\Column(type="string", name="Name")
*/
private $name;
/**
* #ORM\Column(type="boolean", name="AvailableOnline")
*/
private $online;
/**
* #ORM\Column(type="integer", name="SequenceNumber", nullable=true)
*/
private $order;
/**
* #ORM\Column(type="integer", name="Parent_id")
*/
private $parentId;
/**
* One Category has Many Packs.
*
* #var Pack
*
* #ORM\OneToOne(targetEntity="Pack", inversedBy="category")
* #ORM\JoinColumns(
* #ORM\JoinColumn(name="Pack_id", referencedColumnName="Pack_id"),
* #ORM\JoinColumn(name="Optios_id", referencedColumnName="Optios_id"),
* )
*/
private $pack;
/**
* #ORM\Column(type="boolean", name="Deleted")
*/
private $deleted;
I have two entities joined one to many. When I call the API for it, I get collection as the referencing url and not the entente data itself.
What do I need to have in my entity annotation to get that data collected? Here is the output from API client:
{
"#id": "/app_dev.php/api/fee_schedule_categories/4",
"#type": "FeeScheduleCategory",
"id": 4,
"custId": 0,
"scheduleName": "Daily Claim Schedule",
"scheduleStatus": 1,
"scheduleId": [
"/app_dev.php/api/fee_schedules/1239",
"/app_dev.php/api/fee_schedules/1240",
"/app_dev.php/api/fee_schedules/1241",
"/app_dev.php/api/fee_schedules/1242"
],
}
scheduleId should show data and not API links.
Here are my entities:
AppBundle/Entity/FeeSchedule.php
namespace AppBundle\Entity;
use ApiPlatform\Core\Annotation\ApiResource;
use Doctrine\ORM\Mapping as ORM;
/**
* #ApiResource
* #ORM\Entity
*/
class FeeSchedule
{
/**
* #var int The id of fee category tier.
*
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
/**
* #var FeeScheduleCategory The fee schedule category this fee schedule tier is for.
*
* #ORM\ManyToOne(targetEntity="FeeScheduleCategory",inversedBy="schedule_id")
*/
private $schedule_category;
/**
* #var decimal.
*
* #ORM\Column(type="decimal", precision=13, scale=2)
*/
private $range_from;
/**
* #var decimal.
*
* #ORM\Column(type="decimal", precision=13, scale=2)
*/
private $range_to;
/**
* #var decimal.
*
* #ORM\Column(type="decimal", precision=13, scale=2)
*/
private $amount;
/**
* #var int.
*
* #ORM\Column(type="integer")
*/
private $amount_type;
AppBundle/Entity/FeeScheduleCategory.php
namespace AppBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use ApiPlatform\Core\Annotation\ApiResource;
use Doctrine\ORM\Mapping as ORM;
/**
* #ApiResource
* #ORM\Entity
*/
class FeeScheduleCategory
{
/**
* #var int The id of this fee schedule category.
*
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
/**
* #var ArrayCollection<\AppBundle\Entity\FeeSchedule> Available fee schedules.
*
* #ORM\OneToMany(targetEntity="FeeSchedule", mappedBy="schedule_category")
*/
private $schedule_id;
/**
* #var int The customer id of this this fee schedule category.
*
* #ORM\Column(type="integer")
*/
private $cust_id;
/**
* #var string The title of this schedule category.
*
* #ORM\Column
*/
private $schedule_name;
/**
* #var int The enabled/disabled status.
*
* #ORM\Column(type="integer")
*/
private $schedule_status;
public function __construct()
{
$this->schedule_id = new ArrayCollection();
}
By default, API Platform serializes all relations as links (IRIs). If you want to embed the related document instead, you need to use groups as described in the documentation: Embedding Relations.
For your code, it will look like the following:
FeeScheduleCategory.php
namespace AppBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use ApiPlatform\Core\Annotation\ApiResource;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups;
/**
* #ApiResource(attributes={"normalization_context"={"groups"={"fsc_read"}}})
* #ORM\Entity
*/
class FeeScheduleCategory
{
/**
* #var int The id of this fee schedule category.
*
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
/**
* #var ArrayCollection<\AppBundle\Entity\FeeSchedule> Available fee schedules.
*
* #ORM\OneToMany(targetEntity="FeeSchedule", mappedBy="schedule_category")
* #Groups({"fsc_read"})
*/
private $schedule_id;
/**
* #var int The customer id of this this fee schedule category.
*
* #ORM\Column(type="integer")
* #Groups({"fsc_read"})
*/
private $cust_id;
/**
* #var string The title of this schedule category.
*
* #ORM\Column
* #Groups({"fsc_read"})
*/
private $schedule_name;
/**
* #var int The enabled/disabled status.
*
* #ORM\Column(type="integer")
* #Groups({"fsc_read"})
*/
private $schedule_status;
// ...
}
FeeSchedule.php
namespace AppBundle\Entity;
use ApiPlatform\Core\Annotation\ApiResource;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups;
/**
* #ApiResource
* #ORM\Entity
*/
class FeeSchedule
{
/**
* #var int The id of fee category tier.
*
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
/**
* #var FeeScheduleCategory The fee schedule category this fee schedule tier is for.
*
* #ORM\ManyToOne(targetEntity="FeeScheduleCategory",inversedBy="schedule_id")
*/
private $schedule_category;
/**
* #var decimal.
*
* #ORM\Column(type="decimal", precision=13, scale=2)
* #Groups({"fsc_read"})
*/
private $range_from;
/**
* #var decimal.
*
* #ORM\Column(type="decimal", precision=13, scale=2)
* #Groups({"fsc_read"})
*/
private $range_to;
/**
* #var decimal.
*
* #ORM\Column(type="decimal", precision=13, scale=2)
* #Groups({"fsc_read"})
*/
private $amount;
/**
* #var int.
*
* #ORM\Column(type="integer")
* #Groups({"fsc_read"})
*/
private $amount_type;
// ...
}
I have these 3 entitites
Users.php
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Users
*
* #ORM\Table(name="users")
* #ORM\Entity(repositoryClass="AppBundle\Repository\UsersRepository")
*/
class Users
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="email", type="string", length=255, unique=true)
*/
private $email;
/**
* #var string
*
* #ORM\Column(name="password", type="string", length=20)
*/
private $password;
/**
* #var string
*
* #ORM\Column(name="phone", type="string", length=20)
*/
private $phone;
/**
* #var string
*
* #ORM\Column(name="type", type="string")
*/
private $type;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=255)
*/
private $name;
/**
* #var int
*
* #ORM\Column(name="feedback", type="integer")
*/
private $feedback;
/**
* #var string
*
* #ORM\Column(name="picture", type="blob")
*/
private $picture;
/**
* #var int
*
* #ORM\Column(name="rating", type="integer", length=255)
*/
private $rating;
/**
* #var string
*
* #ORM\Column(name="info", type="text")
*/
private $info;
/**
* #var \DateTime
*
* #ORM\Column(name="datecreated", type="datetime")
*/
private $datecreated;
/**
* #ORM\Column(name="is_active", type="boolean")
*/
private $isActive;
}
client.php
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* client
*
* #ORM\Table(name="client")
* #ORM\Entity(repositoryClass="AppBundle\Repository\clientRepository")
*/
class client extends Users
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var int
*
* #ORM\Column(name="numberofjobsposted", type="integer")
*/
private $numberofjobsposted;
/**
* #var string
*
* #ORM\Column(name="clienttype", type="string", length=255)
*/
private $clienttype;
}
sprovider.php
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* sprovider
*
* #ORM\Table(name="sprovider")
* #ORM\Entity(repositoryClass="AppBundle\Repository\sproviderRepository")
*/
class sprovider extends Users
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var array
*
* #ORM\Column(name="interestedin", type="simple_array")
*/
private $interestedin;
/**
* #var int
*
* #ORM\Column(name="numofsuccjobs", type="integer")
*/
private $numofsuccjobs;
/**
* #var string
*
* #ORM\Column(name="sprovidertype", type="string", length=255)
*/
private $sprovidertype;
/**
* #var string
*
* #ORM\Column(name="address", type="string", length=255)
*/
private $address;
/**
* #var string
*
* #ORM\Column(name="postcode", type="string", length=255)
*/
private $postcode;
}
So I achieved that the extends statement provides the Users properties in the client and sprovider tables in MySQL. That's awesome. What I want now is to make the relations so that when I add a new client for example, both the tables Users and client add a new user/client in MySQL, and they have same id too.
the type() property in the Users entity i would like to be optional for the type of user I create. Example : I create a new client and in the Users table in MySQL the type is set to "CLIENT".
I read this and so far I think it has to be ManyToMany relation but It's quite confusing to me.
How to make those relations in the entities and then how to use them in the controller? If possible, please provide an example.
I think you're confused about the reasons to use inheritance.
The idea is that you have base class, in this case User, and that can be extended to provide variations of that class, in this case client (you should capitalise this) and sprovider.
Ideally, you would not have a User table, only the other 2.
In doctrine, this is called a mapped super-class.
A mapped superclass is an abstract or concrete class that provides persistent entity state and mapping information for its subclasses, but which is not itself an entity. Typically, the purpose of such a mapped superclass is to define state and mapping information that is common to multiple entity classes.
see the documentation here
you can link properties using relationships, this is their example.
<?php
/** #MappedSuperclass */
class MappedSuperclassBase
{
/** #Column(type="integer") */
protected $mapped1;
/** #Column(type="string") */
protected $mapped2;
/**
* #OneToOne(targetEntity="MappedSuperclassRelated1")
* #JoinColumn(name="related1_id", referencedColumnName="id")
*/
protected $mappedRelated1;
// ... more fields and methods
}
/** #Entity */
class EntitySubClass extends MappedSuperclassBase
{
/** #Id #Column(type="integer") */
private $id;
/** #Column(type="string") */
private $name;
// ... more fields and methods
}
I defined a mapping for
/**
* Identite entity
* #ORM\Entity
* #ORM\Table(name="identite")
* #ORM\InheritanceType("JOINED")
* #ORM\DiscriminatorColumn(name="discr", type="string")
* #ORM\DiscriminatorMap({"identite" = "Identite","candidat" = "Candidat","consultant"="Consultant","staff"="Staff" })
*/
class Identite extends ObjetEtat{
/**
* #var integer
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var string
*
* #ORM\Column(name="nomidentite", type="string", length=200, nullable=true)
*/
private $nomidentite;}
and I have the mapping of the super Class:
/**
* Identite entity
* #ORM\Entity
* #ORM\Table(name="objetetat")
* #ORM\InheritanceType("JOINED")
* #ORM\DiscriminatorColumn(name="discrimin", type="string")
* #ORM\DiscriminatorMap({"objetetat" = "ObjetEtat","identite" = "Sigmatis\SigBundle\Entity\Identites\Identite" })
*/
class ObjetEtat {
//put your code here
/**
* #var integer
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id; }
And this is the third level of my hierarchy :
/**
* Candidat entity
* #ORM\Entity
* #ORM\Table(name="candidat")
*/
class Candidat extends Identite {
}
After updating my schema : I don't find the field "discr " of my table Identite . Do I miss something ??
You should put the #ORM\DiscriminatorColumn and #ORM\DiscriminatorMap annotations on the superclass, not the child one