Implement Unary Many-to-Many Relation with Eloquent models [Laravel] - database

How I can implement Unary Many-to-Many Relation with Eloquent models
Ex: If there's a relation that User can send request friend to one or more user
I know that I have to create new model like user-request-user for example,, Primary Keys for new model will be [user1_id , user2_id] that's what I think
but how to implement this relation then ..

yes dear it is possible in just like ordinary many to many relationship but with a little difference.
first step for many to many relation is create pivot table so you create migration for pivot table. pivot table is belongs to two table in normal many to many relation but this pivot table is belongs to a single table.if you create pivot table name "friend_request_user", so here is the migration
public function up()
{
Schema::create('friend_request_user', function(Blueprint $table)
{
$table->integer('user_id')->unsigned()->index();
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->integer('request_user_id')->unsigned()->index();
$table->foreign('request_user_id')->references('id')->on('users')->onDelete('cascade');
$table->timestamps();
});
}
now you should have two models one "User" and other as you already have "user-request-user". both models should point to same table which is "users". by default User model is point to users table but you write a property $table for pointing "users" table for "user-request-user" model so
protected $table = 'users';
in User model you just write a simple method as write in any other many to many relation... so
public function request(){
return $this->belongsToMany('App\user-request-user', 'friend_request_user','user_id', 'request_user_id');
}
first parameter of "belongsToMany" function is relational model, 2nd is pivot table name, 3rd is foreign key and 4th is other key use in pivot table. we write these parameters just because not follows the laravel syntax in this case. this is all, now just call this function like
Auth::user()->request;
you may also like to use opposite of function which can write on other model "user-request-user" but this is just for your need.
public function nameOfFunction(){
return $this->belongsToMany('App\User', 'friend_request_user', 'request_user_id', 'user_id');
}

Related

Larave database model relation between itself

I have some doubts about how to design a model whith a relation bewteen itself.
In my case, I have a users table with id and coach_id. All users has an id (obviously) but users with role Runner has also coach_id referred to an user with role Coach.
First step is how to create the key on laravel table migration and then, how to add correct relation in User model.
First, make sure that coach_id can be NULL:
$table->unsignedInteger('coach_id')->nullable();
Use unsignedBigInteger if model id use big integers.
Then define a foreign key:
$table->foreign('coach_id')
->references('id')
->on('users')
->onDelete('set null');
Use set null instead of cascade because you don't want delete related users when coach is deleted.
And set up one-to-many relation in User model:
public function coach() {
return $this->belongsTo(self::class);
}
From Laravel > 7 you can use shortcut in migration:
$table->foreignId('coach_id')
->nullable()
->constrained('users')
->onDelete('set null');

laravel select specific columns but with relationships

I'm currently optimizing my application and one thing is selecting only the things from database which are really needed.
For example when I'm retrieving a User object I normally do it like this:
$user = User::where($attribute, '=', $value)->first();
This code will give me back a full user object with all the columns. My users table is pretty big, so I thought it is a good idea to only select the columns which I need like this:
$user = User::where($attribute, '=', $value)->first($columns);
This is also working as expected. But my problem is, as soon as I specify columns, the relationships of the $user variable are not working anymore, because it is no longer an object.
My question: Is it possible to select only a few columns but still be able to use relations like
$user->parents
Thanks!
Try This
$user = User::where($attribute, '=', $value)->select($columns)->first();
Just add all foreign keys for the relationships you want to get. For example, if you want to use parent() relationship, just add the key to the $columns:
array_push($columns, 'parent_id');
After that, you'll be able to use the parent() relationship.
Yes it is possible to load relationship with selected columns but for that you have to select foreign keys of that relationship table.
So here you also have to select the column of user table which is foreign key in parents table and also mention relationship using with(),
For example if you have user_id column in parents table as foreign key then you have to select id column of user while you are mentioning columns array in first() method as below:
$user = User::with('parents')->where($attribute, $value)->first(['id','email','image']); // also select 'id' for foreign key to load relationship
After using above code you can get relationship of parents as: $user->parents, and don't forget to put relationship in your User Model.
If you have foreign key on user table as parent_id which belongs to parents table then you have to select that parent_id column as below code:
$user = User::with('parents')->where($attribute, $value)->first(['parent_id','email','image']);

