Laravel 4.2 Eloquent Relationship with custom table name - php

Im trying to access url property on files table by $post->file->url, but i'm getting "Trying to get property of non-object" error. My table and model is different because i can't use File as model name. is there something missing? I hope someone come with solution. here's my tables:
- posts:
[PK] id
title
[FK] featured_image
- files:
[PK] id
title
url
my model:
class TheFile extends \Eloquent
{
protected $table = 'files';
public function post() {
return $this->belongsTo('Post');
}
}
class Post extends \Eloquent
{
protected $table = 'posts';
public function file() {
return $this->hasOne('TheFile', 'id', 'featured_image');
}
}
thanks in advance.

Maybe I'm wrong but as I see it, you actually have the relationship the wrong way around here. If table X has one table Y then the FK field is on Y and related to the PK on X. But you have it the other way around.
As such you need to do one of two things:
Change your database to put post_id on files rather than having featured_image (points as file`.`id) on posts
Change your relationships to match your database structure:
class TheFile extends \Eloquent
{
protected $table = 'files';
public function post() {
return $this->hasOne('Post');
}
}
class Post extends \Eloquent
{
protected $table = 'posts';
public function file() {
return $this->belongsTo('TheFile');
}
}
Obviously with your various field changes too if you aren't going to change the tables.
The basic rule of thumb is that if a table has the FK it's the 'belongs to' table. The other table is either 'has one' or 'has many'. The slight exception to this rule is obviously 'belongs to many' where a table can relate to another table where neither has an FK - but even that's a specialised version of the same rule - X 'has many' X_Ys and Y 'has many' X_Ys and X_Y belongs to X and X_Y belongs to Y. So it's just syntactic sugar really.

I changed my table name to medias, and my model to Media. Then put these code into Post model . It's works. The name of tables, model and method must be similar.
public function media() {
return $this->belongsTo('Media', 'featured_image', 'id');
}

Related

How to join two tables with a pivot table using Laravel?

I have these three tables:
tbl_lista_contactabilidad tbl_equipo_postventaatc users
------------------------- ----------------------- -----
id id id
usuarios_id asesor_id name
tbl_lista_contactabilidad.usuarios_id should be related with tbl_equipo_postventaatc.asesor_id. asesor_id should be the "pivot" between tbl_lista_contactabilidad.usuarios_id and users.id to make the relation.
I want to make this relation so I tried to do this relation in this way (I will put only the relation of the model)
Tbl_Lista_Contactabilidad (Model 1)
public function postventaatc(){
return $this->belongsTo('App\Models\Tbl_EquipoPostventaatc','usuarios_id');
}
Tbl_Equipo_Postventaatc (Model 2) -> This should be the pivot model
public function contactabilidad(){
return $this->hasMany('App\Models\Tbl_Lista_Contactabilidad','usuarios_id');
}
public function user(){
return $this->belongsTo('App\Models\User','asesor_id');
}
User (Model 3)
public function postventaatc(){
return $this->hasMany('App\Models\Tbl_Lista_Postventaatc','asesor_id');
}
EXAMPLE:
As you see in the image... if I relate usuarios_id with users directly I will get another name and I don't want that... I want the relation just like in the image
A pivot table is a structure used to join two separate models together with a single relationship. This is called a many-to-many relationship in Eloquent.
From what you've described, this is not the case here. Rather, it looks like a has-many-through relationship.
If I'm understanding correctly, your relationships should look like this:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Tbl_Lista_Contactabilidad extends Model {
protected $table = 'tbl_lista_contactabilidad';
public function postventaatc() {
return $this->belongsTo(Tbl_EquipoPostventaatc::class, 'usuarios_id');
}
}
class Tbl_EquipoPostventaatc extends Model {
protected $table = 'tbl_equipo_postventaatc';
public function contactabilidad() {
return $this->hasMany(Tbl_Lista_Contactabilidad::class, 'usuarios_id');
}
}
class User extends Model {
public function postventaatc() {
return $this->belongsTo(Tbl_EquipoPostventaatc::class, 'asesor_id');
}
public function contactabilidad() {
return $this->hasManyThrough(Tbl_Lista_Contactabilidad::class, Tbl_EquipoPostventaatc::class, 'asesor_id', 'usuarios_id');
}
}
Obviously this is easier for a native English speaker, but I cannot stress how much easier this would be if you were following the Laravel rules around naming your models, tables, and columns. Why does usuarios_id column relate to a table called tbl_equipo_postventaatc? Why use asesor_id instead of user_id? 🤷🏽‍♂️ Those names have nothing to do with each other, and make it hard to figure out what is going on.

Add field to an Eloquent model

