Laravel 8 factory class is not overriding the parameters while creating the factories - laravel-8

I am developing a web application using Laravel 8. I have noticed that quite a lot of things have changed in Laravel 8 including factories.
I have a factory class MenuCategoryFactory for my MenuCategory model class with the following definition.
<?php
namespace Database\Factories;
use App\Models\Menu;
use App\Models\MenuCategory;
use Illuminate\Database\Eloquent\Factories\Factory;
class MenuCategoryFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* #var string
*/
protected $model = MenuCategory::class;
/**
* Define the model's default state.
*
* #return array
*/
public function definition()
{
return [
'name' => $this->faker->name,
'menu_id' => Menu::factory()->create(),
];
}
}
In my code (database seeder class), I am trying to override the menu_id as follow while I am creating the factories.
$restaurant = Restaurant::first();
MenuCategory::factory()->create([
'menu_id' => $restaurant->menu->id
]);
But it is not using the value I passed, $restaurant->menu->id. Instead, it is creating a new menu. What is wrong missing in my code and how can I fix it?

In your factory definition, don't call ->create(), instead set it up like this:
public function definition()
{
return [
'name' => $this->faker->name,
'menu_id' => Menu::factory(),
];
}
Then you you should be able to set up related models (assuming you the relationships setup in the model) like this:
$restaurant = Restaurant::first();
MenuCategory::factory()->for($restaurant)->create();

Change the definition to
public function definition()
{
return [
'name' => $this->faker->name,
'menu_id' => function() {
Menu::factory()->create()->id,
}
];
}
then you can replace the value

Related

Retrieve the attributes passed to a factory within the definition method - Laravel 9

I've been trying to find a way to retrieve the attributes passed to a factory within the definition method but have no luck, I first attempted to access the $this->states property (within the definition method) which returns a closure and then attempted to retrieve the attributes from there but have had no luck with this.
I am currently using the factories below:-
<?php
namespace Database\Factories;
use App\Models\Developer;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* #extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Developer>
*/
class DeveloperFactory extends Factory
{
/**
* Specify the corresponding model for the factory
*
* #var string $model
*/
protected $model = Developer::class;
/**
* Define the model's default state.
*
* #return array<string, mixed>
*/
public function definition()
{
return [
'name' => $this->faker->firstName
];
}
public function configure()
{
$this->afterCreating(function (Developer $developer) {
User::factory()->create([
'userable_type' => $developer->getMorphClass(),
'userable_id' => $developer->id
]);
});
}
}
<?php
namespace Database\Factories;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;
class UserFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* #var string
*/
protected $model = User::class;
/**
* Define the model's default state.
*
* #return array
*/
public function definition()
{
/**
* TODO: get any attributes that are passed into this factory
* e.g.userable_type, userable_id
*
* If these attributes are passed into the factory, stop the faker randomly generating a
* factory for a random user type and use the one passed into the factory
*/
$userableModel = (new $this->faker->userTypeModel)->factory()->create();
return [
'userable_type' => $userableModel->getMorphClass(),
'userable_id' => $userableModel->id,
'name' => $this->faker->name(),
'email' => $this->faker->unique()->safeEmail(),
'email_verified_at' => now(),
'password' => bcrypt('admin1234'), // password
'remember_token' => Str::random(10)
];
}
/**
* Indicate that the model's email address should be unverified.
*
* #return \Illuminate\Database\Eloquent\Factories\Factory
*/
public function unverified()
{
return $this->state(function (array $attributes) {
return [
'email_verified_at' => null,
];
});
}
}

class xxx contains 1 abstract method and must therefore be declared abstract or implement the remaining methods App\Models\xxx::getActivitylogOptions

