How to improve Laravel code using with operator? - laravel

In my request to DB I use Laravel's models and function with like:
$user = User::with("city")->get();
Problem is that if to do the following in template:
{{$user->city()->name}}
It will work only then if user specified city, so then value exists in database table. Otherwise it returns an error:
How to get rid of superfluous checks like:
#if(isset($user->city()->name))
{{$user->city()->name}}
#endif
This is awfully!

When defining the relationship on your model, use the withDefault method:
class User extends Model
{
public function city()
{
return $this->hasOne(City::class)->withDefault();
}
}
With this in place, $user->city will always return a City model.

Related

Inconsistency with 'show' function

I've been working on a project for a few months now and I feel like I am seeing some inconsistency with how the public function show is working
I have a model and controller for a Location that has
public function show(Location $Location)
{
$Loc = Location::with('company:id,name')->findOrFail($Location);
return response()->json($Loc,200);
}
and that works just fine. Note the parameters.
I just made a new model and controller for Asset and it has this:
public function show(Asset $asset)
{
$AssetReturn = Asset::with('location:id,name,address')->findOrFail($asset);
return response()->json($AssetReturn,200);
}
but that does not work. it just returns empty. If i remove the class name from the parameters so its just
public function show($asset)
then it works as intended.
relation from asset model to location:
public function location()
{
return $this->belongsTo(Location::class);
}
According to the documentation, Laravel automatically resolves Eloquent models defined in routes or controller actions whose type-hinted variable names match a route segment name. For example:
Route::get('/assets/{asset}', function (App\Asset $asset) {
$asset->load('location:id,name,address');
return response()->json($asset);
});
Since the $asset variable is type-hinted as the App\Asset Eloquent model and the variable name matches the {asset} URI segment, Laravel will automatically inject the model instance that has an ID matching the corresponding value from the request URI. If a matching model instance is not found in the database, a 404 HTTP response will automatically be generated.
If you don't want this behavior and want to use findOrFail manually:
Route::get('/assets/{asset}', function ($assetId) {
$asset = App\Asset::with('location:id,name,address')->findOrFail($assetId);
return response()->json($asset);
});

Custom method not work on HasMany relation

I trying to call a custom method from a model by relation.
User Model:
class User extends Model
{
public function files()
{
return $this->hasMany(Files::class, 'file_id', 'id');
}
}
File Model:
class Files extends Model
{
public function cover()
{
dd('blah blah');
}
}
In my controller I said:
$user = User::find(1);
$user->files()->cover();
But I will get this error:
Call to undefined method Illuminate\Database\Eloquent\Relations\HasMany::cover()
What is the problem in my code?
Basically you are calling your cover() method over the collection. That's why that is not working.
You are using hasMany Laravel relationship. And this hasMany returns collection of related records(items). And yo can't call any model function on that directly.
But if you wan to call function on this. you need to firstly loop the items, like below example:-
$user = User::find(1);
foreach($user->files() as $file) {
$file->cover();
}
Above code will provide you output. Try this.
If you want to get all the covers of you files, you can do this :
$user = User::with('files.cover')->find(1);
$covers = $user->files->pluck('cover')->flatten();
I want to use this method to check and then store the cover. because I need to check the cover before insert I couldn't use create method, it will be an alias to create. so I couldn't overwrite to create method?
From this, you can do the following:
foreach($user->files as $file){
$cover = $file->cover()->firstOrCreate(['attribute' => $value]);
// If you want to check if you just created the cover
if($cover->wasRecentlyCreated){
// Do stuff
}
}

Getting data from two separate models in laravel

I wanted to get data which is related to an id and I used the find($id) method to get those data, now I wanna get data from two tables which have one to many relationship.
How can I get data which is related to the same id from two table?
I try to this way but it hasn't worked:
public function show($id)
{
$post=Clients::find($id);
return view('pet.shw',['post'=>$post,'pets'=>$post->pets]);
}
Why you dont use with() I have simple solution but maybe not best solution:
Post::with('pets')->where('id',$id)->first();
Maybe below code is work to i dont test it:
Post::with('pets')->find($id);
Of course you should have comments method in your Post Object:
public function pets(){
return $this->hasMany(Pet::class);
}
hope help
You need to first define a relationship between your Client model and Pet model
So, in App\Client, you would have the following relationship:
public function pets()
{
return $this->hasMany(Pet::class);
}
and in App\Pet, you would have the following relationship:
public function client()
{
return $this->belongsTo(Client::class)
}
You should then be able to do this in your Controller:
public function show($id)
{
$post = Client::with('pets')->find($id);
return view('pet.shw')
->withPost($post);
}
and accesses your relationship like this in the pet.shw view:
foreach($post->pets as $pet) {}
For more information read about Eloquent Relationships

laravel model relation not working

