How to successfully execute test via phpunit within relationship between two models? - laravel

I'm new in Laravel. I have 2 tables Productions and Products. Also, I have 2 factories ProductionFactory and ProductFactory. I want to test them via phpunit. Their connection is via production_id.
Error is ErrorException: Undefined variable: production.
I don't get it.
Thanks in advance.
This is a code.
ProductionFactory.php
$factory->define(App\Production::class, function (Faker $faker) {
return [
'name' =>$faker->name,
];
});
ProductFactory.php
$factory->define(App\Product::class, function (Faker $faker) {
$production_id = App\Production::pluck('id');
if(!$production_id->isEmpty()){
$production = $production_id->random();
}
return [
'id' =>$faker->uuid,
'name' =>$faker->name,
'price' => $faker->numberBetween($min = 100, $max = 900),
'description' =>Str::random(10),
'production_id'=> $production,
];
ProductionTest.php
class ProductionTest extends TestCase
{
use RefreshDatabase;
/**
* A basic unit test example.
* #test
* #return void
*/
public function production()
{
factory(Production::class)->make();
$this->assertTrue(true);
}
}
ProductTest.php
class ProductTest extends TestCase
{
use RefreshDatabase;
/**
* A basic unit test example.
* #test
* #return void
*/
public function product()
{
factory(Product::class)->make();
$this->assertTrue(true);
}
}

Model Production
use Illuminate\Database\Eloquent\SoftDeletes;
class Production extends Model
{
use SoftDeletes;
protected $fillable = [
'name',
];
public function products()
{
return $this->hasMany('App\Product');
}
Model Product
class Product extends Model
{
use SoftDeletes;
protected $fillable = [
'id','name','price','description','production_id'
];
public function production()
{
return $this->belongsTo('App\Production');
}
SQLSTATE[HY000]: General error: 1364 Field 'production_id' doesn't have a default value

It depends on what functionality should be tested.
A basic test to check the model relationship is set correctly?
I pushed a working demo to GitHub (https://github.com/.../laravel-basic-relationship-tests).
App/Product.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
public function production()
{
return $this->belongsTo(Production::class);
}
}
App/Production.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Production extends Model
{
public function products()
{
return $this->belongsTo(Product::class);
}
}
Product Factory
<?php
/* #var $factory \Illuminate\Database\Eloquent\Factory */
use App\Product as Model;
use Faker\Generator as Faker;
$factory->define(Model::class, function (Faker $faker) {
$production = factory(\App\Production::class)->make();
$production->save();
return [
'name' => $faker->name,
'price' => $faker->numberBetween($min = 100, $max = 900),
'description' => $faker->text,
'production_id' => $production->id
];
});
Production Factory
<?php
/* #var $factory \Illuminate\Database\Eloquent\Factory */
use App\Production as Model;
use Faker\Generator as Faker;
$factory->define(Model::class, function (Faker $faker) {
return [
'name' => $faker->name
];
});
$factory->afterCreatingState(Model::class, 'seed', function ($production, $faker) {
$product = factory(\App\Product::class)->make();
$production->products()->associate($product);
});
Product Test
<?php
namespace Tests\Feature;
use Tests\TestCase;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Foundation\Testing\RefreshDatabase;
class ProductTest extends TestCase
{
/**
* #return void
*/
public function testProductHasWorkingProductionRelationship()
{
$product = factory(\App\Product::class)->create();
$this->assertNotEmpty($product->production);
}
}
Production Test
<?php
namespace Tests\Feature;
use Tests\TestCase;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Foundation\Testing\RefreshDatabase;
class ProductionTest extends TestCase
{
/**
* #return void
*/
public function testProductionHasWorkingProductRelationship()
{
$production = factory(\App\Production::class)->state('seed')->create();
$this->assertNotEmpty($production->products);
}
}
Hope this is a great starting point for any further tests.

Related

Image value should be null when image is not uploaded

Employee Controller
<?php
namespace App\Http\Controllers;
use App\Talent\Employee\Requests\EmployeeCreateRequest;
use App\Talent\Employee\EmployeeManager;
use Illuminate\Http\Response;
use App\Talent\User\UserManager;
use App\Talent\Documents\DocumentManager;
use Illuminate\Support\Facades\Hash;
class EmployeeController extends Controller
{
public function __construct(private EmployeeManager $employeeManager,private UserManager $userManager,private DocumentManager $documentManager)
{
}
public function store(EmployeeCreateRequest $request){
$validated = $request->validated();
$userArray=[
'name'=>$validated['first_name']." ".$validated['last_name'],
'email'=>$validated['email'],
'password'=>Hash::make("Introcept#123"),
'role'=>'user'
];
$userCreate=$this->userManager->store($userArray);
return $this->employeeStore($validated,$userCreate,$request);
}
public function employeeStore($validated,$userCreate,$request){
if($request->hasFile($validated['avatar']))
{
$validated['avatar']=$validated['avatar']->store('employeeimages','public');
}
else
{
$validated['avatar']='null';
}
$userId=$userCreate->id;
$userIdArray=[
'user_id'=>$userId,
'status'=>'Active',
];
$employeeArray=array_merge($validated,$userIdArray);
$employeeCreate=$this->employeeManager->store($employeeArray);
$employeeId=$employeeCreate->id;
foreach($validated['documents'] as $document){
$name=$document->getClientOriginalName();
$type=$document->getClientMimeType();
$path=$document->store('employeedocuments','public');
$documentArray=[
'employee_id'=>$employeeId,
'original_name'=>$name,
'type'=>$type,
'path'=>$path,
];
$documentCreate=$this->documentManager->store($documentArray);
}
return response([
'userId'=>$userId,
'employeeId'=>$employeeId,
'message'=>'Personal detail added successfully',
],Response::HTTP_OK);
}
}
Employee.php
<?php
namespace App\Talent\Employee\Model;
use App\Talent\Documents\Model\Document;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Employee extends Model
{
use HasFactory;
protected $fillable = [
'first_name',
'last_name',
'email',
'contact_number',
'date_of_birth',
'current_address',
'pan_number',
'bank_account_number',
'avatar',
'status',
'user_id',
];
**EmployeeRequest.php**
<?php
namespace App\Talent\Employee\Requests;
use Illuminate\Foundation\Http\FormRequest;
class EmployeeCreateRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array<string, mixed>
*/
public function rules()
{
return [
'first_name'=>'required|string',
'last_name'=>'required|string',
'email'=>'required|email|unique:employees,email',
'contact_number'=>'required|string',
'date_of_birth'=>'required|date',
'current_address'=>'required|string',
'pan_number'=>'string|nullable',
'bank_account_number'=>'string|nullable',
'avatar' => 'nullable|image|mimes:jpg,jpeg,png',
'documents'=>'required',
'documents.*'=>'max:5000|mimes:pdf,png,jpg,jpeg',
];
}
public function messages()
{
return [
'documents.max' => "Error uploading file:File too big.Max file size:5MB",
];
}
}
EmployeeMigration
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('employees', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->constrained('users')->restrictOnDelete();
$table->string('status');
$table->string('first_name');
$table->string('last_name');
$table->string('email')->unique();
$table->string('contact_number');
$table->date('date_of_birth');
$table->string('current_address');
$table->string('pan_number')->nullable();
$table->string('bank_account_number')->nullable();
$table->string('avatar')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('employees');
}
};
I am trying to create an API that stores employee personal details into the database. Here, image field is optional so I made avatar field nullable in both migration and validation request as well. But when I try save details into the database without uploading image it shows undefined avatar. I don't know what happening here any help or suggestions will be really appreciated. Thank you.
You are using the string value of null instead of the keyword null.

Laravel 8 Invalid Date time while seeding

I am new to laravel , I receive error while trying to seed data, I have done it successfully in two different tables but I am stuck at this one :
Model
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Project extends Model
{
use HasFactory;
public $timestamps = false;
protected $fillable = [
'Pmid',
'Ministry',
'P_name',
'Budget',
];
protected $casts = [
'Registered_at' => 'datetime',
];
}
Factory
<?php
namespace Database\Factories;
use App\Models\Project;
use Illuminate\Database\Eloquent\Factories\Factory;
class ProjectFactory extends Factory
{
protected $model = Project::class;
/**
* Define the model's default state.
*
* #return array
*/
public function definition()
{
return [
'Pmid' => $this->faker->unique()->name(),
'Ministry' => $this->faker->name(),
'P_name' => $this->faker->name(),
'Budget' => $this->faker->name(),
'Registered_at' => now(),
];
}
}
Seeder
<?php
namespace Database\Seeders;
use App\Models\Project;
use Illuminate\Database\Seeder;
class ProjectTableSeeder extends Seeder
{
/**
* Run the database seeds.
*
* #return void
*/
public function run()
{
Project::factory()->count(20)->create();
}
}
Migration
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateProjectsTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('projects', function (Blueprint $table) {
$table->increments('id');
$table->string('Pmid')->unique();
$table->string('Ministry');
$table->string('P_name');
$table->integer('Budget');
$table->timestamp('Registered_at');
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('projects');
}
}
error
Illuminate\Database\QueryException
SQLSTATE[22007]: Invalid datetime format: 1366 Incorrect integer value: 'Mathias Kuhlman' for column laravel.projects.Budget at row 1 (SQL: insert into projects (Pmid, Ministry, P_name, Budget, Registered_at) values (Nicholas Mayer, Ms. Donna Strosin, Hermann Bins, Mathias Kuhlman, 2021-12-05 08:36:39))
You're using
'Budget' => $this->faker->name(),
to create the data, but your migration shows that that column should be an integer :
$table->integer('Budget');
I suspect you've just copied and pasted the faker rows without changing the type of value being faked.

Getting an error when trying to run seed in laravel

I'm using [Nwidart][1] module package and I'm trying to create a seeder using a factory. But when I try to run php artisan db:seed I get this error
Call to undefined function Modules\Products\Database\Seeders\factory()
Here is my ProductsDatabaseSeeder.php
<?php
namespace Modules\Products\Database\Seeders;
use Illuminate\Database\Seeder;
use Illuminate\Database\Eloquent\Model;
use Modules\Products\Models\Product;
class ProductsDatabaseSeeder extends Seeder
{
/**
* Run the database seeds.
*
* #return void
*/
public function run()
{
Model::unguard();
factory(Product::class, 10)->create();
}
}
My ProductFactory
<?php
/** #var \Illuminate\Database\Eloquent\Factory $factory */
use Faker\Generator as Faker;
use Modules\Products\Models\Product;
$factory->define(Product::class, function (Faker $faker) {
return [
'title' => $this->faker->title,
'price' => $this->faker->randomNumber(3),
];
});
My Product.php
<?php
namespace Modules\Products\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
use HasFactory;
protected $fillable = [];
}
Full error
Call to undefined function Modules\Products\Database\Seeders\factory()
at Modules/Products/Database/Seeders/ProductsDatabaseSeeder.php:25
21▕
22▕
23▕
24▕
➜ 25▕ $product = factory(Product::class, 10)->create();
26▕
27▕
28▕ }
29▕ }
+8 vendor frames
9 database/seeders/DatabaseSeeder.php:20
Illuminate\Database\Seeder::call()
+24 vendor frames
34 artisan:37
Illuminate\Foundation\Console\Kernel::handle()
This is what I get after changing
factory(Product::class, 10)->create();
to
Product::factory()->count(10)->create();
Class 'Database\Factories\Modules\Products\Models\ProductFactory' not found
at vendor/laravel/framework/src/Illuminate/Database/Eloquent/Factories/Factory.php:656
652▕ public static function factoryForModel(string $modelName)
653▕ {
654▕ $factory = static::resolveFactoryName($modelName);
655▕
➜ 656▕ return $factory::new();
657▕ }
658▕
659▕ /**
660▕ * Specify the callback that should be invoked to guess factory names based on dynamic relationship names.
+1 vendor frames
2 Modules/Products/Database/Seeders/ProductsDatabaseSeeder.php:25
Modules\Products\Models\Product::factory()
+8 vendor frames
11 database/seeders/DatabaseSeeder.php:21
Illuminate\Database\Seeder::call()
[1]: https://nwidart.com/laravel-modules/v6/introduction
As of Laravel 8 which is what you probably use - as you are using the HasFactory trait - you will need to call
Product::factory()->create()
In order to run the factory
https://laracasts.com/discuss/channels/code-review/please-help-call-to-undefined-function-factory?signup
Apart from adding the HasFactory trait to your model, in order to support the Modules{Module} namespace you need to put this in your model:
/**
* Create a new factory instance for the model.
*
* #return \Illuminate\Database\Eloquent\Factories\Factory
*/
protected static function newFactory()
{
return \Modules\Module\Database\Factories\ModelFactory::new();
}
So, in your model Product.php
<?php
namespace Modules\Products\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
use HasFactory;
/**
* Create a new factory instance for the model.
*
* #return \Illuminate\Database\Eloquent\Factories\Factory
*/
protected static function newFactory()
{
return \Modules\Products\Database\Factories\ProductFactory::new();
}
protected $fillable = [];
}
Also, since laravel 8 the conventions of using a factory has changed.
So, in your
ProductsDatabaseSeeder.php
<?php
namespace Modules\Products\Database\Seeders;
use Illuminate\Database\Seeder;
use Illuminate\Database\Eloquent\Model;
use Modules\Products\Models\Product;
class ProductsDatabaseSeeder extends Seeder
{
/**
* Run the database seeds.
*
* #return void
*/
public function run()
{
Model::unguard();
Product::factory()->count(50)->create();
}
}
And, finally the factory class ProductFactory.php like
<?php
namespace Modules\Products\Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
use Modules\Products\Models\Product;
class ProductFactory extends Factory
{
protected $model = Product::class;
public function definition()
{
return [
'title' => $this->faker->title,
'price' => $this->faker->randomNumber(3),
];
}
}

