Doctrine - Database representation - mysql

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.

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.

Related

Laravel Many To Many Merges Pivot?

I must be going insane or be really tired. So I have this situation where I get a collection of all the Roles assigned to the User. That part goes ok.... however I noticed something super strange.
I am using Laravel 8 and PHP8 (not the strange part).
For some reason, I do not get only the result from the other table but also pivot data is merged in. I can't tell why this is happening. Here is the example:
Relationship on user model:
/**
* Relationship with roles model.
*
* #return BelongsToMany
*/
public function roles(): BelongsToMany
{
return $this->belongsToMany(
Role::class,
'role_user',
'user_id',
'role_id'
)->withTimestamps();
}
Relationship on the Role model:
/**
* Relationship with users table.
*
* #return BelongsToMany
*/
public function users(): BelongsToMany
{
return $this->belongsToMany(
User::class,
'role_user',
'role_id',
'user_id'
)->withTimestamps();
}
In the user model, I have this.
$this->roles->each(function($role) {
dd($role);
});
I was expecting to get a dump of related model however for some weird reason what I get is pivot table merged with the model:
"id" => 7 // this is the relation ID from the pivot table
"display_name" => "Administrator" // this is from Role model
"code" => "admin" // role model
"description" => "Super User - can do everything in the system. This role should only be assigned to IT staff member." // role model
"created_at" => "2021-10-01 11:00:00" // pivot table
"updated_at" => null // pivot table
"deleted_at" => null // pivot table
"role_id" => 1 // pivot table
"user_id" => 2 // pivot table
Either I am doing something very wrong or I am missing something very obvious. Does anyone know what in the world is happening here?
Just to add: the data is from both places but the result is just a Role model as expected.
Should I not just get the role model without the pivot stuff in it? It is overriding my role model fields.
EDIT:
Parenthesis seems to make a difference. The data is still merged. However, when I do it like this looks like data from end model is merged (so it overrides) to data from the pivot. So I get correct ID.
$this->roles()->each(function($role) {
echo $role;
});
But this gives me this weird pivot merged version with wrong ID.
$this->roles->each(function($role) {
echo $role;
});
I know what that was exactly. Without thinking I've added the ID column into the pivot table.
This ID from pivot was overriding my ID from my end model. After I've removed it the problem is gone.
I don't know why Laravel would by default add these fields and merge with pivot columns... I guess it just does that for no reason. Although I don't understand what's the point if there is a separate mechanism to access the pivot table (pivot relationship on the model).
This makes me think I did something wrong. But yeah, hope it helps. If anyone knows why Laravel automatically adds pivot stuff, let me know.

Select related rows in Yii2

I have related tables (table train_schedule have departute_station_id and arrival_station_id) linked on Station:
enter image description here
I want select records from train_schedule with stations name:
$trainsTchedule = TrainSchedule::find()
->joinWith('getArrivalStation')
->joinWith('getDepartuteStation()')
->all();
In TrainSchedule class:
/**
* #return \yii\db\ActiveQuery
*/
public function getArrivalStation()
{
return $this->hasOne(Station::className(), ['id' => 'arrival_station_id']);
}
And
/**
* #return \yii\db\ActiveQuery
*/
public function getDepartuteStation()
{
return $this->hasOne(Station::className(), ['id' => 'departute_station_id']);
}
Error:
Relation names are case sensitive. app\models\TrainSchedule has a
relation named "arrivalStation" instead of "ArrivalStation".
Howe get data wrom linked tables?
You have defined your relations correctly but, you are calling them incorrectly. Your relation
getArrivalStation should be specified as arrivalStation
getDepartuteStation() should be departuteStation
when specifying in the joinWith, and you need to provide an array if you need to specify multiple relations when calling joinWith as currently your second call ->joinWith('getDepartuteStation()') is overriding the previous one ->joinWith('getArrivalStation').
So the query should look like below
$trainsTchedule = TrainSchedule::find()
->joinWith(['arrivalStation','departuteStation'])
->all();
You should read about Working with Relational Data

