0

I tried almost everything trying to make Entities that represent my database schema and still having full page errors. If someone can give me some light I would appreciated.

Basically we have 2 registration forms, one for the brand and one for the influencer. In each form we ask for the user information PLUS the specific information depending on which form page you are.

DATABASE SCHEMA:

  • Role (this table is already populated with the "type" of person they are, either administrator, brand or influencer)

id | name

  • User (this table contains the general information of a person, email and password will be used to login)

id | id_role FK| name | phone | email | password | created_at | status

  • Brand (this table contains the specific information of a brand which used the brand form for the registry)

id | user_id FK| name_brand | position_id | email_brand | nif_brand | name_firma | phone_brand |

  • Position (this table is already populated with positions we display to be selected, e.g, CEO)

id | name

  • District (this table is already populated with districts we display to be selected, e.g, NJ)

id | name

  • Influencer (this table contains the specific information of a influencer which used the brand form for the registry)

id | user_id FK | surname | date_of_birth | email_brand | district_id FK | gender

MAIN POINTS:

I already tried to use Doctrine annotation and still didn't worked for me, not sure if it's because Im new to this or if Im not structuring the database/entities correctly or even the managing an entity with its associations into the database.

The idea is that ONE user/person can be EITHER a BRAND or INFLUENCER. That is achieved by the role_id which links to the role table. E.g, if i'm in the brand form and try add my information it will add the personal info in the users table and use the role_id 2 to link to the role table. The specific brand information given will then be inserted in the table BRAND using the user PRIMARY KEY to link both tables. (NOT SURE IF THERE'S A MISTAKE HERE, maybe the user should go through the role table and from that table to the specific table, which is not what i'm doing now). In the BRAND table I ask for it's info and coming from the POSITION SELECT in the form I get the FK position_id and link it to the table POSITION.

A different but similar thing happens with the influencer, which will select his district and then i use that district_id to link the districts table.

The problem is always the foreign key associations with doctrine and property's I need to define in the entities. I already don't declare the foreign keys because I'm aware that doctrine handles the FK relations internaly using objects but can't make this to work..

I would appreciate a lot all the help you guys can share. Thank you.

  • Have you had a look at inheritance? Specifically [CTI](https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/reference/inheritance-mapping.html#class-table-inheritance) or [STI](https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/reference/inheritance-mapping.html#single-table-inheritance) by Doctrine? – rkeet Apr 19 '18 at 10:51
  • @rkeet I didn't actually! The most appropriate way seems to be CTI – Rúben Silva Apr 19 '18 at 11:16
  • Hi Ruben, how'd it go? Did my answer help you out at all? – rkeet May 23 '18 at 14:45

1 Answers1

1

I think you're trying to manually do what Doctrine can provide through inheritance.

A small setup that should work with your description of what you're trying to do.

Generic User setup

/**
 * @ORM\Table(name="users")
 * @ORM\Entity
 *
 * @ORM\MappedSuperclass

 * @ORM\InheritanceType("JOINED")
 * @ORM\DiscriminatorColumn(name="discr", type="string")
 */
class User 
{
    /**
     * @var int
     * @ORM\Id
     * @ORM\Column(name="id", type="integer")
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    protected $id;

    /**
     * @var string
     * @ORM\Column(name="name", type="string", length=255, nullable=false, unique=true)
     */
    protected $name;

    /**
     * @var Position
     * @ORM\OneToOne(...)
     */
    protected $position; // TODO

    // getters/setters & other properties
}

Brand user

/**
 * @ORM\Table(name="brands")
 * @ORM\Entity
 */
class BrandUser extends User
{
    /**
     * @var string
     * @ORM\Column(name="specific_brand_property", type="string", length=255, nullable=false, unique=false)
     */
    protected $specificBrandProperty;

    // getters/setters & other properties
}

This small setup should already provide you with 2 Entity objects: User and BrandUser, where the latter expands the first.

The primary keys for BrandUser will be Foreign Keys to User and requirements of User are also requirements for BrandUser.

If you're using Fieldset and InputFilter classes you can have the BrandUserFieldset expand the Fieldset for use in your form (example below and more info in one of my repo's on this subject)

class UserFieldset
{
    public function init()
    {
        parent::init();

        $this->add([
            'name' => 'id',
            'required' => true,
            'type' => Hidden::class,
        ]);

        $this->add([
            'name' => 'name',
            'required' => true,
            'type' => Text::class,
            'options' => [
                'label' => 'Name',
            ],
        ]);

        $this->add([
            'name' => 'position',
            'required' => true,
            'type' => ObjectSelect::class,
            // other properties
        ]);
    }
}

Extended for BrandUser

class BrandUserFieldset extends UserFieldset
{
    public function init()
    {
        parent::init(); // <-- adds id, name, position

        $this->add([
            'name' => 'specificBrandProperty',
            'required' => true,
            'type' => Text::class,
            'options' => [
                'label' => 'Name',
            ],
        ]);
    }
}

Thought to add some commands, they might help you out. My setup requires me to prefix commands with ./vendor/bin/doctrine-module, add what you need for your setup to the following:

  • orm:validate-schema - will check your Doctrine Annotation for errors. Will also return any errors (syntax and logic) it finds
  • orm:schema-tool:update - command to create/update your database schema
    • flag -f - will make :update execute for real
    • flag --dump-sql will make :update not execute, but have the SQL dumped in your Terminal
    • flags -f and --dump-sql may be combined
  • orm:mapping:describe “\Full\Namespace\To\Entity” - Shows all information Doctrine has about a specific Entity - including relations, relation mappings, discriminators, extending (child) and parent entities, et cetera

Also, have a look at a solution I had for a similar problem some time ago.

rkeet
  • 3,406
  • 2
  • 23
  • 49
  • Thank you very much for your time and answer! I have another doubt, actually in the generic user should i add the property that is used in the database as the FK? Not sure if im thinking wrong but I can't have the position there on the generic user because when I create class InfluencerUser extends User then it will have a position, and the position is specific of the brand. Do you mean ROLE so each user has a specific role? – Rúben Silva Apr 19 '18 at 11:24
  • The `Primary Key` identifier is the property `id`. When extending a class like this, and using a Discriminator, the unique `id` property is set on the top-most class. In this example, the primary key `id` is in the `users` table (`id` property). The `id` used by `BrandUser` is a Foreign Key to the `User` Entity. – rkeet Apr 19 '18 at 11:44
  • I added `position` and `specificBrandProperty` properties as examples for you to fill in with your own properties. If you have your own `position` property only in your `InfluencerUser` Entity and not in `BrandUser`, then yes, you should move my example property to your `InfluencerUser` Entity. When using inheritance the "above" properties should be usable (and relevant!) to all child-classes. If they're not relevant, they're on the wrong level or in the wrong Entity all together. – rkeet Apr 19 '18 at 11:46
  • I will take a close look at everything, thank you so much! – Rúben Silva Apr 19 '18 at 14:19