Laravel Factory - laravel

Hi I am new to creating factories on Laravel and I am setting up a blog website. There is no need for users at this time as it is a draft but I am trying to set up a factory to create dummy blog posts.
I have a Post.php file which looks like this:
namespace App;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
protected $table = 'posts';
public $primaryKey = 'id';
public $timestamps = true;
}
My PostFactory looks like this
use App\Post;
use Faker\Generator as Faker;
use Illuminate\Support\Str;
$factory->define(App\Post::class, function (Faker $faker) {
return [
'title' => $faker->name,
'body' => $faker->unique()->safeEmail,
];
});
but everytime i try to create the records it throws this error "InvalidArgumentException with message 'Unable to locate factory for [App/Post].'"
i know its about linking these files but i cannot figure out how to do it.

First as mentioned above your file must be named Post.php and not posts.php.
Since you are using App\Post at the beginning of your file, you can simply call Post::class
$factory->define(Post::class, function (Faker $faker)
Another option could also be that you are missing the factories folder in your composer classmap:
"autoload": {
"psr-4": {
"App\\": "app/"
},
"classmap": [
"database/seeds",
"database/factories"
]
},
If this does not solve the problem, then you might need to post your code where you are calling your factory
#edit
this is pretty good overview over conventions

Related

Loading a belongs to relationship inside of a laravel resource collection

I'm having some issues loading my relationships into a ResourceCollection to be consumed by an API, I want to load blogs that each belong to a category.
The blog model which uses a belongsTo relationship
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;
class BlogPost extends Model {
use HasFactory, SoftDeletes;
protected $fillable = [
'title',
'content',
'seo_title',
'seo_content',
];
public function categories(): BelongsTo {
return $this->belongsTo(BlogCategory::class);
}
}
The Category model has a hasMany to blogs
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
class BlogCategory extends Model {
use HasFactory;
protected $fillable = [
'slug'
];
public function blogs(): HasMany {
return $this->hasMany(BlogPost::class);
}
}
Inside of the blog_post migration, I added a foreign key to blog_categories
$table->foreignId('category_id')->constrained('blog_categories');
Then, in my BlogPost ResourceCollection I tried loading the relationship,
#[ArrayShape(['data' => "\Illuminate\Support\Collection", 'category' => AnonymousResourceCollection::class])] public function toArray($request): array {
return [
'data' => $this->collection,
'category' => BlogCategoryCollection::make($this->whenLoaded($this->categories))
];
}
I call the collection inside of the index function of my controller
public function index(): BlogPostCollection
{
return new BlogPostCollection(BlogPost::all());
}
And when I hit the api/blogs endpoint I get the error :
Property [categories] does not exist on this collection instance.
Managed to fix it in the end.
Changed the BlogPostResourceCollection to the following
return [
'data' => $this->collection,
'categories' => BlogCategoryCollection::collection($this->whenLoaded('categories'))
];
seems to work in the end.

Unable to locate factory in Laravel 7

