How can i get the related data via the model? - php

I want to simply have a loop which have a sub-loop with all of the images link to the project. project.id = images.model_key in my case.
So i was trying to do something which didn't work.
function index()
{
$projects = Project::all();
foreach($projects as $project)
{
echo "<pre>";
print_r($project->images);
echo "</pre>";
}
}
Im the project model.
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use App\ProjectCategoryProject;
use App\Models\Image;
class Project extends Model
{
public $fillable = ['id', 'title','description', 'home_page', 'display'];
public function categories()
{
return $this->hasMany('App\ProjectCategoryProject');
}
public function images()
{
return $this->hasMany('App\Models\Image');
}
...
So i guess i have to specify in the model that project.id = images.model_key but how ?
Error :
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'images.project_id' in 'where clause' (SQL: select * from `images` where `images`.`project_id` = 4 and `images`.`project_id` is not null)
Thanks, sorry i'm guetting confused.

By default Laravel tries to guess the column name from current model, so in a model Project it will presume the column for it's ids in other models to be project_id. You can however override this and explicitly specity the columns to use for relationship:
public function images()
{
// specify a foreign key to use
return $this->hasMany('App\Models\Image', 'model_key');
}
Or this if you wanna be fully explicit.
public function images()
{
// specify a foreign key to use
return $this->hasMany('App\Models\Image', 'model_key', 'id');
}
I would however strongly encourage you to abide by laravel "convention" for better readability and easier maintenance. If possible, just rename the column :).

Related

Laravel Eloquent getting data from relations

I have Task model. My Task model has some relationships and it currently looks like this:
class Task extends Model
{
use HasFactory;
public $timestamps = false;
public function city()
{
return $this->hasOne(City::class, 'id', 'city_id');
}
public function type()
{
return $this->hasOne(Type::class, 'id', 'type_id');
}
public function note()
{
return $this->hasOne(Note::class, 'id', 'note_id');
}
public function operator()
{
return $this->hasOne(User::class, 'id', 'operator_id');
}
}
Now, in my TasksController I need to get Tasks that match certain criteria, like this:
$tasks = Task::whereCityId($city->id)->whereTypeId($type->id)->get()->toArray();
The problem is that fields named city_id type_id note_id operator_id will get my integer values that they have.
Instead I would like to get certain value from a related Model.
For example:
operator_id should be replaced with username from User table that corresponds to the user id.
An obvious solution to this would be to simply use foreach loop, go through my results and get the data I need and simply create another array with the information replaced, but I am not sure if this is the best idea and perhaps there is something better.
You have to change in your code:
$this->hasOne(ClassName::class, 'id', 'foreign_key');
To
$this->belongsTo(ClassName::class, 'foreign_key', 'id');
because Task's id does not available as foreign key in these tables. These table's id present in task table as foreign key so you have to use belongsTo() relationship to tell script from where these id belongs.
Then access properties like this:
$tasks = Task::with("type", "city", "operator")
->whereCityId($city->id)->whereTypeId($type->id)->get();
foreach($tasks as $task){
echo $task->city->name;
}
first you should fix your relation:
public function city()
{
return $this->hasOne(City::class,'city_id','id');
}
and so one the same error, foreign key in argument order comes before the primary key.
after that you can use addSelect:
$tasks = Task::whereCityId($city->id)->whereTypeId($type->id)
->addSelect(['userName' => User::select('name')
->whereColumn('users.id', 'tasks.operator_id')
->limit(1)])->get()->toArray();
i think this will help better than what you ask.
$tasks = Task::whereCityId($city->id)
->whereTypeId($type->id)
->with('operator')
->get()->toArray();
with('operator') is ORM feature that make you collection to include its relation as collection property. In this case it will convert to array property.
you could access it from your foreach function as
#foreach($task as $key)
$key['operator']['username']
#endforeach
Have a nice day

Alternatives to writing joins with foreign keys in eloquent?

