I have 2 tables, estimates and models.
There's a 1-to-1 relation between the two.
I want to move model names from the models table to the estimates table. That will be done with a script that I will have to write myself.
The way this database was set up was wrong, for many reasons I don't need to specify here.
The models table has only 2 columns - id and name.
I access this relation in a lot of controllers, and views all over my app :
$estimate->model_info->name
So I would keep both the models table (with no records) and the Model.php model, keep the old code in the controllers and views, but the new code of accessing model names would be just :
$estimate->name
In the Estimate.php model I have this relation :
public function model_info() {
return $this->hasOne('App\Models\Model', 'id', 'model_id');
}
How can I just change this relation into a mutator, so the old way of accessing model names and the new way would work at the same time?
I've tried the withDefault() callback method with no luck, it returns an empty value :
public function model_info() {
return $this->hasOne('App\Models\Model', 'id', 'model_id')
->withDefault([
'name' => $this->attribute->name
]);
}
Do I have to update my code in all controllers and views or if there's an easier way to do this?
Related
In my app, you can create lists of roles that are attached to contacts. So you can assign the contact "Bob" the roles of "Gardener" and "Pet Sitter". Then you can create the list "People" and add "Gardener (Bob)" and "Pet Sitter (Bob)" to it.
I have the following tables:
contacts
id
name
roles
id
name
contact_role (pivot)
id
contact_id
role_id
lists
id
name
contact_role_list (pivot)
id
contact_role_id
list_id
Everything was working smoothly until the second pivot table linked to the first pivot table. My pivot tables are (currently) not having any models so I'm not sure if there is a built-in feature to tackle this in Laravel or if I need to think differently.
I currently have this in my List model:
public function list_roles(): BelongsToMany
{
return $this->belongsToMany(XYZ::class, 'contact_role_list', 'list_id', 'contact_role_id');
}
Is this even close? What do I put where it says XYZ::class?
Ok, so the below is doing what I want, but is there an even better way to do it? The key to solving my problem was to create a Model for ContactRole and changing extends Model to extends Pivot.
I placed this in my List Model:
public function list_roles(): BelongsToMany
{
return $this->belongsToMany(ContactRole::class, 'contact_role_list', 'list_id', 'contact_role_id');
}
And this in my ContactRole Model:
public function contact(): BelongsTo
{
return $this->belongsTo(Contact::class);
}
Now I could reach the contact data by using something like this: List::first()->contact_roles->first()->contact
Any way to use with, pivot or similar to tidy this up even more? Thanks!
I like to approach these issues in terms of Models rather than pivots. I think many new Developers in Laravel get over obsessed with what's going on in the Database which is fine, but theres a lot of Magic going on so you can write very simple code that does a lot of Heavy lifting, so that being said if I fully understand your problem
You have a Contacts Model
This model can have many roles
so in your contacts Model you need a role relationship
public function roles()
{
return $this->belongsToMany(Roles::class);
}
next of course you have a role Model (pun intended)
your each role can have many list
public function lists()
{
return $this->hasMany(List::class)
}
then the idea is now that you have roles on contacts and lists on roles you should be able to have many lists through contact
public function lists()
{
return $this->hasManyThrough(List::class, Role::class);
}
I've done similar things before and for your description it seems like that's the approach you might need to take.
I have 2 simple models. First, one is called Builds and the second one is called SlotOptions. Each build can have like 5 assigned slots.
class BuildDB extends Model
And has 5 such relations slot1-5 and id changes to slot1-5_id
public function slot1()
{
return $this->hasOne('\App\SlotOptions', 'id', 'slot1_id');
}
In the controller I call it such way;
BuildDB::with([ 'slot1', 'slot2', 'slot3', 'slot4', 'slot5'])->find(5);
\App\SlotOptions model doesn't contain any extra coding.
This generates 5 "same" queries. - atm the eager loading would work if I get a list of builds and each slot would have whereIn clause, is it possible to have it a one big wherein the clause, or does it require to change the DB schema.
It's not possible to optimize eager loading in this case.
I recommend that you change your database schema to a many-to-many relationship.
This design is more flexible, it allows you to easily add more slots in the future.
Create a pivot table named build_slot_option with these columns: build_id, slot_option_id
Add an additional column if you want to number/order the slots.
Then define a BelongsToMany relationship:
class BuildDB extends Model
{
public function slots()
{
return $this->belongsToMany(
SlotOptions::class, 'build_slot_option', 'build_id', 'slot_option_id'
);
}
}
BuildDB::with('slots')->find(5);
I have a Laravel model called "Area" which contains "Elements".
Elements can be different Models (in this case a FreetextElement and a CheckboxElement). The whole thing is hooked up with a polymorphic pivot table,
which contains the area_id, the element_id and the element_type.
The basic relationship works fine.
If I for example say:
$area->freetextElements
Then I get all the freetextElements that are attached to that particular area.
My issue is that I'd like a relationship function, which gets all the elements that are attached to the area, regardless of their model.
Here are the areas relations:
public function freetextElements()
{
return $this->morphedByMany(ElementFreetext::class, 'element', 'coaching_element_area_element');
}
public function checkboxElements()
{
return $this->morphedByMany(ElementCheckbox::class, 'element', 'coaching_element_area_element');
}
//find a better solution for this
public function elements()
{
return array_merge( $this->freetextElements->all(), $this->checkboxElements->all());
}
The last function "elements" is just to illustrate what I'm trying to achieve.
Any suggestions? Thanks in advance.
Best Regards
So I have found a solution to this issue. It's not the cleanest solution.
So I'm still open to any additional feedback, but I thought I leave this here for other people.
I simply created a model for the pivot table entries. Area->Elements is the relationship to the pivot table entries and That pivot table model is related to the individual elements via it's own relation. Now I can chain the relation by saying: Area->Elements->Element. It's not optimal, but it gets the job done.
Is it possible to seed related tables using the following in Laravel 5?
php artisan db:seed
I have two tables
users
id
first name
projects
id
name
and a pivot table
project_user
project_id
user_id
I would like to create a number of users, a number of projects and then relate the users and their respective projects.
Seeding the users and projects isn't a problem but I am not sure how to handle the pivot table.
Is it possible?
Of course you can. If you are using Eloquent, you can simply work with normal relations (maybe the easiest way). Or if you use the SQL builder directly, you can feed the table just as normal, but you need to stick to your foreign key rules.
Just give in a try and you'll see. But make sure you import classes you use.
Adding a relation between two models is easy, but there are some differences between the common relation types (and he perspective): one-to-many, many-to-one and many-to-many.
One-to-Many and Many-to-One
Assumed that each of your project has a creator, an owner so-to-say, you could have a 1:n relation between User and Project.
public class User {
public function ownedProjects() {
return $this->hasMany('App\Project');
}
}
public class Project {
public function owner() {
return $this->belongsTo('App\User');
}
}
In this relation, you can either attach a Project to a User or tell the Project who his owner is.
// Attach a project to an user
$project = Project::create([]);
User::find($id)->ownedProjects()->save($project);
// There is also a function saveMany() for an array of projects
// Tell the project who his owner is
$project = Project::create([]);
$project->owner()->associate(User::find($id));
Many-to-Many
In your case, we need a Many-to-Many relation between Users and Projects. The syntax is a bit different, but the outcome quite straight forward. First we need a relation between the both models:
public class User {
public function projects() {
return $this->belongsToMany('App\Project');
}
}
public class Project {
public function users() {
return $this->belongsToMany('App\User');
}
}
Then we can query the relation just like that:
$project = Project::create([]);
User::find($id)->projects()->attach($project->id);
You can also attach a whole bunch of projects, do the same things from the other side, detach models or synchronize them, if you want to make sure that an exact amount (and only this amount) is in relation:
// Adds a relation for the user to projects with ids 1, 2, 4 and 6
User::find($id)->projects()->attach([1, 2, 4, 6]);
// Adds the users with ids 19 and 173 to this project
Project::find($id)->users()->attach([19, 173]);
// Removes the user 19 from the projects relations
Project::find($id)->users()->detach(19);
// Removes all relations between this user and projects that are
// not listed in the synchronization array and adds a relation
// to all projects where none exists yet
User::find($id)->projects()->sync([4, 7, 19, 6, 38]);
This is the normal syntax for Many-to-Many relations, but you can also attach models just like in a One-to-Many relation:
// Creation of project could also be done before and saved to a variable
User::find($id)->projects()->save(Project::create([]));
I have 4 controllers and one database. Each controller is associated with one table. I am not able to query in one controller if i have to access table of another controller. I get "table not found" error.
You need to define the relations between the tables, using the associations:
http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html
By adding the right colums to your tables (Foreign ID fields) and defining the model associations, you will be able to access all the fields from the related tables.
Your question is a little confusing to say the least. Are you having issues accessing different models inside different controllers or is this an association issue? In your controller, you can define what models your controller uses by setting $uses:
class UsersController extends AppController {
$uses = array('User', 'File');
public function index(){
$results = $this->File->find('all');
}
}