1
votes

I am trying to create a symfony2 application. The main idea behind the project is that there is an event which many guests are invited to and they are categorized. I have created a relational model for all the entities.

There are 4 tables:

  1. Guests - who is invited
  2. Category - what category/categories he belongs to ?
  3. Event - the event which they are invited to
  4. Guest_Event (attendance)

I have concluded to the following schemas:

xxxxBundle\Entity\Guest:
  type: entity
  table: guest
  id:
    id:
      type: integer
      generator: { strategy: AUTO }
  fields:
    name:
      type: string
      length: 100
      nullable: false
    surname:
      type: string
      length: 100
      nullable: false   
    email:
      type: string
      length: 255
      nullable: true
    address:
      type: string
      length: 255
      nullable: true
    phone:
      type: string
      length: 10
    description:
      type: text
    created_at:
      type: datetime
    updated_at:
      type: datetime
      nullable: true   
    token:
      type: string
      length: 255
      unique: true
    is_activated:
      type: boolean
      nullable: true
  manyToOne:
    category:
      targetEntity: Category
      inversedBy: guest
      joinColumn:
        name: category_id
        referencedColumnName: id
  lifecycleCallbacks:
    prePersist: [ setCreatedAtValue ]
    preUpdate: [ setUpdatedAtValue ]

Category

xxxxBundle\Entity\Category:
  type: entity
  table: category
  id:
    id:
      type: integer
      generator: { strategy: AUTO }
  fields:
    name:
      type: string
      length: 255
      unique: true
  oneToMany:
    guests:
      targetEntity: Guest
      mappedBy: category
    attend:
      targetEntity: Attendance
      mappedBy: category

Event

xxxxxBundle\Entity\Event:
  type: entity
  table: event
  id:
    id:
      type: integer
      generator: { strategy: AUTO }
  fields:
    name:
      type: string
      length: 100
      nullable: false
    location:
      type: string
      length: 255
      nullable: true
    scheduled_at:
      type: datetime
  manyToMany:
    category:
      targetEntity: guest
      inversedBy: event
      joinColumn:
        name: event_id
        referencedColumnName: id
  • A guest might belong to multiple categories (manyToOne)
  • A category will have many guests (manyToOne)
  • A guest might attend many events (manyToOne)
  • An event might have many attendants (manyToMany?)
  • the attendance table (guest_event) should be a join table ?

I am a little bit confused about ORM and doctrine coding. Creating the tables via SQL code or phpmyadmin seems much easier to me but I want to go the hard way ! The documentation seems confusing because each tutorial suggests different things and the doctrine ORM section in the symfony2 book doesn't have a complete example but pieces of code..

How can I correct my tables to include all the specifications ?

4
You should be more specific on your question. What's the real one? What do you thing it's wrong with your model? An btw, you'll appreciate the Doctrine stuff especially with Sf2 forms and querying the data...gremo
Actually I do not know how to connect the tables between them. In pure SQL I could use foreign keys, but as far as I know you do not have to declare that it's a many-to-one or one-to-one relatioship etc. As doctrine & yaml ask for this kind of things, it's a little bit confusing.Radolino
Forgot to say (if this is your first Sf2 app) go for annotations. Make PHP classes and let doctrine generate setters/getters. This way you can have field definition plus validation in the same file (class).gremo
You have to do nothing, it's doctrine that will carry foreign keys generation for you. You want to set nullable=false (default is true) for those foreign keys that can't be null: docs.doctrine-project.org/projects/doctrine-orm/en/2.0.x/…gremo
Do you find annotations easier than yaml ? I am reading the jobeet Sf2 tutorial and he uses yml so I supposed it's easier that way ens.ro/2012/03/27/symfony2-jobeet-day-3-the-data-model How should I connect two entities (guests_id and events_id) ? It's a manyToMany relationship and seems the hardest of all to code.Radolino

4 Answers

0
votes

My two cents:

A guest might belong to multiple categories

So many guests can belong to many categories, so it's many to many guest side. Assuming the owning side is Guest:

xxxxBundle\Entity\Guest:
  manyToMany:
    categories:
      targetEntity: Category
      inversedBy: guests
      joinTable:
         name: guests_categories

A category will have many guests (manyToOne)

If category will have many guests, why is's many to one? Many categories can be assigned to many guest:

xxxxBundle\Entity\Category:
  manyToMany:
    guests:
      targetEntity: Guest
      mappedBy: categories

If i understand you correctly, a categoy may exist even without a guest, and vice-versa a guest may exist even without a category.

And for guest/events relation, i'll go again for many to many / many to many. Take a look at here and ask yourself: one/many type of my entity can have one/many type of another entity?

0
votes

I would strongly suggest you work your way through the official Symfony 2 documentation: http://symfony.com/doc/master/book/doctrine.html

It takes you step by step through the process of initializing the database, making an entity, mapping it to the database and then using the entity.

You are trying to understand multiple concepts by reading assorted documentation. The fact that you seem to have yaml files in your entity directory indicates a basic lack of understanding.

Go through the tutorial first then add in your real entities. It's pretty straight forward once you get a few things working.

0
votes

I changed my mind and used annotations as yaml seems confusing to me.

So far :

For the Guest entity

<?php
// xxxxBundle/Entity/Guest.php

namespace xxxxBundle\Entity;

use Symfony\Component\Validator\Mapping\ClassMetadata;
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\Validator\Constraints\Email;
use Symfony\Component\Validator\Constraints\MinLength;
use Symfony\Component\Validator\Constraints\MaxLength;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 * @ORM\Table(name="guest")
 */