Create record with id

I need to import the data from a different database and transfer it to the new database. but the ID information of the members is required for the relationship. I have to carry them too.
Therefore, I have to fill in the ID column which is increased as AUTOINCREMENT.
My Migrate Controller
public function migrate(BackupUser $buser, User $user)
{
$backup_user = $buser->get();
foreach ($backup_user as $bulk) {
$user->create([
'id' => $bulk->uye_id,
'name' => $bulk->uye_nick,
'email' => $bulk->uye_mail,
'password' => $bulk->uye_sifre,
'created_at' => $bulk->uye_tarih
]);
}
}
when I do this, the AUTOINCREMENT increases normally and I can not get the ID information of the previous members.
What is the best way to do this?
By default, the id field for User is not fillable by mass assignment like you're doing. If you want to assign it, you must add 'id' to the array of fillable fields in the user class.
app/User.php
...
class User extends Authenticatable
{
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'id', 'name', 'email', 'password',
];
...
I think you are trying to take database from joomla or wordpress to laravel.
If I need to do this . my approach would be to store first all base tables without id and then with stored id generated after insertion would be in related tables. So the steps would be
S1: store new `user` and get `id`
S2: relate with other table like `role` with `user_id`
Loop again till last row

Relationships between tables in laravel using backpack package

I am using backpack CRUD package to create my website project in laravel 5.2
I want to establish a relationship between two tables. First table is called customer and second table is called transaction. Each customer has many transaction(1:N relationship).
Customer table record:
ID Name
123456 xyz
Transaction table record:
ID CustomerID
101010 123456
I know that I have to specify the relation in the customer model. But, how can I display the result of the relationship in CRUD ?
You should have relationships on both the Transaction and the Customer models, so you can do $customer->transactions and $transaction->customer:
class Customer extends Model
{
/**
* Get the comments for the blog post.
*/
public function transactions()
{
return $this->hasMany('App\Transactions', 'CustomerID', 'ID');
}
}
and
class Transaction extends Model
{
/**
* Get the comments for the blog post.
*/
public function customer()
{
return $this->belongsTo('App\Customer', 'CustomerID', 'ID');
}
}
Spend some time in the Eloquent Relationships Documentation. It's really important to understand them if you want to be a Laravel developer.
In order to display the relationship in the CRUD, you can then use Backpack's select column type to display it in the table view and select or select2 field types to display it in the add/edit views. Read the CRUD Example Entity to better understand how that works.
First of all when you are creating migrations for both tables, table which contain Foreign Key (FK) must have field like this:
public function up(){
$table->increments('id');
$table->integer('customerID')->unsigned();
}
After that you are need to call next command into console
php artisan migrate
Next is going next commands:
php arisan backpack:crud customers
php arisan backpack:crud transactions
After that you need to define functions in models which returns values from other tables. Customer models need to have next function
public function transactions(){
return $this->hasMany('Transaction');
}
Transaction model must have next function
public function customer() {
return $this->belongsTo('Customer');
}
Next you must add CRUD field in Customer controller to display
transactions in select box.
$this->crud->addField([
'label' => 'Transactions', // Label for HTML form field
'type' => 'select2', // HTML element which displaying transactions
'name' => 'customerID', // Table column which is FK for Customer table
'entity'=> 'customer', // Function (method) in Customer model which return transactions
'attribute' => 'ID', // Column which user see in select box
'model' => 'Transaction' // Model which contain FK
]);
Hope this helps :)
After you built onetomany relationship with transaction, you can get the results.
$customer=Customer::where(['id'=>'123456'])->with('transaction')
->first();
print_r($customer->Name); // gives the customer name
foreach($customer->transaction as $cid)
{
print_r($cid->CustomerID); // gives the customer id
}
Laravel Relationships Documentation is always helpful. Go through it.

Symfony2 - how to insert values into two different tables with one form in doctrine?

