Laravel - Retrieving associated model using all function - php

I am writing a program that has a many-to-many relationship between clients and concerns. I have configured my models to use the belongsToMany() function as outlined in the Laravel documents. Please see the code for the two models below:
Client.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Client extends Model
{
use HasFactory;
protected $fillable = [
'first_name',
'last_name',
'email',
'preferred_day',
'preferred_time',
'presenting_concerns',
'is_active',
];
public function invoices() {
return $this->hasMany(Invoice::class);
}
public function concerns() {
return $this->belongsToMany(Concern::class);
}
}
Concern.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Concern extends Model
{
use HasFactory;
protected $guarded = [
'concern',
];
public function clients() {
return $this->belongsToMany(Client::class);
}
}
I was able to create some sample data using factories and php artisan tinker. I am now in the process of building out my views. However when I call
$clients = Client::all()->concerns()
in my controller, I get a concerns does not exist error message. I did a dd on just Clients::all(), and I don't see the concerns attached to the returned model. From my understanding, with just the call to all() function, I just return the client model. However, I was hoping by calling the concerns() function, I would be able to return the concerns as well. Is it possible to retrieve all clients and their concerns in one call?
Please note that I can use Client::find(2)->concerns() but that does not help me in my case because that only returns the concerns for client with ID 2.

Yes you can do this. You need to eager load your relation of interest.
If you do the following, you will load the relation and will be able to see it when doing dd().
$clients = Client::with('concerns')->get();

Related

Laravel How to reference model outside of package?

I'm using laravel 8 with a custom package. I have models in this package and outside this package, for example User (from default auth) and thread model (in a package). I've got thread-user relationship belongsToMany for "like"-system that I need to have working. here is a piece of code, of thread model.
namespace LaraChan\Core\Models;
use Illuminate\Database\Eloquent\Model;
use LaraChan\Core\Traits\Renderable;
use LaraChan\Core\Traits\Uuids;
use LaraChan\Core\Traits\Image;
use App\Models\User;
class Thread extends Model
{
use Uuids, Image, Renderable;
protected $fillable = [
'id',
'board',
'title',
'image',
'body',
'user_author'
];
public function userlikes(){
return $this->belongsToMany(User::class, 'threads_liked', 'thread_id', 'user_id');
}
}
it does not seem to me that relationship is working. I've used Larachan package. https://github.com/anthonybudd/LaraChan
In order to reference a model outside of a package in Laravel, you can use the full namespace of the model.
For example, if your model is located in the App\Models namespace, you can reference it like this:
$model = App\Models\MyModel::find(1);

Laravel / Mongdb - DB::collection() is not working

I am following this Laravel/Mongodb package: https://github.com/jenssegers/. Here if you go to this section https://github.com/jenssegers/laravel-mongodb#basic-usage-2 you can see that they are using DB::collection() method and passed the collection name to that.
Now, in my controller, I am trying to do this:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use App\Models\Import;
use App\Models\Projects;
use Jenssegers\Mongodb\Collection;
use Jenssegers\Mongodb\Query\Builder;
class ImportController extends Controller
{
public function get_all_products() {
// Predefined key
$predefined_keys = [ 'image_link', 'title', 'price', 'brand', 'link' ];
// Get all the products
//$get_products = Import::paginate(10);
$get_products = DB::collection('products_1')->get();
return response()->json($get_products, 200);
}
}
but I don't get any result. Can you tell me what I am missing here?
My goal is to set the collectioin name directly in this controller not in Model.
Update:.
Here is my Import Mode:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Jenssegers\Mongodb\Eloquent\Model;
class Import extends Model
{
protected $connection = 'mongodb';
protected $collection = 'products_46';
// protected $table = 'projects';
}
Something is wrong with how you have configured this project.
From the documentation that you linked:
When using MongoDB connections, Laravel will automatically provide you with the corresponding MongoDB objects.
Yet in the comments you report that DB::collection('products_1')->get(); results in:
message": "Method Illuminate\\Database\\MySqlConnection::collection does not exist."
This error message is referencing MySQL rather than MongoDB. It seems you are using MySQL for other portions of your application per this question.
In any case, I think the answer is to be sure to load the packages appropriately (and perhaps also to disambiguate between namespaces if DB is separately defined in Illuminate\Support\Facades and is in scope for this portion of the code).