Hello I am using Laravel-activitylog and when i tried to add the train to Model it gives me this error
Class App\Models\Setting contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (App\Models\Setting::getActivitylogOptions)
and this is all my Model code
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Astrotomic\Translatable\Translatable;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Astrotomic\Translatable\Contracts\Translatable as TranslatableContract;
use Spatie\Activitylog\Traits\LogsActivity;
class Setting extends Model
{
use Translatable,SoftDeletes;
use LogsActivity;
public $translatedAttributes = ['name', 'slogan', 'description', 'summary', 'address'];
protected $fillable = ['id', 'logo', 'favicon', 'phone', 'email', 'facebook', 'twitter', 'instagram', 'created_at', 'updated_at'];
// protected static $logAttributes = ['name', 'logo'];
public static function check()
{
$setting = Self::all();
if(count($setting)<1)
{
$arrayName = array();
$arrayName['id']= 1;
foreach(config("app.languages") as $key => $language)
{
$arrayName[$key]['name'] = $language;
$arrayName[$key]['description'] = $language;
}
Self::create($arrayName);
}
return $setting = Self::where('id','1')->first();
}
}
It looks like you are using version 4 of laravel-activitylog, in that case you should add:
use Spatie\Activitylog\LogOptions;
And the getActivitylogOptions() method, for example:
public function getActivitylogOptions()
{
return LogOptions::defaults()
-> logOnly(['text'])
-> logOnlyDirty()
-> dontSubmitEmptyLogs();
}
If you are using PHP 8 do not forget to also declare the return type:
public function getActivitylogOptions(): LogOptions
{
return LogOptions::defaults();
}
More info here: https://spatie.be/docs/laravel-activitylog/v4/advanced-usage/logging-model-events
For the format you are using in your code to work, you can also use the previous version, indicating in composer:
"spatie/laravel-activitylog": "^3", and following this documentation: https://spatie.be/docs/laravel-activitylog/v3/introduction

i wanna do php artisan db:seed, then i got this error " ErrorException array_merge(): Expected parameter 2 to be an array, int given"

I wanna make API Authentication Laravel Passport - Forgot and Reset Password with this source video on Youtube : https://www.youtube.com/watch?v=F9Xmc3iHc88&t=6s
My source Youtube use Laravel 6x, and i use Laravel 8x.
When i do step "seeding and factory database" in minute video 8:17 , i got
ErrorException array_merge(): Expected parameter 2 to be an array, int given
This is my error cmd
this is my UserFactory.php :
<?php
namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
use App\Models\User;
class UserFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* #var string
*/
protected $model = User::class;
/**
* Define the model's default state.
*
* #return array
*/
public function definition()
{
return [
'first_name' => $this->faker->firstName,
'last_name' => $this->faker->lastName,
'email' => $this->faker->unique()->safeEmail,
'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
];
}
}
this is my UsersTableSeeder.php :
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use App\Models\User;
class UsersTableSeeder extends Seeder
{
/**
* Run the database seeds.
*
* #return void
*/
public function run()
{
User::factory(App\Models\User::class, 10)->create();
}
}
and my DatabaseSeeder.php :
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
/**
* Seed the application's database.
*
* #return void
*/
public function run()
{
$this->call(UsersTableSeeder::class);
}
}
Can someone help me to explain why i got this error merge array?
Case Closed guys, in Laravel 8x u dont need type "
User::factory(App\Models\User::class, 10)->create();
just type :
User::factory(10)->create();
because u already call it User at first word..

Yii: change active record field names