I'm sure that this question has been asked before but I'm finding it difficult to find a solution that pertains to my exact issue so I am hoping someone can help me out.
Basically, I have two tables, one called "pet" and one called "customer_pet". These two tables are linked so that I can assign pets to specific people (customers). However I find that if I add the customer id into the form (which is not a field in the pet table) that it does not persist anything. I'm having difficulties with the different types of table and column association in doctrine I think.
In my Pet entity, I have the following:
/**
* #var integer
*
* #ORM\ManyToMany(targetEntity="AppBundle\Entity\Oc49Customer", inversedBy="pet", cascade={"persist"})
* #ORM\JoinTable(name="customer_pet",
* joinColumns={
* #ORM\JoinColumn(name="customer_id", referencedColumnName="id")
* },
* inverseJoinColumns={
* #ORM\JoinColumn(name="pet_id", referencedColumnName="id")
* }
* )
*/
private $customer_id;
But I am unsure how to map it back in my customer_pet entity. The customer_pet table simply contains pet_id and customer_id. The pet_id is generated when a pet is added and the customer_id is passed through the form in a hidden field.
I'm not overly familiar with table associations in doctrine so any help is appreciated. If anyone needs any other code snippets please ask.
Here is my addPet() method:
/**
* Add pet
*
* #param \AppBundle\Entity\Pet $pet
* #return Customer
*/
public function addPet(\AppBundle\Entity\Pet $pet)
{
$this->pet[] = $pet;
return $this;
}
Thank you in advance
Michael
1)Declare all the tables.
2)Create the form.
3)Send to multiple tables.
4)Persist data.
use AppBundle\Entity\site;
use AppBundle\Entity\nba;
1)Declare all the tables.
$site = new site;
$nba = new nba;
2)Create form
$form = $this->createFormBuilder($site)
->add('site_id', IntegerType::class, array('attr' => array('class' => 'form-control', 'style' => 'margin-bottom:15px')))
->add('category', ChoiceType::class, array('attr' => array('class' => 'form-control', 'style' => 'margin-bottom:15px'), 'choices' => $output))
->add('team', ChoiceType::class, array('attr' => array('class' => 'form-control', 'style' => 'margin-bottom:15px'), 'choices' => $nbat))
3)Insert into multiple tables.
$site_id = $form['site_id']->getData();
$category = $form['category']->getData();
$team = $form['team']->getData();
$site->setSiteId($site_id);
$site->setCategory($category);
$nba->setWinner($team);
4)Persist data
$em = $this->getDoctrine()->getManager();
$em->persist($site);
$em->persist($nba);
$em->flush();
You only need to configure the two entities: Pet and Customer. The other table - customer_pet - is a so-called join-table. Doctrine does not need an Entity mapping for this table. You need to configure an association mapping to make Doctrine aware of the relationship between Customers and Pets. In this specific case you can use the Many-To-Many, Bidirectional association, meaning one Customer can have many Pets, and one Pet can have many Customers.
More or less:
in Customer entity
/**
* #ORM\ManyToMany(targetEntity="Pet", inversedBy="customers")
* #ORM\JoinTable(name="customer_pet")
**/
private $pets;
public function __construct() {
$this->pets = new \Doctrine\Common\Collections\ArrayCollection();
}
in Pet entity:
/**
* #ORM\ManyToMany(targetEntity="Customer", mappedBy="pets")
**/
private $customers;
public function __construct() {
$this->customers = new \Doctrine\Common\Collections\ArrayCollection();
}
Then your createPetAndSetCustomerAction could look like this:
public function createPetAndSetCustomerAction($idCustomer)
{
$pet = new Pet();
$pet ->setName('Fluffy');
$customer = $this->getDoctrine()
->getRepository('MyBundle:Customer')
->find($idCustomer);
$pet->getCustomers()->add($customer);
$em = $this->getDoctrine()->getManager();
$em->persist($pet);
$em->flush();
return new Response('Created pet ' . $pet->getName() . ' and set customer ' . $customer->getDescription());
}
We're speaking about some basic concepts here and I really recommend you read the Databases and Doctrine chapter of the Symfony Book two or three times to fully understand these concepts.