I've seen a lot of posts here which describes the separation of concerns regarding organizing your app in bundles which work on their containing entities. But none of them states the point that these entities are related through different bundles.
As I already have an existing database which contains tables for posts, comments, tags, users, roles and some more I want to import this definition into my new symfony2 project.
My problem is that I would like to have that in different bundles like BlogBundle, UserBundle, StaticBundle, ..., but I do not know how to import the respective entities into the right bundle.
Further problem is that the user entity is referenced inside the post and comment entity so how should I do that. When I import the post, comment, tag into the BlogBundle, the user entity does not exist yet.
Can anyone guide me with a hint on how to go on with that process?
Entities are shared between bundles (of course).
If you want to do a blog, you can create a UserBundle (which could override the awesome FOSUserBundle for example), and a BlogBundle.
UserBundle will contain your User entity, BlogBundle will contain your Post and Comment entities.
Now an example of code:
In your UserBundle:
<?php
namespace YourVendorName\UserBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Table(name="my_user_table")
* #ORM\Entity(repositoryClass="YourVendorName\UserBundle\Entity\UserRepository")
*/
class User
{
/**
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(name="name")
*/
private $name;
// Getters and setters...
}
In your BlogBundle:
<?php
namespace YourVendorName\BlogBundle\Entity;
class Post
{
/**
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(name="title", type="string", length=255)
*/
private $title;
/**
* #ORM\Column(name="body", type="text")
*/
private $body;
/**
* #ORM\Column(name="created_at", type="datetime")
*/
private $createdAt;
/**
* #ORM\ManyToOne(targetEntity="YourVendorName\UserBundle\Entity\User")
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
*/
private $author;
// Getters and setters
}
So you reference an entity in another bundle thanks to such annotations:
#ORM\ManyToOne(targetEntity="YourVendorName\UserBundle\Entity\User")
Anyway, you should really read the Symfony2 documentation, it might help you understand everything.
Related
I'm converting a project to Doctrine 2.4 and the used database there is PostgreSQL.
I was wondering if it's possible to tell Doctrine to create the columns of the table(entity) in a particular order?
The table I'm currently converting has a lot of columns and some of them are relations to other tables. When the table is created, the first columns would be the primary keys, followed by foreign keys and at the end - everything else.
Here is an example code:
/**
* #Entity
* #Table(name="receipts")
*/
class Receipt {
/**
* #var
* #Id
* #GeneratedValue(strategy="IDENTITY")
* #Column(name="receipt_id", type="integer")
*/
private $receipt_id;
/**
* #var
* #Column(name="created_date", type="date", nullable=false)
*/
private $created_date;
/**
* #var
* #Column(name="updated_date", type="date", nullable=true)
*/
private $updated_date;
/**
* #var
* #Column(name="invoice_number", type="string", nullable=true)
*/
private $invoice_number;
/**
* #var
* #Column(name="invoice_date", type="date", nullable=true)
*/
private $invoice_date;
/**
* #var
* #Column(name="invoice_link", type="text", nullable=true)
*/
private $invoice_link;
/**
* #var
* #ManyToOne(targetEntity="models\Receipts\Invoice\Type")
* #JoinColumn(name="invoice_type_id", referencedColumnName="invoice_type_id")
*/
private $invoiceType;
/**
* #var
* #ManyToOne(targetEntity="models\Payments\Method")
* #JoinColumn(name="invoice_payment_method_id", referencedColumnName="payment_method_id")
*/
private $invoicePaymentMethod;
/**
* #var
* #ManyToOne(targetEntity="models\Payments\Type")
* #JoinColumn(name="invoice_payment_type_id", referencedColumnName="payment_type_id")
*/
private $invoicePaymentType;
public function __construct(){
$this->created_date = new \Date_Time();
$this->updated_date = new \Date_Time();
}
?>
The code above will look like this in PHPPgAdmin:
And this is how I would like the columns to appear:
Of course, everything is working fine. It's just the people working on the project with me (including I) are used to seeing the tables & columns ordered in a concrete way so that we could find things fast and easy. Hopefully there is a Doctrine ninja here that could help me with this. I couldn't find anything in the documentation.
I am using Symfony2 with Doctrine 2.
I have 5 entities in my application.
Book
Keyword (Bidirectional, should fetch all books having particular keyword)
Author (Bidirectional, should fetch all books having particular author(s))
Category (Bidirectional, should fetch all books falling into particular category)
BookExtra (Unidirectional, In Book Entity, should fetch BookExtra data)
Each book can have many keywords
Each book can have many authors
Each book can fall into a single category
Each book have exactly one BookExtra record.
The keyword and author tables should contain unique values
When a new Book is added, if the Author(s) and Keyword(s) exists, the respected Author ID and Keyword ID should be assigned to the Book, and if it doesn't exist, the new records will be created and the respected ID should be assigned to the Book.
I have the following Entity Classes:
Book.php
namespace Acme\StoreBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Book
*
* #ORM\Table(name="book")
* #ORM\Entity
*/
class Book {
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var string
*
* #ORM\Column(name="isbn", type="string", length=16)
*/
protected $isbn;
/**
* #var string
*
* #ORM\Column(name="title", type="string", length=255)
*/
protected $title;
/*
* #ORM\OneToOne(targetEntity="BookExtra")
* #ORM\JoinColumn(name="extra_id", referencedColumnName="id")
*
* ********* OR *********
* *********What should go HERE*********
*
*/
protected $bookextra;
/*
* #ORM\ManyToMany(targetEntity="Author", inversedBy="books")
* #ORM\JoinTable(name="authors_books")
*/
protected $author;
/*
* #ORM\OneToOne(targetEntity="Category")
* #ORM\JoinColumn(name="category_id", referencedColumnName="id")
*/
protected $category;
}
BookExtra.php
namespace Acme\StoreBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* BookExtra
*
* #ORM\Table(name="book_extra")
* #ORM\Entity
*/
class Detail {
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var string
*
* #ORM\Column(name="data", type="string", length=255)
*/
protected $data;
}
Author.php
namespace Bookhut\BookBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Author
*
* #ORM\Table(name="author")
* #ORM\Entity
*/
class Author {
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=100)
*/
protected $name;
// **********What should go HERE*********
protected $books;
}
Keyword & Category Entities are similar to Author Entity
The Problem is that, when i generate schema with cli, it never generates Relationships/Associations.
And what should be the proper Relationships/Associations for Book & Author Entity
I searched for this problem and proper Relationships/Associations
I found this:
Symfony2 app/console not generating properties or schema updates for Entity Relationships/Associations
Saving onetoone relation entities
doctrine2: in a one-to-many bidirectional relationship, how to save from the inverse side?
But it didn't help me.
Can somebody give an example of this type of Relationships/Associations and insert operations?
For author->books:
/**
* #ManyToMany(targetEntity="Author", inversedBy="books")
* #JoinTable(name="authors_books",
* joinColumns={#JoinColumn(name="book_id", referencedColumnName="id")},
* inverseJoinColumns={#JoinColumn(name="author_id", referencedColumnName="id")}
* )
*/
protected $author;
For books->authors
/**
* #ManyToMany(targetEntity="Book", mappedBy="author")
*/
protected $books;
See http://docs.doctrine-project.org/en/latest/reference/association-mapping.html#many-to-many-bidirectional for documentation of many-to-many
See http://docs.doctrine-project.org/en/latest/reference/association-mapping.html for full documentation of associations
EDIT
Is assume all your entities will have setters and getters.
// Create new Author object
$Author = new Author();
// Use setters to set all attributes for this author
// Create new book
$Book = new Book();
// Use setters to set all attributes for book
// Attach book to author
$Author->addBook($Book);
$Book->addAuthor($Author);
The addBook and addAuthor will look like this:
// Inside author entity
public function addBook(Book $Book) {
$this->books->add($Book);
}
// Inside book entity
public function addAuthor($Author) {
$this->authors->add($Author);
}
And add a constructor to both the author and book entities:
public function __construct() {
$this->books = new ArrayCollection();
}
public function __construct() {
$this->authors = new ArrayCollection();
}
Have a look at the documentation to see more examples:
http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/working-with-associations.html
I need help. Here is the situation. I am using Symfony2 + FOSRestBundle, I created my Entity-Classes to store my data in MySQL via Doctrine. I also wrote all the Controllers to get the data and directly translate it to my database. That works fine.
namespace Stat\ContentBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="agegroups")
*/
class Table
{
* #ORM\Column(name="id", type="smallint")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
protected $id;
/**
* #ORM\Column(name="description", type="string", length=50)
* #Type("string")
*/
protected $description;
Now I do want to use the same Entity declaration and extend it with some more information for usage with MongoDB. I want to store my data in MySQL and additionally in MongoDB. To reuse the code with the mongodb-odm-bundle I have to use the namespace Document - and that's just the beginning of the problems. If I would want to reuse my Controllers I would have to rewrite that code for MongoDB as well.
namespace Stat\ContentBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB;
/**
* #MongoDB\Document
* #ORM\Entity
* #ORM\Table(name="agegroups")
*/
class Table
{
* #ORM\Column(name="id", type="smallint")
* #ORM\Id
* #MongoDB\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
protected $id;
/**
* #ORM\Column(name="description", type="string", length=50)
* #MongoDB\String
* #Type("string")
*/
protected $description;
/**
* #ORM\Column(name="mySqlOnly", type="string", length=50)
* #Type("string")
*/
protected $mySqlOnly;
/**
* #MongoDB\String
*/
protected $mongoDbOnly;
Is there an easy way to use a Doctrine-database schema for both document-based and relational databases?
Maybe this helps:
Blending the ORM and MongoDB ODM
It is quote easy to use a database nybrid with Doctrine2 since you have an entity- plus an documentmanager.
I've been trying to get an existing project working on local copy but have been countering alot of problems with the ODM and the dependencies.
I'm encountering this Sluggable issue :
[Semantical Error] The annotation "#Gedmo\Mapping\Annotation\Sluggable" in property
Cereals\ProductBundle\Document\Category\Specialty::$name does not exist, or could not be
auto-loaded.
And my Cereals...\Specialty file is such:
<?php
namespace Cereals\ProductBundle\Document\Category;
use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB;
use Gedmo\Mapping\Annotation as Gedmo;
/**
* #MongoDB\Document(collection="Specialty",
repositoryClass="Cereals\ProductBundle\Repository\SpecialtyRepository")
*/
class Specialty
{
/**
* #MongoDB\Id(strategy="auto")
*/
protected $id;
/**
* #Gedmo\Sluggable
* #MongoDB\Index(order="asc")
* #MongoDB\String
*/
protected $name;
/**
* #MongoDB\String
* #MongoDB\UniqueIndex
* #Gedmo\Slug
*/
protected $slug;
/**
* #MongoDB\String
*/
I understand from Googling that there are some syntax updates for doctrine 2.1.x and I've used the new annotations for the #Gedmo\Mapping\Annotation\Sluggable here too.
Still the Semantical Error turns up.
Can anyone point some directions ? Thanks !
The #Gedmo\Sluggable annotation does not exisit. If you look in this folder, you will see this anottation is not implemented.
Actually, You can define your class like that:
<?php
namespace Cereals\ProductBundle\Document\Category;
use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB;
use Gedmo\Mapping\Annotation as Gedmo;
/**
* #MongoDB\Document(collection="Specialty",
repositoryClass="Cereals\ProductBundle\Repository\SpecialtyRepository")
*/
class Specialty
{
/**
* #MongoDB\Id(strategy="auto")
*/
protected $id;
/**
* #MongoDB\Index(order="asc")
* #MongoDB\String
*/
protected $name;
/**
* #MongoDB\String
* #MongoDB\UniqueIndex
* #Gedmo\Slug(fields={"name"})
*/
protected $slug;
}
The #Gedmo\Slug annotation needs the properties which will be used for the slug generation.
i finally set up my mapping for my two tables, i can now join tables via the querybuilder..
however, i cant add data to the join column, its keeps saying null.
my account entity:
namespace Entities\Users;
/**
* #Entity(repositoryClass="\Entities\Users\Account")
* #Table(name="account")
* #HasLifecycleCallbacks
*/
class Account extends \Entities\AbstractEntity {
/**
* #Id #Column(name="accid", type="bigint",length=15)
* #GeneratedValue(strategy="AUTO")
*/
protected $accid;
/** #Column(name="name", type="string", length=255) */
protected $name;
/** #Column(name="profileid", type="integer", length=255) */
protected $profileid;
/** #Column(name="acc_added_date", type="datetime", columnDefinition="datetime", nullable=true) */
private $acc_added_date;
/**
* #ManyToOne(targetEntity="Profiledetails")
* #JoinColumn(name="profileid", referencedColumnName="pid")
*/
private $account;
and my profiledetails entity:
namespace Entities\Users;
/**
* #Entity(repositoryClass="\Entities\Users\Profiledetails")
* #Table(name="profiledetails")
* #HasLifecycleCallbacks
*/
class Profiledetails extends \Entities\AbstractEntity {
/**
* #Id #Column(name="pid", type="bigint",length=15)
* #GeneratedValue(strategy="AUTO")
*/
protected $accid;
/** #Column(name="name", type="string", length=255) */
protected $name;
/** #Column(name="profileid", type="integer", length=255) */
protected $profileid;
/** #Column(name="acc_added_date", type="datetime", columnDefinition="datetime", nullable=true) */
private $acc_added_date;
/**
* #OneToMany(targetEntity="Account", mappedBy="account")
* #JoinColumn(name="pid", referencedColumnName="pid")
*/
private $stances;
i use to use :
$postdata array ('name'=>'jason');
$entity =new \Entities\Users\Account;
$obj->setData($postdata);
$this->_doctrine->persist($obj);
$this->_doctrine->flush();
$this->_doctrine->clear();
and it doesnt add.. what the way to add data to the parent table where all linked tables get updated? because before i could enter a profileid and now its null because i used it as a the joined column..
Linked objects can be "updated" if you setup cascade=[persist] in your relationship definitions. You also need #mappedBy and #inversedBy to be set for both sides of the relations. Basically #mappedBy is set to the oneToMany side (called inverse side) and #inversedBy to the manyToOne side (called owning side)
http://www.doctrine-project.org/docs/orm/2.0/en/reference/association-mapping.html#one-to-many-bidirectional
The proper way is basically
//assume $this->_doctrine is instance of EntityManager
$user = new User();
$user->setEmail('john#example.com');
$account = new Account();
$account->setName('john');
$account->setUser($user);
$user->addAccount($account); //if no cascade set
$this->_doctrine->persist($account);
$this->_doctrine->persist($user); //if no cascade set
$this->_doctrine->flush();
http://www.doctrine-project.org/docs/orm/2.0/en/reference/working-with-associations.html#establishing-associations