How to use eloquent on the auth command user in laravel

I am facing a weird error right now
In my controller, when I import the class user like this
use Illuminate\Foundation\Auth\User;
It works when I use eloquent like
public function index()
{
$farms = User::where('role_id', 3)->get();
$user = Auth::user();
$animal = Animal::all();
return view('clinic.index', compact('user', 'animal', 'farms'));
}
But refuses to work when it comes to table relationships like
public function show($id)
{
$farms = User::with(['animals'])->findOrFail($id);
return view('clinic.show',compact('farms'));
}
showing me this error
"Call to undefined relationship [animals] on model [Illuminate\Foundation\Auth\User]"
But whenever I import the user class as App\User in my controller,
It works in the relationship but refuses to work with the eloquent showing this error
"Call to a member function get() on null"
Now I am kinda confused. Any help will be welcomed
App\User
<?php
namespace App;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Database\Eloquent\Model;
class User extends Authenticatable
{
use Notifiable;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $guarded = [];
public static function where(string $string, int $int)
{
}
public static function select(array $array)
{
}
public function role(){
return $this->belongsTo(Role::class);
}
public function animals(){
return $this->hasMany(Animal::class);
}
public function clinics(){
return $this->hasMany(Clinic::class);
}
public function slaughter(){
return $this->hasMany(Slaughter::class);
}
public function address(){
return $this->belongsTo(Address::class);
}
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
/**
* The attributes that should be cast to native types.
*
* #var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
}
The Illuminate\Foundation\Auth\User class is the parent of the App\User class and animals relation set in the App\Userclass. So you can't call animals relation from Illuminate\Foundation\Auth\User class.
You should remove these functions from the App\User Model:
public static function where(string $string, int $int)
{
}
public static function select(array $array)
{
}

undefined $user->withAccessToken function/method

I wrote an API Code in laravel, and here my code, in this API I am using passport
class TransactionApi extends BaseController
{
public function __construct()
{
$this->middleware('client');
}
In the constructor, I call the client middleware
kernel.php
protected $routeMiddleware = [
...
'client' => CheckClientCredentials::class,
];
Here's my API service providers
protected function mapApiRoutes()
{
Route::prefix('api/v1')
->middleware('api')
->namespace($this->namespace)
->group(__DIR__ . '/../routes/api.php');
}
API routes
Route::group(['prefix' => 'transaction'], function () {
Route::get('all', 'TransactionApi#showAllWithPaginate');
Route::get('total_refund', 'TransactionApi#totalRefund');
Route::get('total_price', 'TransactionApi#totalPrice');
Route::get('/', 'TransactionApi#show');
});
User model
<?php
namespace Corals\User\Models;
use Corals\Foundation\Traits\Hookable;
use Corals\Foundation\Traits\HashTrait;
use Corals\Foundation\Transformers\PresentableTrait;
use Corals\Modules\CMS\Models\Content;
use Corals\Settings\Traits\CustomFieldsModelTrait;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Spatie\Activitylog\Traits\LogsActivity;
use Spatie\MediaLibrary\HasMedia\HasMediaTrait;
use Spatie\MediaLibrary\HasMedia\Interfaces\HasMediaConversions;
use Spatie\MediaLibrary\Media;
use Spatie\Permission\Traits\HasRoles;
use Yajra\Auditable\AuditableTrait;
use Corals\User\Traits\TwoFactorAuthenticatable;
use Corals\User\Contracts\TwoFactorAuthenticatableContract;
use Corals\User\Notifications\MailResetPasswordNotification;
use Corals\Modules\Subscriptions\Models\Subscription;
use Laravel\Passport\HasApiTokens;
class User extends Authenticatable implements HasMediaConversions, TwoFactorAuthenticatableContract
{
use
TwoFactorAuthenticatable,
HasApiTokens,
Notifiable,
HashTrait,
HasRoles,
Hookable,
PresentableTrait,
LogsActivity,
HasMediaTrait,
AuditableTrait,
CustomFieldsModelTrait;
protected $slack_url = null;
/**
* Model configuration.
* #var string
*/
public $config = 'user.models.user';
protected static $logAttributes = ['name', 'email'];
protected static $ignoreChangedAttributes = ['remember_token'];
protected $casts = [
'address' => 'json',
'notification_preferences' => 'array'
];
protected $appends = ['picture', 'picture_thumb'];
protected $dates = ['trial_ends_at'];
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $guarded = [
'id'
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token', 'two_factor_options'
];
public function __construct(array $attributes = [])
{
$config = config($this->config);
if (isset($config['presenter'])) {
$this->setPresenter(new $config['presenter']);
unset($config['presenter']);
}
foreach ($config as $key => $val) {
if (property_exists(get_called_class(), $key)) {
$this->$key = $val;
}
}
return parent::__construct($attributes);
}
Given that setup, testing locally is fine, it will return the requested json
But they same setup, on staging environment, returned
{
"message": "Call to undefined method Illuminate\\Auth\\GenericUser::withAccessToken()",
"exception": "Symfony\\Component\\Debug\\Exception\\FatalThrowableError",
"file": "/path/to/vendor/laravel/passport/src/Guards/TokenGuard.php",
"line": 148,
What are the posible cause why on staging
in this line
return $token ? $user->withAccessToken($token) : null;
undefined $user->withAccessToken function/method?

Resources