Can I create a separate table for a single Collection property using Entity Framework code first?

I have a class Foo with an ICollection<string>. To be able to store this through Entity Framework, I have created a class Bar with an Id and Value property. Entity Framework creates a table for Bar with a foreign key column to Foo. This works well.
The problem is that I have a whole bunch of classes with such a ICollection<string>. I converted them all to ICollection<Bar>. The result however is that the Foo table now contains a foreign key column for every class that has an ICollection<Bar> (10+).
While I understand that it's necessary to do this to have those relationships work in the database, the database diagram doesn't get more intuitive this way.
I was thinking that, like in a many to many relationship, I would like to have a table in between each of those relationships. For example,
a table Foo_Bar with two columns: Foo_Id and Bar_Id for the relationship between Foo and Bar and another table Baz_Bar with Baz_Id and Bar_Id.
To achieve this, I can create a sub class of Bar (e.g. FooBar) for every relationship; change the collection to use those (e.g. ICollection<FooBar>); and let EF create the database using the table per type (e.g. by decorating FooBar with [Table("Foo_Bar")]) approach for these types. But I would like to prevent having to create all these empty classes.
I wonder if it is possible to somehow specify this behaviour just based on the property. Something like this:
public class Foo
{
[Table("Foo_Bar")]
public ICollection<Bar> Bars { get; set; }
}
On a side note: If this approach is a bad idea in the first place, don't hesitate to let me know :).
to summarize comments:
what you want (i.e.: 5 tables) is a many to many relation for Entity Framework.
By conventions you get it by setting a collection on both entities
Foo {
ICollection<Bar> Bars
}
Foo {
ICollection<Foo> Foos
}
if you don't want the reverse collections (Foos) then you have to setup the relation by the fluent API.
modelBuilder.Entity<Foo>.HasMany(x => x.Bars).WithMany()
AFAIK there is no annotation allowing to reach this last result by using the Annotations.
You then have to handle by hand the unicity of Foo for a Bar. A solution may be a unique constraint on the Bar Key of the join table created by EF.

Many-to-Many relationship in Zend 2 Framework

I use the Zend 2 Framework to build my web application. I implemented my database table models by this tutorial: http://framework.zend.com/manual/2.1/en/user-guide/database-and-models.html
I have a many-to-many relationship between two models in my database. To get data from them I googled and found this link: http://mattmccormick.ca/2010/04/24/how-to-easily-create-models-and-table-relationships-in-zend-framework/
The problem is that all the table models extends from Zend_Db_Table_Abstract in the example. I don't know how to get data from the models.
I have a table containing votings, every voting has a unique hash id. Every voting also has tags. Therefore I defined a table tags with all the tags available and a voting_tag_map where all many-to-many relationships are mapped.
What I have tried so far is the following, that's code from my VotingTable class:
public function getTagsByVoting($votingHash){
$select = $this->tableGateway->getSql()->select();
$select->from(array('v' => 'voting'))
->join('voting_tag_map', 'v.voting_id=voting_tag_map.voting_id')
->join('tags', 'voting_tag_map.tag_id=tags.tag_id');
$resultSet = $this->tableGateway->selectWith($select);
return $resultSet;
}
It says then:
Since this object was created with a table and/or schema in the constructor, it is read only.
Thats because of the from() method. If I delete the from() method, it says:
Statement could not be executed
Can anyone help me please?
Since this object was created with a table and/or schema in the constructor, it is read only.
This error is because you are trying to set the table name in the from clause, but it's already been set in the contructor of the TableGateway, and you can't change it once set.
If you really need to do this then you can extens AbstractTableGateway yourself then you won't have to add a string tablename to the contructor, but you don't really need to use an alias on your main table...
The SQL error you get when you comment out the from() method will be due to your referencing the votes table as it's alias 'v' in your join, when you are not using the alias v, try changing it to 'voting.XXX' from 'v.XXX'