Why does only some laravel routes return model attributes?

i´m studying laravel but having some doubts..
Controller
namespace App\Http\Controllers;
use App\ItemNfe;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
class ItensNfeController extends Controller
{
public function edit($id,ItemNfe $itemNfe)
{
//i don´t want to have to make this select below
//$itemNfe = DB::table('itens_nfe')->where('id_itemnfe',$id)->get();
// dd($itemNfe); this dd() returns model attributes on few of my controllers only
return view...
}...
Model: (note i´m not using laravel convention but it´s informed)
namespace App;
use Illuminate\Database\Eloquent\Model;
class ItemNfe extends Model
{
protected $table = 'itens_nfe';
protected $primaryKey = 'id_itemnfe';
protected $fillable = [
'id_itemnfe','fk_venda', 'fk_produto'...
];
public function nfe()
{
return $this->belongsTo('App\Nfe'); //this is one diference among others models, but apparently doesn´t affects when i tested without this code.
}
}
The route i´m using is the same for everyone.. "resource routes"
At the first 2, i have the attributes returning, but not at the last one...
Route::resource('/usuarios', 'UsuariosController');
Route::resource('/nfes', 'NfesController');
Route::resource('/itensnfe', 'ItensNfeController');
The Url used is:
https://localhost/erpoverweb/public/itensnfe/1/edit
If needing more code please tell me... thanks!
If you don't want to manually search the database for the entry, you can use Laravel Container do perform a Dependency Injection. https://laravel.com/docs/7.x/container#introduction
public function edit(ItemNfe $itemNfe)
{
// Returns the model, and you didn't need to manually searched.
// Laravel automaticly injects this for you.
dd($itemNfe);
}
Sounds like you are looking for Route Model Binding (implicit at that). This requires that the route parameter name and the name of the parameter of the method signature for that route match.
public function edit(ItemNfe $itensnfe)
The resource route with resource name 'itensnfe' should make the parameter 'itensnfe'.
If you don't make these match you will just end up with Dependency Injection which would inject a new model instance.
Laravel 7.x Docs - Routing - Route Model Binding - Implicit Binding

Laravel Sanctum (Former airlock) - How do I issue tokens for other models?

I am trying laravel sanctum for the first time.
I want to issue tokens for an Eloquent Model called Campaign.
This is my Campaign.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Laravel\Sanctum\HasApiTokens;
class Campaign extends Model
{
use HasApiTokens;
protected $guarded = ['id'];
public function users()
{
return $this->belongsToMany(User::class)->withPivot(['percentage'])->withTimestamps();
}
}
As you can see, I put the HasApiTokens trait on it.
With this, I can issue a token to any campaign like that:
$campaign->createToken('my-token-name');
So far, so good. It works and is correctly stored at the database.
The problem begins when I try to use the token to make any request protected with sanctum's middleware. This is the error that shows when I do it:
Call to undefined method App\\Campaign::getAuthIdentifier()
Well, I guess this getAuthIdentifier() comes from use Illuminate\Foundation\Auth\User class, which is commonly imported on the User model as Authenticatable;
I tried to create this method on my Campaign model and give it a try, that's what I've done:
public function getAuthIdentifier()
{
return 'id';
}
When I tried to post again, it seems to work. But I think it's not correct because it's kind weird. And it gets even worse when I call auth()->user() and I am able to access the Campaign object. I know that this is a consequence of what I have done here.
Can this package issue tokens based on something that is not actually an User?
If you know how to do it correctly, I would appreciate an answer :)
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Laravel\Sanctum\HasApiTokens;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Auth\Authenticatable;
class Campaign extends Model implements AuthenticatableContract
{
use HasApiTokens,Authenticatable;
protected $guarded = ['id'];
public function users()
{
return $this->belongsToMany(User::class)->withPivot(['percentage'])->withTimestamps();
}
}
In addition to your comment, if you like to get campaign send token in the header in the request and then search in the token table to find the related campaign