I am making a unit test for PHPunit. The code is:
<?php
namespace Tests\Unit;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use PHPUnit\Framework\TestCase;
class ThreadTest extends TestCase
{
use DatabaseMigrations;
public function test_a_thread_has_replies()
{
$thread = factory('App\Thread')->create();
$this->assertInstanceOf('Illuminate\Database\Eloquent\Collection', $thread->replies);
}
}
When I run PHPUnit i get the error:
InvalidArgumentException: Unable to locate factory for [App\Thread].
I have a threadfactory:
<?php
/** #var \Illuminate\Database\Eloquent\Factory $factory */
use App\Thread;
use Faker\Generator as Faker;
$factory->define(Thread::class, function (Faker $faker) {
return [
'user_id' => factory(App\User::class),
'title' => $faker->sentence,
'body' => $faker->paragraph
];
});
If I use the factory in Tinker it works fine.
I have similar testfunctions and factories for other classes and these work fine.
Most likely I am making a very stupid error, but I cannot find it.
Any suggestions?
Kind regards,
HUbert
You are extending the php unit testcase class. Which does not load your Laravel application. You should extends the use Tests\TestCase provided by Laravel.
Using php artisan make:test UserTest on the CLI will create a test with the correct template fitting for testing a Laravel application.
What worked for me was to use
$factory->define(App\Model::class, function (Faker $faker) {
//return code here
}
Instead of just using the Model name without placing APP\ in front of the model name
$factory->define(Model::class, function (Faker $faker) {
//return code here
}

Laravel 6.2 whereHasMorph not returning expected value

Need some help for laravel polymorphic. I'm trying to filter from the main table which is Comment to get its morph tables and search for the key word FOO. I have tried with whereHas but get error saying to use whereHasMorph so I tried changing whereHas to whereHasMorph. But every time i filter, the result will be an empty collection even if the value exist in the table. So I went through laravel documentation and found the below sample. I tried the sample but I'm still getting an empty collection. I have tried reading but could not find a fix.
Below is the sample code which I have tried
** Models **
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Comment extends Model
{
protected $table = 'comments';
protected $fillable = [
'body',
'commentable_id',
'commentable_type'
];
public function commentable()
{
return $this->morphTo();
}
}
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
protected $table = 'posts';
protected $fillable = [
'title',
'body'
];
public function comments()
{
return $this->morphMany('App\Comment', 'commentable');
}
}
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Video extends Model
{
protected $table = 'videos';
protected $fillable = [
'title',
'url'
];
public function comments()
{
return $this->morphMany('App\Comment', 'commentable');
}
}
** Controller **
public function commentList () {
$comments = App\Comment::whereHasMorph(
'commentable',
['App\Post', 'App\Video'],
function ($query) {
$query->where('title', 'like', '%foo%');
}
)->get();
dd($comments);
}
Is there anything I'm missing out or do i need to configure something or install some packages ?
"php": "^7.2",
"laravel/framework": "^6.2",
Images of DB table
I have tried and dont know why suddenly work when i remove the first \ in the DB.
Changed \App\Post in the table to App\Post and also in the code then it work already. Thanks for all the help.

How to create a Custom Auth Guard / Provider for Laravel 5.7

I'm migrating from Laravel 4 to 5.7 and having trouble with my custom auth provider. I've followed various walkthroughs (e.g. 1, 2, 3) as well as quite a bit of googling.
I've attempted to get this working by the following:
Set the guards and providers and link to my target model.
'defaults' => [
'guard' => 'custom_auth_guard',
'passwords' => 'users',
],
'guards' => [
'custom_auth_guard' => [
'driver' => 'session',
'provider' => 'custom_auth_provider',
],
],
'providers' => [
'custom_auth_provider' => [
'driver' => 'custom',
'model' => App\UserAccount::class,
],
],
Register the driver defined in the above provider. I'm piggybacking off AuthServiceProvider for ease
...
public function boot()
{
$this->registerPolicies();
\Auth::provider('custom',function() {
return new App\Auth\CustomUserProvider;
});
}
...
Created my custom provider which has my retrieveByCredentials, etc. I've replaced the logic with some die() to validate if it is making it here. In Laravel 4, it used to go to validateCredentials().
class CustomUserProvider implements UserProviderInterface {
public function __construct()
{
die('__construct');
}
public function retrieveByID($identifier)
{
die('retrieveByID');
}
public function retrieveByCredentials(array $credentials)
{
die('retrieveByCredentials');
}
public function validateCredentials(\Illuminate\Auth\UserInterface $user, array $credentials)
{
die('validateCredentials');
}
For reference, App/UserAccount looks like so
class UserAccount extends Authenticatable
{
use Notifiable;
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'public.user_account';
// no updated_at, created_at
public $timestamps = false;
private $_roles = [];
private $_permissions = [];
}
Finally, I am calling it via my controller.
if(\Auth::attempt($credentials){
return \Redirect::intended('/dashboard');
}
I have also tried to call the guard direct
if(\Auth::guard('custom_auth_guard')->attempt($credentials){
return \Redirect::intended('/dashboard');
}
This results in the following error: "Auth guard [custom_auth_guard] is not defined."
I've tried a few other commands to make sure there is no cache issue:
composer update
php artisan cache:clear
The results: when I call Auth::attempt($credentials) Laravel is trying to run a query on the users table. the expected result is that it would hit one of the die()'s in CustomUserProvider... or at lease try and query public.user_account as defined in the model.
I've been messing with this for some time and I must be missing something simple... hopefully someone with a bit more experience in Laravel 5 can see what I am doing wrong.
Thanks in advance!!
Managed to work it out. Couple little problems but the main one was that I was trying to piggyback on AuthServiceProvider as opposed to my own provider. Below is what I did to get a custom auth provider working in Laravel 5.7
Set the provider in config.auth.php.
'providers' => [
'user' => [
'driver' => 'eloquent',
'model' => \UserAccount::class,
],
],
Create a new provider in app/providers/ . This links the listed provider above with the correct User Provider Code.
namespace App\Providers;
use Auth;
use App\Auth\CustomUserProvider;
use Illuminate\Support\ServiceProvider;
class CustomAuthProvider extends ServiceProvider
{
public function register()
{
//
}
public function boot()
{
Auth::provider('eloquent',function()
{
return new CustomUserProvider(new \UserAccount());
});
}
}
Created my custom provider in app/auth/. This is the logic for validating the user and replaces the laravel functions for auth. I had an issue here where it was validating but not populating the user object. I originally had a test to see if the object was null and if it was, populate... however it was always populated with an empty object. removing the test allowed me to call Auth::user() functions.
namespace App\Auth;
use Illuminate\Contracts\Auth\Authenticatable as UserContract;
use Illuminate\Auth\EloquentUserProvider;
class CustomUserProvider implements EloquentUserProvider{
public function __construct()
{
$this->user = $user;
}
public function retrieveByID($identifier)
{
$this->user = \UserAccount::find($identifier);
return $this->user;
}
public function retrieveByCredentials(array $credentials)
{
// find user by username
$user = \UserAccount::where('name', $credentials['username'])->first();
// validate
return $user;
}
public function validateCredentials(\Illuminate\Auth\UserInterface $user, array $credentials)
{
//logic to validate user
}
Updated App/Models/UserAccount looks like so
use Illuminate\Foundation\Auth\User as Authenticatable;
class UserAccount extends Authenticatable
{
protected $table = 'public.user_account';
// no updated_at, created_at
public $timestamps = false;
private $_roles = [];
private $_permissions = [];
}
That's it. I can now validate via the below call
if(\Auth::attempt($credentials){
return \Redirect::intended('/dashboard');
}

Models in laravel

I'm developing an app in laravel, specifically a social network.
After wasting some time stuck on an issue I found out I had two files wich responded to the user model.
One is namespaced under "appname" and the other under "appname\Models",
Adding the posts() method in the one under "appname" gave me an error where the method couldn't be found, so I assumed the one under "appname\Models" was the correct one. Although deleting the "User.php" under "appname" gives me a
Fatal error: Class 'Instyle\User' not found
error.
I'm sure I've misunderstood something along the lines I just can't point out where.
app\Models\User.php
namespace Instyle\Models;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
protected $table = 'users';
protected $fillable = [
'username',
'email',
'password',
'first_name',
'last_name',
'location',
];
protected $hidden = [
'password',
'remember_token',
];
public function getName()
{
if($this->first_name && $this->last_name)
{
return "{$this->first_name} {$this->last_name}";
}
if ($this->first_name)
{
return $this->first_name;
}
return null;
}
public function getUsername()
{
return $this->username;
}
public function getFirstNameOrUsername()
{
return $this->first_name ?: $this->username;
}
public function getAvatarUrl()
{
$hash = md5(strtolower(trim($this->attributes['email'])));
return "http://www.gravatar.com/avatar/$hash?d=https://u.pomf.is/maqope.png";
}
public function posts()
{
return $this->hasMany('Instyle\Post');
}
}
app/User.php
<?php
namespace Instyle;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
protected $fillable = [
'name', 'email', 'password',
];
protected $hidden = [
'password', 'remember_token',
];
public function posts()
{
return $this->hasMany('Instyle\Post');
}
}
app\post.php
<?php
namespace Instyle;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
protected $fillable = ['body'];
// protected $appends = ['humanCreatedAt'];
public function user()
{
return $this->belongsTo('Instyle\User');
}
}
if your application name is Instyle, Instyle\User is the User.php inside the app folder not the User.php in app/Models/.
More info: learn more in psr namespacing and autoloading. check your compose.json . here it says that namespace Instyle is app/ folder and from here the namespace at the top of each file goes according to the absolute folder path.
"psr-4": {
"Instyle\\": "app/"
}
One more thing, If you are willing to use User.php anywhere else and thinking it for authentication purpose remember to change authentication configuration declared in config/auth.php accordingly
I would avoid to have both models with the same name because it may collide one with the other, although they are in different paths.
Make sure you are importing your custom models with the use path\to\your\namespace\Model; expression to allow the root path of your models to be located in a correct way.
May be helpful to see your Post and User models sample code to evaluate the error.
UPDATE: Why don't you try to generate only one User model and, the other data related with the User Profile, try to save in one One-to-One Relationship to a Profile table? i.e. firstname, lastname, location, twitter_account, facebook_account, phone_number, and so on could be stored in a User_Profile or Profile separated table, then you maintain your User table with the minimum required fields and delete the other one.

Resources