So I have two Laravel/Eloquent models, and I want to add one more field to one of them.
Model 'Car' gets data from table 'cars' and has fields 'id', 'model', 'color' and 'price'. Model 'Person' has fields 'id', 'name' and 'car_id', which is foreign key from 'cars' table. I want model 'Person' to have a field named 'car', which would contain car model from 'Car' model, depending on existing car_id. I've tried something like:
use App\Models\Car;
class Person extends Model {
protected $car = array(Car::find($this->car_id));
}
But that was unsuccessful (errors like 'syntax error, unexpected '(', expecting ')''). What could be the solution? Thanks!
You need to define One-To-Many relationship first. Then get car model for the person:
$carModel = Person::find($personId)->car->model;
Take a look at Eloquent Relationships. What you are trying to do is to create a relationship between Car and Person models. It is up to you if a person can own one or multiple cars. I am suggesting you to let a person have multiple cars.
So, the Person model should know that it has multiple cars:
class Person extends Model
{
public function cars()
{
return $this->hasMany(App\Car::class);
}
}
A car belongs to a person, so the model should know that:
class Car extends Model
{
public function person()
{
return $this->belongsTo(App\Person::class);
}
}
Of course, when creating the tables you should add the field person_id to the CARS table.
Well, what I needed was:
protected $appends = ['car'];
public function getTypeAttribute($car)
{
return Car::find($this->car_id)->model;
}
It was all about serialization and 'protected $appends', thank you all :)
That's not how its done.
The person can have a car (or many). Let's suppose that every person have one car in your database, your car table should have a nullable person_id column, and add this to your User model
public function car() {
return $this->hasOne('App\Role');
}
Now you can get the person and the his car information's like this
User::where('id',$id)->with('car')->get();
I hope you get the point here

Laravel Eloquent Join

I'm fairly new with Laravel. I'm still trying to learn it. My question is:
I have 3 tables named
games
game_options
game_platforms
I have 3 Models for those tables
Game Model
class Game extends Eloquent
{
protected $table = 'games';
public function platforms()
{
return $this->hasManyThrough('GamePlatform','GameOptions','id','game_id');
}
}
GamePlatform Model
class GamePlatform extends Eloquent
{
protected $table = 'game_platform';
}
GameOption Model
class GameOptions extends Eloquent
{
protected $table = 'game_options';
}
So when I do
$game = Game::find(1)->platforms;
It only shows,
{"id":1,"platform_id":20,"game_id":1}
{"id":1,"platform_id":21,"game_id":1}
{"id":1,"platform_id":22,"game_id":1}
{"id":1,"platform_id":23,"game_id":1}
{"id":1,"platform_id":24,"game_id":1}
But I need game name and platform names with those ID's. The thing is, I want to do this with eloquent only. I could go with "DB" or oldschool SQL but I want to learn if this way is possible or not.
Also I'm looking for better documentation/books for laravel. Most of what I read were only introduce laravel or far too advanced for me.
I left a comment earlier about this but now I'm pretty sure it's the answer you're looking for: you should use belongsToMany rather than hasManyThrough. So first, might I suggest you rename your tables and models to follow Laravel's conventions (plural snake_case table names, singular snake_case alphabetical order pivot table names, singular StudlyCaps model names), that way you'll have the following situation:
Tables:
games
id
name
game_option
id
game_id
option_id
options
id
option
name
Now you can rewrite your models to conform to the new structure, and use a belongsToMany relationship too:
class Game extends Eloquent
{
public function platforms()
{
return $this->belongsToMany('Option');
}
}
class Option extends Eloquent
{
public function platforms()
{
return $this->belongsToMany('Game');
}
}
Note: you don't have to model the pivot table (game_option) unless you store extra data on the pivot.
Now you should be good to get all options for a given game:
$options = Game::find(1)->options;
Or if you need to get all platforms (though I am trying to infer meaning of your code here regarding options and platforms):
$platforms = Game::find(1)->options()->whereOption('platform')->get();
you can use the with method with eloquent
$game = Game::where('id',1)->with('platforms')->get();
Should return you the game and platforms
For documentation I would first start with the documentation provided (find it to be about 50% complete) and with the api everything else is covered
You would have to model your tables like:
**games**
id
name
**game_options**
id
game_id
name
**game_platform**
id
game_options_id
platform_id /* which i assume you get from a platform master table */
Then in your Game Class:
class Game extends Eloquent
{
protected $table = 'games';
public function platforms()
{
return $this->hasManyThrough('GamePlatform','GameOptions','game_id','game_options_id');
}
}
Now, this would be assuming that Game Platform belongs to Games through Game Options.

laravel4 one to one relationship can not load the relationship