I'm using laravel-eloquent and want to return a collection that joins several tables. For now, I do this using the query builder join method, but I would like to stay within eloquent. I mean, I already defined all my relationships, why should I write joins with foreign keys all the time?
For example, if I have defined my models like this:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
public function comments()
{
return $this->hasMany('App\Comments');
}
}
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Comment extends Model
{
public function user()
{
return $this->belongsTo('App\User');
}
}
and want to return all the comments with the user names, for now I would write this:
DB::table('users')->select('users.name', 'comments.body')
->join('comments', 'users.id', '=', 'user_id')
->get();
I have tried writing
$users = new 'App\User';
$users->with('comments')
->select('name', 'comments.body');
but it didn't work. Do I need to define a new collection? I will end up with many, many collections if I do that...
Try:
$result = null;
$users = new 'App\User';
$records = $users->with('comments')->get();
if ($records->isNotEmpty()){
$result = $records->map(function($val,$key){
return ["name"=>$val->name, "comments" => $val->comments()->get(['body']);
})->values()->all();
}
dd($result);
I have not tested the codes yet. Please check and let me know if it works for you?

Database Relationships in Laravel

I have Author model that looks like this:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Author extends Model {
public $timestamps = false;
public function role()
{
return $this->hasOne('App\Role');
}
}
And Role model that looks like:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Role extends Model {
public $timestamps = false;
}
My AuthorController.php looks like:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Author;
class AuthorController extends Controller
{
public function index(){
$role = Author::find(5)->role->pareigos;
return view('authors', ['role' => $role]);
}
}
But I get error like:
"SQLSTATE[42S22]: Column not found: 1054 Unknown column
'roles.author_id' in 'where clause' (SQL: select * from roles where
roles.author_id = 5 and roles.author_id is not null limit 1)
Where does the author_id even come from?
I have two tables in database, first one is authors that has id,firstname,lastname,role_id. Second one is roles that has two rows - id and pareigos. So I use this command:
$role = Author::find(5)->role->pareigos;
To find Author by id (5) and check his role_id in roles table and return pareigos if the ID's matches.
Don't know if I have described the problem clearly - if not, just let me know I eill add more details.
Your relationship is setup incorrectly. The table that has the key pointing to another table, belongs to that other table.
class Author ...
{
public function role()
{
return $this->belongsTo(Role::class);
}
...
This will want to look for a role_id key on authors table. By default, unless you pass more arguments to override it, Laravel uses the calling function name to decide the name of the foreign key for belongsTo relationships. [ method is named role, so it knows to look for role_id ... methodname + _id ]

Eloquent - Having problems using eager loading on nested relationships

I'm trying to eager load nested relationships, but I'm having trouble returning the correct results.
Here are the models:
User.php
class User extends Model
{
public function universities()
{
return $this->hasMany('\StudentApp\Models\UserUniversity');
}
}
UserUniversity.php
class UserUniversity extends Model
{
protected $fillable = [ 'user_id', 'university_id', 'choice' ];
public function university()
{
return $this->hasOne('\StudentApp\Models\University');
}
}
University.php
class University extends Model
{
protected $table = 'university';
}
What I want to do is get a user by ID, fetch the users universities from the UserUniversity pivot table, and then fetch the name of that university from the University table.
I've tried the following to test if it works:
$user = User::with('universities')->find($this->jwtObject->uid);
return $response->withJson($user->universities[0]->university);
But I get the following error:
Column not found: 1054 Unknown column 'university.user_university_id' in 'where clause' (SQL: select * from `university` where `university`.`user_university_id` = 10 and `university`.`user_university_id` is not null limit 1) [] {"uid":"28c5a97"}
user.user_university_id is incorrect. That column doesn't exist and I'm not sure why it's trying to use that column.
What it should be using is user.university_id
How can I do this?
You should add foreign key and primary key in relation:
public function universities()
{
return $this->hasMany('\StudentApp\Models\University', 'university_id', 'id');
}
Correct nested eager loading syntax is:
User::with('universities.university')
Also, make sure you've using the correct foreign key in the university table:
user_university_id
Or define another key in the relationship:
public function university()
{
return $this->hasOne('\StudentApp\Models\University', 'another_foreign_key');
}

Laravel Eloquent Joins

I have below query in core php:
SELECT DISTINCT device_tocken FROM push_details JOIN users ON users.id=push_details.user_id
I have to integrate it in laravel 4
Application already have User extends Eloquent class
I created Push_details class as below
class Push_details extends Eloquent {
public $table = 'push_details';
public function User() {
return $this->hasMany('\User','id');
}
}
Table : users
Primary key : id
Table: push_details
Primary key: id
Foreign key: user_id belongsTo('users.id');
But i m not able to get expected result.
One more thing i didn't write anything in User's model yet.
Only way to join table is.. to join it, as Eloquent relations don't work using joins but separate queries with WHERE IN clauses. So this will do:
DB::table('push_details')
->select('device_tocken')
->distinct()
->join('users','users.id','=','push_details.user_id')
->get();
Above will return array of stdObject's so or if you need Eloquent Collection with Eloquent models as a result replace DB::table('push_details')->select... with PushDetails::select...
Now, correct your relations, as they are wrong:
// PushDetails model (as previously stated, I suggest renaming it to StudlyCase)
public function user() {
return $this->belongsTo('\User','user_id'); // user_id is may be omitted here
}
// User model
public function pushDetails() {
return $this->hasMany('\PushDetails','user_id'); // user_id is may be omitted here as well
}
In your User model, you need to link back to the PushDetails model, like so
class User extends Eloquent {
public function push_details() {
return $this->belongsTo('PushDetails');
}
}
Use CamelCase for Class names, because laravel has several functions, in which CamelCase are changed to snake_case
Change
public function User() {
return $this->hasMany('\User','id');
}
to
public function users() {
return $this->hasMany('User');
}
See the docs 'Eloquent ORM' for more...

Categories