Laravel relationships in migrations?

I know you can define table relationships fairly easy with $this->belongs_to(), $this->has_many() etc, but what i don't understand is how the relationship table is created; the table that binds the two tables together (i forgot what the term is called).
Let's say i'm creating a users table. I want that user to belong to a certain "Role". There are multiple roles, and every role can have multiple users. I will need to also create a roles table for that. So far, so good.
But after reading the documentation, it says i should add the $this->belongs_to() in the model, not the migration itself. When, and how is the relationship table created? If i create the roles and users tables, and add $this->belongs_to('roles') to the users model, and $this->has_many('users') to the roles model, will the middle table be created automatically?
When creating a migration you can specify foreign keys on your tables,
i.e.
public function up()
{
Schema::table('roles', function(Blueprint $table) {
$table->increments('id');
$table->integer('user_id')->unsigned();
//rest of fields then...
$table->foreign('user_id')->references('id')->on('users');
});
}
This will create a foreign key on the user_id column on the roles table.
The benefits of foreign keys is that when an update or delete is made the foreign key table will be automatically updated or "cascaded" great description found here
As described on the Laravel documentation you could also specify your cascading on update using the following syntax
$table->foreign('user_id')
->references('id')->on('users')
->onDelete('cascade');
I would do a bad job of trying to explain it better than the documentation does so please have a read through the "Relationships" section of the Eloquent ORM documentation to see how its done.
It looks like a few of the initial questions were never answered, i.e. "When, and how is the relationship table created" & "will the middle table be created automatically":
As far as I am aware, these tables need to be created manually. So create the migration file like so:
Laravel 5
php artisan make:migration create_role_user_table
Laravel 4
php artisan migrate:make create_role_user_table
Note that the names are singular, and are presented in alphabetical order.
Then in the migration something like:
public function up()
{
Schema::create('role_user', function($table) {
$table->increments('id');
$table->integer('role_id');
$table->integer('user_id');
$table->timestamps();
});
}
Hope that helps. I'm not sure if the timestamps are needed in Pivot Tables or not, so please experiment.
Though its an old Post, I though I can contribute something updated. For Laravel5, Jeffrey Way has developed a package Laravel5 Generators-extended which enhance the generator capability of php artisan for
make:migration:schema
make:migration:pivot
make:seed
For many-to-many relation between users and role, you can just use
php artisan make:migration:pivot users role
and it will generate the required migration class. You don't need to code manually for this.
As far as I know, no relationship table will be created. What you will need to do is have a role_id on your users table, so that when you create a user, the ID of the role will be stored there. This will enable you do select all users where role_id == '1' or whatever it may be.
For example:
$admins = User::where('role_id', '=', 1);
Where on the ROLES table the record with ID='1' is admin.
So again to answer your question, no relationship table is created, instead the relationship exists within your two tables in the form of a role_id column for each user. Out of interest, are you using foreign keys?
If you want to have a relationships table you could create one called user_roles or something and store the role_id and user_id in there, however I think its easier to use the above method as then you can use all the Laravel/Eloquent goodness.
Hope this helps :)
This video helped me.
https://laracasts.com/series/laravel-5-fundamentals/episodes/14
What was surprising for me was that only one side of the relationship needs pointer_id in migration table, not both. For example, if we have Author with many Articles, we only add
$table->integer('author_id')
to article migration and thats it.
I know this is an old post but as I had the same question in mind. I've found the solution in the Laravel manual (5.0) where it is described that for this particular many-to-many relationship you can create the table manually and then declare the type of relationship into Model in this way:
return $this -> belongsToMany('App\<Model>', '<table_created_manually>');
or if you want to use specific associated keys:
return $this -> belongsToMany('App\<Model>', '<rel_table1_table2>' '<table1>_id', '<table2>_id');
Hope this can help.

Resources