class Guest
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /**
    * @ManyToMany(targetEntity="Category", inversedBy="guests")
    * @JoinTable(name="guests_categories")
    */
    protected $categories;

    /**
    * @ManyToMany(targetEntity="Event", inversedBy="events")
    * @JoinTable(name="guests_events")
    */
    protected $events;

    /**
     * @ORM\Column(type="string", length=30)
     */
    protected $name;

    /**
     * @ORM\Column(type="string", length=30)
     */
    protected $surname;

    /**
     * @ORM\Column(type="string", length=30)
     */
    protected $email;

    /**
     * @ORM\Column(type="string", length=100)
     */
    protected $address;

    /**
     * @ORM\Column(type="string", length=10)
     */
    protected $phone;

    /**
     * @ORM\Column(type="string", length=10)
     */
    protected $mobile;

    /**
     * @ORM\Column(type="text")
     */
    protected $description;

    /**
     * @ORM\Column(type="datetime")
     */
    protected $created_at;

    /**
     * @ORM\Column(type="datetime")
     */
    protected $updated_at;

    /**
     * @ORM\Column(type="string")
     */
    protected $token;

    /**
     * @ORM\Column(type="boolean")
     */
    protected $is_activated;

    public function __construct() {
        $this->categories = new \Doctrine\Common\Collections\ArrayCollection();
    }

    public static function loadValidatorMetadata(ClassMetadata $metadata)
    {
        $metadata->addPropertyConstraint('name', new NotBlank());
        $metadata->addPropertyConstraint('surname', new NotBlank());
        $metadata->addPropertyConstraint('email', new Email(array(
            'message' => 'I do not like invalid emails. Give me a real one!')));

        $metadata->addPropertyConstraint('phone', new MaxLength(10));
        $metadata->addPropertyConstraint('mobile', new MaxLength(10));

    }    

}

For the Category entity

<?php
// xxxxBundle/Entity/Category.php

namespace xxxxBundle\Entity;

use Symfony\Component\Validator\Mapping\ClassMetadata;
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\Validator\Constraints\Email;
use Symfony\Component\Validator\Constraints\MinLength;
use Symfony\Component\Validator\Constraints\MaxLength;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 * @ORM\Table(name="category")
 */
class Category
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /**
    * @ManyToMany(targetEntity="Guest", mappedBy="categories")
    */
    protected $guests;

    /**
     * @ORM\Column(type="string", length=30)
     */
    protected $name;

    /**
     * @ORM\Column(type="text")
     */
    protected $description;

    public function __construct() {
        $this->categories = new \Doctrine\Common\Collections\ArrayCollection();
    }

    public static function loadValidatorMetadata(ClassMetadata $metadata)
    {
        $metadata->addPropertyConstraint('name', new NotBlank());

    }    

}

For the Event entity

<?php
// xxxxBundle/Entity/Event.php

namespace xxxxBundle\Entity;

use Symfony\Component\Validator\Mapping\ClassMetadata;
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\Validator\Constraints\Email;
use Symfony\Component\Validator\Constraints\MinLength;
use Symfony\Component\Validator\Constraints\MaxLength;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 * @ORM\Table(name="event")
 */
class Event
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /**
    * @ManyToMany(targetEntity="Guest", mappedBy="categories")
    */
    protected $guests;

    /**
     * @ORM\Column(type="string", length=30)
     */
    protected $name;

    /**
     * @ORM\Column(type="string", length=100)
     */
    protected $location;

    /**
     * @ORM\Column(type="text")
     */
    protected $description;

    /**
     * @ORM\Column(type="datetime")
     */
    protected $scheduled_at;

    public function __construct() {
        $this->categories = new \Doctrine\Common\Collections\ArrayCollection();
    }

    public static function loadValidatorMetadata(ClassMetadata $metadata)
    {
        $metadata->addPropertyConstraint('name', new NotBlank());
        $metadata->addPropertyConstraint('location', new NotBlank());
    }    

}

I feel confused about the Attendance entity. The Attendance entity will have the following variables:

  • Guest_id
  • Event_id
  • Will_attend (yes/no/maybe)
  • Comment
  • Replied_at
  • Updated_at

I do not know which will be the primary key (or the primary keys?). The db table does not need to have a separate Id (or not?).

<?php
// xxxxBundle/Entity/Attendance.php

namespace xxxxBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 * @ORM\Table(name="attendance")
 */
class Attendance
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /**
    * @ManyToMany(targetEntity="Guest", mappedBy="categories")
    */
    protected $guests;

    /**
    * @ManyToMany(targetEntity="Event", mappedBy="events")
    */
    protected $events;

    /**
     * @ORM\Column(type="string", length=3)
     */
    protected $will_attend;

    /**
     * @ORM\Column(type="text")
     */
    protected $description;

    /**
     * @ORM\Column(type="datetime")
     */
    protected $replied_at;

    public function __construct() {
        $this->categories = new \Doctrine\Common\Collections\ArrayCollection();
    }

}
0
votes

The attendance entity requires a person to declare while he/she will attend an event or not. That means that it's a oneToOne relation because for every event must be ONE event - ONE person - ONE attendance reply.

The solution is to change the following code in the attendance entity :

/**
* @ORM\OneToOne(targetEntity="Guest")
*/
protected $guests;

/**
* @ORM\OneToOne(targetEntity="Event")
*/
protected $events;

Then run php app/console doctrine:generate:entities , php app/console doctrine:schema:update --force and the crud command If you generate them automatically. Now everything works fine.