In my Laravel app there are 3 Models:
Movie, User, Review
Review:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Review extends Model
{
use HasFactory;
protected $hidden = ['user_id','movie_id','created_at','updated_at'];
public function movie(){
return $this->belongsTo(Movie::class);
}
public function user(){
return $this->belongsTo(User::class);
}
}
Movie:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Movie extends Model
{
use HasFactory;
protected $hidden = ['created_at','updated_at'];
public function review(){
return $this->hasMany(review::class);
}
public function getAvg()
{
return $this->review()->average('rating');
}
public function count()
{
return $this->review()->count();
}
public function getBestRating()
{
return $this->review()->max('rating');
}
public function getWorstRating()
{
return $this->review()->min('rating');
}
}
User:
<?php
namespace App\Models;
// use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
use Tymon\JWTAuth\Contracts\JWTSubject;
class User extends Authenticatable implements JWTSubject
{
use HasApiTokens, HasFactory, Notifiable;
public function review()
{
return $this->hasMany(Review::class);
}
}
The query that doesn't work
$movies = Movie::has('review')->with('review.user')->get();
In localhost it works fine. but after deploying in digitalOcean it returns "Class "App\Models\review" not found"
I tried the console on digitalOcean:
> Movie::has('review')->get()
[!] Aliasing 'Movie' to 'App\Models\Movie' for this Tinker session.
ERROR Class "App\Models\review" not found in vendor/laravel/framework/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php on line 775.
but after running this in the same session:
Review::all()
the previous Movie::has('review') works fine.
Why is that? Am I missing something?
You are most likely loading the classes from case sensitive file system hence why this issue is causing the issue. Whilst PHP class names are not case sensitive. It is considered good practice to them functions as they appear in their declaration
You need to change this line:
return $this->hasMany(review::class);
to
return $this->hasMany(Review::class);
You are using different letter case. Class is defined as Review but you invoke review:
$this->hasMany(review::class);
Unlike variable names, neither class names nor function names are case sensitive in PHP:
class Example
{
public static function test(): void
{
echo 'Hello, World!';
}
}
// This works
eXaMpLe::TeSt();
// This doesn't: Warning: Undefined variable $FOO
$foo = 1;
echo $FOO;
Demo
However, Laravel is using a PSR-4 compliant class auto-loader to locate and read the PHP files where classes are defined. Such auto-loader maps class names to file names, so whenever App\Models\Review is used in code, a filesystem path like /your/project/libraries/path/App/Models/Review.php is loaded. If any of your path components, either a directory or the file name, was created using a different case, whether it'll work or not will depend on the case-sensitive flag in the file system. If your file system is something like NTFS (typical on Windows) it'll decide that review.php and Review.php are the same file, so it'll work. In most Linux filesystems, it's actually allowed to have two different review.php and Review.php files, so they need to be considered different.
It's also worth nothing that the ::class syntax is just a string feature and doesn't really trigger class autoloading:
// This is fine
echo Does\Not\Exist::class;
So you don't get the error right in the offending line, but later down the line when the class is eventually used.
Related
I added a method to one of my models:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Test extends Model
{
public static function boot()
{
parent::boot();
static::created(function ($model) {
//log $model or maybe do something more complex here
});
}
}
And i wish to extend the same behaviour to many other models. Copy pasting this doesent seem like a good idea because if something changes i dont want to change it in different places. What is the best solution to write this only once and get the same behaviour to multiple models?
Traits are built for that. Write once and use on all classes.
Create a trait in app/Traits/MyTraitName.php
<?php
namespace App\Traits;
use Carbon\Carbon;
trait MyTraitName
{
public function someName() {
// TO DO;
}
}
and then just import it on top of any model class for example User:
<?php
namespace App;
use App\Traits\MyTraitName;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
use Notifiable, MyTraitName;
..............
The difference between extending a class and making a trait is that when you make a trait that function is already written and it's automatically used the same way on every model, and extending from some base class is better if that function is not going to be the same for every Model.
Using Relationships first time and having issue to understand it.
I have a Student Class and a Course Model Class. A student can take many courses. In Student Model I do this:
public function course()
{
return $this->belongsTo('Course');
}
and in controller when I do this: .$student->course()->course_title it gives an error:
FatalThrowableError in Model.php line 779:
Class 'Course' not found
What am I doing wrong?
replace your code with it
public function course()
{
return $this->belongsTo(Course::class);
}
Make sure your namespace in your Course class matches 'App\Models'. You might be trying to access an "empty" namespace.
Namespaces are declared at the top of your class file. So for example:
Course.php:
namespace App\Models;
use Illuminate\Http\Request;
...
class Course extends Model { ... }
OtherClass.php
namespace App\Models;
use Illuminate\Http\Request;
...
class OtherClass extends Model {
...
public function course()
{
return $this->belongsTo('App\Models\Course')
}
}
Please note that the namespace declared at the top of Course.php matches the path provided to the relationship method (return) belongsTo(). You can also provide Course::class to the belongsTo method, but you need to import aka use the class in your php class.
I hope this helps!
I had the same problem and i solved it by adding a name space in the top of my model
for your case,
use \App\Course ; // Your name space of your class in relation
Hope this help others
NB : I used Laravel 5.0
I am having an issue utilizing traits in a laravel enviroment.
I have attempting to access the trait from wtihin a model in laravel and am getting trait not found error. Below is my trait, this is stored in the app\Traits folder and is named testTrait.php
<?php
namespace App\Traits;
trait test{
public function printTest()
{
$test = 'test';
return $test;
}
}
This is the model I am using to try and access it, this is stored in the app\Models folder and otherwise works fine without attempting to use the trait
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use App\Traits\testTrait;
class Home extends Model
{
use testTrait;
public function someMethod()
{
/*
something here
*/
}
}
I assume it might have something to do with namespacing and the fact that I have to assign the App\Models namespace but even if I change or remove this it doesn't work.
Your file may be named testTrait.php, but you've called the trait in that file plain old test.
trait test { ... }
Rename it to testTrait in the testTrait.php file.
trait testTrait { ... }
You have defined your trait as trait test{ but in your model you are using wrong trait name use testTrait;
change it to
use test;
I using Laravel, I have a Model class under App/Models
<?php
namespace App\Models;
class TodoList extends \Eloquent{
public function listItems(){
return $this->hasMany('TodoItem');
}
}
In my Controller I have included the namespace as follows:
namespace App\Http\Controllers;
...
use App\Models\TodoItem;
use App\Models\TodoList;
class TodoListController extends Controller
My method looks like this:
public function show($id)
{
$list=TodoList::findOrFail($id);
return \View::make('todos.show')->with('list', $todo_list);
}
but when I call to a request i get the error:
FatalErrorException in TodoListController.php line 75: Class
'App\Models\TodoList' not found
Trying running composer dump-autoload. Basically your classes become cached so you need to tell Laravel to look for newly added classes.
I'm not sure, just try this :
namespace App\Models;
use Illuminate\Database\Eloquent\Model as Eloquent;
class TodoList extends Eloquent{
public function listItems(){
return $this->hasMany('TodoItem');
}
}
Here is the code from the docs, but for your example. Note the use Model:
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class TodoList extends Model {
//insert public function listItems() here
}
Hope this is helpful!
Make sure the file is in the correct folder and has the same name caption as the Class you want to import.
If the caption of the file "TodoList" is not TodoList.php but Todolist.php for example, Laravel wont find it.
Depending on your setup running "composer dump" might help to refresh autoload files.
In my app I have Event and User models.Because of Event model I have to put it into namespace .so I created namespace as of following.
Event
<?php namespace App\Models;
class Event extends \Eloquent {
public function user()
{
return $this->belongsTo('User');
}
User
<?php
use Illuminate\Auth\UserTrait;
use Illuminate\Auth\UserInterface;
use Illuminate\Auth\Reminders\RemindableTrait;
use Illuminate\Auth\Reminders\RemindableInterface;
use App\Models\Event;
class User extends Eloquent implements UserInterface, RemindableInterface {
public function events()
{
return $this->hasMany('Event');
}
The relations between User and Event are simple OneToMany. So in my EventController I use POST method to create new event resource .
$e = new Event(array('keys'=>'values')); //without user_id filled
$user->events()->save($e);
At the same time i got an error .
Call to undefined method Illuminate\Support\Facades\Event::newQuery()
If I am not wrong i guess it is namespace error.But namespaces are already declared correctly I guess.
But I try visiting similar questions and used alternative way in relationship and then it worked fine.Personally I don't find it satisfied.Any idea why this is occurred ?
Change the above relation to
public function events()
{
return $this->hasMany('\App\Models\Event');
}
If you put Event inside a namespace you need to use it with it's fully qualified classname.
You can either import it into your controller:
use App\Models\Event;
Or specify the namespace inline:
new App\Models\Event();
Also, I would recommend that if you create a namespace for models that you put all of them in there. (User is missing a namespace in your code)