I have two tables like this:
users
id email
1 abc#ibm.com
2 abc#hp.com
3 abc#google.com
grp_members
grp_id user_id
1 2
2 2
13 1
13 3
2.My model
There, one group member must be a user, so its a one to one relationship just for GroupMember.
Users model about table users
class Users extends Eloquent {
protected $table = "users";
}
GroupMember model about table group_members
class GroupMember extends BaseModel{
protected $table = "grp_members";
public function user(){
return $this -> hasOne('Users', 'id');
}
}
3.In my service GroupApi.php, if I have a query like this
class GroupApi {
public function queryGroupMembers(){
$result = GroupMember::all();
var_dump(get_class(GroupMember::all())); //CODE ONE
foreach($result as $ret){
var_dump(get_class($ret)); //CODE TWO
var_dump(get_class($ret -> user)); //CODE THREE
}
}
}
As you see, when I invoke var_dump(get_class(GroupMember::all())) at CODE ONE,
I got this
.string(39) "Illuminate\Database\Eloquent\Collection"
Yes, that's what I want.
Now, at CODE TWO, it prints
string(11) "GroupMember"
Yes, also correct object, but when the code goes to CODE THREE, it give me a surprise,
the outputs like this:
string(8) "GroupApi"
Why its an instance of GroupApi, but not the instance of Users or GroupMember
And in that case , how can I invoke $ret -> user?
Any idea is welcome, thanks very much.
There are some things I'm not sure I understand in your implementation but something that could be causing you troubles is not using the conventions Laravel asks for, that being using User as the model name and users (model + s) as the table name.
Also, i would guess $g1 is not a GroupMember object as you suggest, could you getClass() it and comfirm?
Ok, I guess you have 3 tables:
users; grp_members; groups
and a many-to-many relationship between users and groups using the table grp_members as pivot table.
In this case, try this:
Class User:
class User extends Eloquent {
public function groups()
{
return $this->belongsToMany('Group', 'grp_members');
}
}
Class Group:
class Group extends Eloquent {
public function users()
{
return $this->belongsToMany('User','grp_members');
}
}
And also change the field name in the table 'grp_members' from grp_id to group_id, to follow eloquent conventions.

Eloquent with multiple relations

I'm new to Laravel and ORMs in general, so this is probably a very basic concept that I'm missing. I have three tables that I'm trying to define a relation with using Laravel 4's Eloquent ORM. Here's the slimmed-down table definitions:
stores
id (PK)
name
postal_codes
id (PK)
postal_code
city
state
country
locations
id (PK)
store_id (FK => stores.id)
postal_code_id (FK => postal_codes.id)
*additional location-specific fields such as address, phone #, etc
The stores table has a one to many relationship with the locations table, so I can use $this->hasMany("Location") in the Stores model, and $this->belongsTo("Store") in the Location model.
My question is, how do I define the relation between locations and postal_codes in their respective models? The locations table has a many-to-one relationship with the postal_codes table. Ideally I want to be able to do something like this: $store->locations()->first()->city. Is this possible?
Aren't you looking for something like:
class Locations
{
public function city()
{
return $this->belongsTo('PostalCode');
}
}
So now you can call $store->locations()->first()->city. This will return a PostalCode model, if you want to return just the city:
public function getCity()
{
return $this->city()->city;
}
And then you call $store->locations()->first()->getCity().
You could go further and create a __get() magic method so it calls everything dynamically.
It sounds like you have a many-to-many relationship between Stores and Postal_Codes. This would be demonstrated this way in Laravel:
class Store extends Eloquent {
public function postal_codes() {
$this->belongsToMany('Postal_Code', 'location');
}
}
class Postal_Code extends Eloquent {
public function stores() {
$this->belongsToMany('Store', 'location');
}
}
For more info, try this link: Laravel Many-to-Many Relationships.
I believe you are looking for a polymorphic relation.
Modify your locations table to include id, imageable_id, imageable_type, and then whatever additional location information you need. The imageable_id field will contain the ID of whatever you are looking for in it's respective table and the imageable_type will be whatever the name of that model for that table is.
On your models...
Class Location extends Eloquent
{
public function imageable()
{
return $this->morphTo();
}
}
Class Store extends Eloquent
{
public function locations()
{
return $this->morphMany('Location','imageable');
}
}
Class PostalCode extends Eloquent
{
public $table = 'postal_codes';
public function locations()
{
return $this->morphMany('Location','imageable');
}
}
And now, it's possible to retrieve all of the locations for the stores or postal codes with something like
$store = Store::find(1);
foreach($store->locations as $location)
{
//
echo $location->city;
}
$postalCode = PostalCode::find(1);
foreach($postalCode->locations as $location)
{
//
echo $location->city;
}

Categories