Can't eager-load a One-to-One relation in Laravel

In Laravel 5.2 I'm trying to eager load a User along with its Usersettings with this piece of code: App\User::with('usersettings')->get(), but it fails, and I can't seem to figure out why. This is the given error.
BadMethodCallException with message 'Call to undefined method Illuminate\Database\Query\Builder::usersettings()'
I've read the laravel docs and I've watched a lot of Laracasts, and this worked before, so I get the idea I'm missing something really small and probably obvious.
User.php
<?php
namespace App;
/* User with fields: id, email */
class User extends Illuminate\Database\Eloquent\Model {
protected $table = 'users';
public function usersettings() {
return $this->hasOne("App\Usersettings", "userid");
}
}
Usersettings.php
<?php
namespace App;
/* Settings with fields: id, userid, textcolor */
class Usersettings extends Illuminate\Database\Eloquent\Model {
protected $table = 'usersettings';
public function user() {
return $this->belongsTo('App\User', 'userid');
}
}
//Edit: I already tried lowercasing the s. This typo might have snuck in copying it to SO, but the error was there, and still is there, even after fixing it.
//Edit:
<?php
namespace App;
use App\UserSettings;
class User extends Illuminate\Database\Eloquent\Model {
protected $table = 'users';
public function settings() {
return $this->hasOne(UserSettings::class, "userid");
}
}
If I run php artisan tinker>>> App\User::with('settings')->get(), it works as expected, but below
<?php
namespace App;
use App\UserSettings;
class User extends Illuminate\Database\Eloquent\Model {
protected $table = 'users';
public function usersettings() {
return $this->hasOne(UserSettings::class, "userid");
}
}
gives BadMethodCallException with message 'Call to undefined method Illuminate\Database\Query\Builder::usersettings()' when I run php artisan tinker >>> App\User::with('usersettings')->get(). Likewise when I rename the method to abc and run php artisan tinker >>> App\User::with('abc')->get() (that fails as well)
You mistyped when defining the relation on the User model:
public function usersettings() {
return $this->hasOne("App\Usersettings", "userid");
}
I would suggest some cleanup:
name the tables 'users' and 'user_settings',
rename the field 'userid' to 'user_id',
rename the 'Usersettings' model to 'UserSettings'.
That way you dont need to explicitly define table names and foreign keys, because you follow the conventions and Laravel can "guess" those.
You can also rename the the relation 'usersettings()' to 'settings()', since its obvious that they're the users' settings. Then you can fetch it like: 'User::with('settings')->get()'.
Did you try running composer dump-autoload after you changed your model relationships?
Just to make sure you're aware of this: you don't actually need to define the relationship in your UserSettings model to achieve what you want, only define the relationship in the User model. This is because you'd only need to get the settings in the context of the User, not the other way around.
Code for the User model:
<?php
namespace App;
use App\UserSettings;
class User extends Illuminate\Database\Eloquent\Model {
public function userSettings() {
return $this->hasOne(UserSettings::class);
}
}
UserSettings model: make sure it's camel case and that userid is present in your migration (the convention in your case would be to have user_id, so I would rename that column in your migration because then Eloquent will pick it up automatically and you don't need the second parameter in your User model's hasOne() definition).
Also, rename your table to user_settings if you can. That's another Eloquent convention, this one being that the model name UserSettings translates the camel case S letter in the middle of the classname to _ (and as a matter of fact, you shouldn't even need to explicitly state the table name if you've used the name user_settings).
Code for the UserSettings model:
<?php
namespace App;
/* Settings with fields: id, userid, textcolor */
class UserSettings extends Illuminate\Database\Eloquent\Model {
protected $table = 'user_settings';
}
Now, you should be able to do the below action. Note that the with parameter needs to be the relation function name from the User model.
$usersThatHaveSettingsIncludedInTheResults = User::with('userSettings')->get();

Categories