I have created a laravel api for my application.I have used Pingpong module package for different modules.I am having hard time establishing many-to-many relation.I have 3 tables:roles,groups,group_roles.And my models are:
Group.php
namespace Modules\User\Entities;
use Illuminate\Database\Eloquent\Model;
class Group extends Model {
protected $fillable = [];
protected $table='groups';
public static function roles(){
return $this->belongsToMany('Modules\User\Entities\Role','group_roles','group_id','role_id');
}
}
Role.php
namespace Modules\User\Entities;
use Illuminate\Database\Eloquent\Model;
class Role extends Model {
protected $fillable = [];
protected $table='roles';
public function groups(){
return $this->belongsToMany('Modules\User\Entities\Group','group_roles','group_id','role_id');
}
}
And my controller
namespace Modules\User\Http\Controllers;
use Pingpong\Modules\Routing\Controller;
use Modules\User\Entities\Group;
use Modules\User\Entities\Role;
use Illuminate\Http\Request;
use App\Login;
use Input;
use Validator;
use Hash;
use Response;
class UserController extends Controller {
public function getGroupById(Request $request){
$groups=Group::with('roles')->get();
return Response::json ([
'status'=>'ok',
'group'=>$groups
],200);
}
}
The problem is I am not able to establish the relation between the models and the getGroupById returns 500 internal error response.$group=Group::all(); $group=Group::find($request['id']); returns fine but it is not returning related roles.
Similar structure and codes work fine on app without the use pingpong.
Your relationships are currently like this:
// not sure why this is static?
public static function roles(){
return $this->belongsToMany('Modules\User\Entities\Role', 'group_roles', 'group_id', 'role_id');
}
public function groups(){
return $this->belongsToMany('Modules\User\Entities\Group', 'group_roles', 'group_id', 'role_id');
}
Please note from the docs, regarding the belongsToMany method:
The third argument is the foreign key name of the model on which you are defining the relationship, while the fourth argument is the foreign key name of the model that you are joining to...
So with this in mind I think your relationships may be incorrect due to using the wrong arguments on your belongsToMany method calls. I think it should be like this:
public function roles(){
return $this->belongsToMany('Modules\User\Entities\Role', 'group_roles', 'group_id', 'role_id');
}
public function groups(){
return $this->belongsToMany('Modules\User\Entities\Group', 'group_roles', 'role_id', 'group_id');
}
Also if you have intermediate table columns you'd need to declare those on the belongsToMany call.
Hope that helps!
Edit
Firstly, you said getGroupById returns 500 internal error response. Have you tried checking what the actual error is!? 500 internal error doesn't provide much info, I'm sure you'd get to the bottom of things a lot faster if you found out the exact issue through laravel's usual error response page.
I assume you're doing this through an ajax request so you could use the network tab if you're using chrome then click on the 500 request to see the error laravel returns or you can use something like postman and hit the url through that.
If I wanted to quickly check the functionality of the models relationship methods, I'd do the following:
After setting up some data for a group and relationship, could you try running this in tinker or a route for testing/debugging.
$g = Group::first(); // get the first group, or you could use find($id) if you had a specific group in mind
// if you're in tinker
$g->roles; // show the roles
// if you're running on a route
dd($g->roles); // show the roles
While haakym's answer is very detailed, but you can also try changing your mapping table name to convention based 'group_role' instead of 'group_roles'. With this method you will have to supply only one argument to belongsToMany call.
Note that in general it should not matter if the other arguments are correct, but its just another step to debug!

laravel display only specific column from relation

I have read a few topics about this, but they managed to solve my problem partially ...
this is my controller
class DeskController extends BaseController{
public function getDeskUsers($deskId){
$user = DeskUserList::where(function($query) use ($deskId){
$query->where('deskId', $deskId);
})->with('userName')->get(array('deskId'));
if (!$user->isEmpty())
return $user;
return 'fail';
}
this is the model
class DeskUserList extends Eloquent {
protected $table = 'desk_user_lists';
public function userName(){
return $this->belongsTo('User', 'userId')->select(array('id','userName'));
}
}
the method getDeskUsers may returns ALL the DeskUserList table records, related with the User table record (on deskUserList.userId = User.id).
practically I want each record returned is composed of:
DeskUserList.deskId
User.userName
eg. [{"deskId":"1","user_name":antonio}]
What i get is
[{"deskId":"1","user_name":null}]
As you can see the user name is a null value...
BUT
if I edit my controller code:
->with('userName')->get(array('userId')); //using userId rather than deskId
then i get
[{"userId":"2","user_name":{"id":"2","userName":"antonio"}}]
By this way I still have two problem:
the userId field is twice repeated
I miss the deskId field (that I need...)
hope be clear, thanks for your time!
You need belongsToMany, no need for a model representing that pivot table.
I assume your models are Desk and User:
// Desk model
public function users()
{
return $this->belongsToMany('User', 'desk_user_list', 'deskId', 'userId');
}
// User model
public function desks()
{
return $this->belongsToMany('Desk', 'desk_user_list', 'userId', 'deskId');
}
Then:
$desks = Desk::with('users')->get(); // collection of desks with related users
foreach ($desks as $desk)
{
$desk->users; // collection of users for particular desk
}
// or for single desk with id 5
$desk = Desk::with('users')->find(5);
$desk->users; // collection of users
$desk->users->first(); // single User model

Resources