I'm new to Yii and I have a table 'Student' with fields like 'stdStudentId', 'stdName', etc.
I'm making API, so this data should be returned in JSON. Now, because I want field names in JSON to just be like 'id', 'name', and I don't want all fields returned, i made a method in the model:
public function APIfindByPk($id){
$student = $this->findByPk($id);
return array(
'id'=>$student->stdStudentId,
'name'=>$student->stdName,
'school'=>$student->stdSchool
);
}
The problem is, stdSchool is a relation and in this situation, $student->stdSchool returns array with fields like schSchoolId, schName, etc. I don't want fields to be named like that in JSON, and also I don't want all the fields from School returned and I would like to add some fields of my own. Is there a way to do this in Yii, or I'll have to do it manually by writing methods like this?
I have been looking for the same thing. There is a great php lib named Fractal letting you achieve it: http://fractal.thephpleague.com/
To explain briefly the lib, for each of your models you create a Transformer that will be doing the mapping between your model attributes and the ones that need to be exposed using the api.
class BookTransformer extends Fractal\TransformerAbstract
{
public function transform(Book $book)
{
return [
'id' => (int) $book->id,
'title' => $book->title,
'year' => $book->yr,
];
}
}
In the transformer you can also set the relation that this model have :
class BookTransformer extends TransformerAbstract
{
/**
* List of resources relations that can be used
*
* #var array
*/
protected $availableEmbeds = [
'author'
];
/**
* Turn this item object into a generic array
*
* #return array
*/
public function transform(Book $book)
{
return [
'id' => (int) $book->id,
'title' => $book->title,
'year' => $book->yr,
];
}
/**
* Here we are embeding the author of the book
* using it's own transformer
*/
public function embedAuthor(Book $book)
{
$author = $book->author;
return $this->item($author, new AuthorTransformer);
}
}
So at the end you will call
$fractal = new Fractal\Manager();
$resource = new Fractal\Resource\Collection($books, new BookTransformer);
$json = $fractal->createData($resource)->toJson();
It's not easy to describe all the potential of fractal in one answer but you really should give it a try.
I'm using it along with Yii so if you have some question don't hesitate!
Since you are getting the values from the database using Yii active record, ask the database to use column aliases.
Normal SQL would be something like the following :
SELECT id AS Student_Number, name AS Student_Name, school AS School_Attending FROM student;
In Yii, you can apply Criteria to the findByPK() function. See here for reference : http://www.yiiframework.com/doc/api/1.1/CActiveRecord#findByPk-detail
$criteria = new CDbCriteria();
$criteria->select = 'id AS Student_Number';
$student = Student::model()->findByPk($id, $criteria);
Note that in order to use a column alias like that, you will have to define a virtual attribute Student_Number in your Student{} model.
Override the populateRecord() function of ActiveRecord can achieve this!
My DishType has 5 properties and override the populateRecord function Yii would invoke this when records fetched from db.
My code is here!
class DishType extends ActiveRecord
{
public $id;
public $name;
public $sort;
public $createTime;
public $updateTime;
public static function populateRecord($record, $row)
{
$pattern = ['id' => 'id', 'name' => 'name', 'sort' => 'sort', 'created_at' => 'createTime', 'updated_at' => 'updateTime'];
$columns = static::getTableSchema()->columns;
foreach ($row as $name => $value) {
$propertyName = $pattern[$name];
if (isset($pattern[$name]) && isset($columns[$name])) {
$record[$propertyName] = $columns[$name]->phpTypecast($value);
}
}
parent::populateRecord($record, $row);
}
}

Creating Dynamic attributes for Mongo Collection - YII Framework

I am trying to create dynamic model class for Mongo Collection and populate data in Cgridview (using YIIMongodbsuite extension)
Getting Column from MySQL DB:
$sql="SELECT name FROM CRM_Field Where crm_base_contact_id = ".$base;
$names =Yii::app()->db->createCommand($sql)->query()-> readAll();
Accessing Model in view:
$cc = new ContactCollection($names);// Passing dynamic column names to Model
$criteria = new EMongoCriteria;
$criteria->crm_base_contact_id('==', $base);
$cc->setDbCriteria($criteria);
CgridView Code:
<?php $this->widget('zii.widgets.grid.CGridView', array(
'id' =>'BCImported-grid',
'dataProvider' => $cc->search(false),
'columns' => $names,
)); ?>
ContactCollection Model :
<?php
class ContactCollection extends EMongoDocument
{
public $dyn_fields;
public function __construct ($names) {
$this->dyn_fields = $names;
}
public function getCollectionName()
{
return 'cartoons';
}
/**
* #return array validation rules for model attributes.
*/
public function rules()
{
$allMembers = implode(', ', array_keys($this->dyn_fields));
return array(
array($allMembers, 'required'),
);
}
public function attributeLabels()
{
return $this->dyn_fields;
}
}
I am getting this error " Property "ContactCollection.0" is not defined."
You don't need the "attributeLabels()" method in that case since each attribute should have an associated value. If you don't set that method, Yii will use the property name as the label itself.