Laravel Faker Factory Relationship - php

I have two factories one for categories and another for products. When I run the factory I want to create x number of products for each category generated. how would I write the code to product this?
the definition for the categories is written as this:
return [
'name' => $this->faker->word,
'slug' => Str::slug($this->faker->unique()->word, '-'),
];
and the definition for the product is written as such:
return [
'category_id' => 1, //instead of 1 the category id used i want to be random
'name' => $this->faker->word,
'slug' => Str::slug($this->faker->unique()->word, '-'),
'description' => $this->faker->paragraph,
'price' => $this->faker->randomFloat(2, 0, 10000),
'is_visible' => 1,
'is_featured' => 1
];
as you can see I hardcoded the category_id, I wasnt too sure how to have it automatically generate and create a product per category that exists. I have the factory for the category written as this, to create 10 items
Category::factory()
->count(10)
->create();
I tried this for trial and error thinking it would work but I get an error that category_id cannot be null .
Product::factory()
->has(Category::factory()->count(2))
->count(20)
->create();

$factory->define(Product::class, function (Faker $faker) {
return [
'category_id' => factory(Category::class), //instead of 1 the category id used i want to be random
'name' => $this->faker->word,
'slug' => Str::slug($this->faker->unique()->word, '-'),
'description' => $this->faker->paragraph,
'price' => $this->faker->randomFloat(2, 0, 10000),
'is_visible' => 1,
'is_featured' => 1
];
});
By setting the attribute to an instance of factory() Laravel will lazily create that model as well and automatically associate it

I am using kind of different syntax, but I think it will work / you can change it
In your Category.php model
public function products() {
return $this->hasMany(Product::class);
}
In seeder
factory(App\Category::class, 10)->create()->each(function($c) {
$c->products()->save(factory(App\Product::class)->make());
}); // each Category will have 1 product
Laravel Database Testing Relationships

You simply need to pass a CategoryFactory to category_id.
return [
'category_id' => Category::factory(),
// ...
];
You can read more about factories here: https://laravel.com/docs/8.x/database-testing#defining-relationships-within-factories

If you want to create multiple products per each created category, you can do something like this:
// CategoryProductSeeder
$categories = Category::factory(50)->create();
$categories->each(function ($category) {
$categories->products()->saveMany(
Product::factory(10)->make()
);
});

this is what worked for me since I'm using laravel 8.
product definition:
return [
'category_id' => Category::factory(),
'name' => $this->faker->word,
'slug' => Str::slug($this->faker->unique()->word, '-'),
'description' => $this->faker->paragraph,
'price' => $this->faker->randomFloat(2, 0, 1000),
'is_visible' => 1,
'is_featured' => 1
];
seeder:
Product::factory()
->has(Category::factory())->count(50)
->create();
created 50 categories and 50 products. 1 category assigned to each product.

Related

Laravel Eloquent Relationships not work with two pivot table

Hello everyone am newly in laravel and i am trying to get data.using state ID please explain me with all Model with relationship each-other with example i have tables like this
1- states table
1- id
2-name
2- cities table
1- id
2-name
3- state_cities pivot table
1-id
2-sate_id
3-city_id
4- locations table
1-id
2-name
5- city_locations pivot table
1-id
2-city_id
3-location_id
6- pincodes table
1-id
2-pincode
7- location_pincodes table
1-id
2-location_id
3-pinecode_id
And this is my Controller
$states_with_cities = $states_with_cities->load(['cities.cityName','location.locationName'])->where('id',1)->get();
$states_with_cities->transform(function($states_with_cities) {
return [
'state_id' => $states_with_cities->id,
'state_name' => $states_with_cities->name,
'cities' => $states_with_cities->cities->map(function($cities,$location) {
return [
'city_id' => $cities->city_id,
'city_name' => $cities->cityName->name,
'location' => $location->locationName->map(function($locationName) use($location) {
return [
'location_id' => $location->location_id,
'location_name' => $locationName->locationName->name
];
})
];
}),
];
});
and that is error which is am geting
"message": "Trying to get property of non-object",
"exception": "ErrorException",
"file": "D:\\xampp\\htdocs\\samudaay-backend\\app\\Http\\Controllers\\API\\PincodeController.php",
"line": 32,
$states_with_cities = $states_with_cities->load(['cities.cityName','location.locationName'])->where('id',1)->get();
$states_with_cities->transform(function($states_with_cities) {
return [
'state_id' => $states_with_cities->id,
'state_name' => $states_with_cities->name,
'cities' => $states_with_cities->cities->map(function($cities,$location) {
// Location is the 'key' of the object in the collection. So it probably will be something like '0' or '1'.
return [
'city_id' => $cities->city_id,
'city_name' => $cities->cityName->name,
'location' => $location->locationName->map(function($locationName) use($location) {
//What you actually do here is: 0->locationName->map(...). This will result in your error
return [
'location_id' => $location->location_id,
'location_name' => $locationName->locationName->name
];
})
];
}),
];
});
$location in the first map function is the key of the object it is iterating at the moment. (see: https://laravel.com/docs/5.6/collections#method-map)
So on line 32 you are trying to call a property on the key variable (which will probably be '0' or '1' or something.) As that is not an object, it will result in the error you get.
Also, trying to map the locationName property is not going to work as expected. locationName is a property and not an eloquent collection.
You should probably try it like this:
'location' => [
'location_id' => $location->location_id,
'location_name' => $location->name
];
})

Yii2 Kartik EditableColumn Dropdown Relation Returns wrong Value

I have an issue with a Gridview using kartik\grid\EditableColumn, after changing the value I am returned the wrong value for the column when it updates. I am returned the dropdown key/main table integer rather than the string contained in a linked table.
I have two tables
Leads - columns id and status_id
Related fields - model, field, related_value, related_value
The relation is based on in this case
model:"Leads",
field:"status_id",
related_id:status_id
I have the following relation in my model
public function getStatus()
{
return $this->hasOne(RelatedFields::className(), ["related_id" => "status_id"])->andOnCondition(["status.field" => "status_id", "status.model"=>"Leads"])->from(["status" => RelatedFields::tableName()]);
}
I also created the following as a test based on this link
public function getStatusValue()
{
return $this->status->related_value;
}
Here is the column code
[
'class' => 'kartik\grid\EditableColumn',
'attribute' => 'status_id',
'value'=>'status.related_value',
//'value' => function($model){ return $model->status->related_value; },
//'value' => function($model){ return $model->StatusValue; },
//'refreshGrid' => true,//Works but not nice
'vAlign'=>'middle',
'hAlign'=>'center',
'pageSummary' => true,
'readonly' => false,
'width'=>'10%',
'filter'=>Html::activeDropDownList($searchModel, 'status', ArrayHelper::map(RelatedFields::Find()->where(['model' =>"Leads","field"=>"status_id"])->all(), 'related_id', 'related_value'),['class' => 'form-control','prompt' => Yii::t('app', '')]),
'editableOptions'=> [
//'attribute'=>'status_id',
//'value'=>'status.related_value',
//'header' => 'profile',
//'format' => Editable::FORMAT_BUTTON,
'inputType' => Editable::INPUT_DROPDOWN_LIST,
'data'=> ArrayHelper::map(RelatedFields::Find()->where(['model' =>"Leads","field"=>"status_id"])->all(), 'related_id', 'related_value'),
]
],
Commented out are a number of lines in my attempts to fix the issue as well as combinations of them, however all result in the wrong value.
If for example I select the related value "New" which has a related_id 1, after the column has been updated I get the value 1 instead of "New".
When the table is first loaded/reloaded the value does show correctly.
I could reload the grid, but this seems wrong just to fix 1% of the data shown on the page.
I your model take a public variable $status_value
create an assigning value method
public function getStatusValue()(){
return $this->status_value= $this->status->related_value;
}
Now in Gridview use getStatusValueenter code heremethod with assigning value as below
use yii\helpers\Url;
$gridColumns = [
[
'class' => 'kartik\grid\EditableColumn',
'attribute' => 'status_value',
'pageSummary' => true,
'readonly' => false,
'value' => function($model){ return $model->statusValue; }, // assign value from getStatusValue method
'editableOptions' => [
'header' => 'status_value',
'inputType' => kartik\editable\Editable::INPUT_TEXT,
'options' => [
'pluginOptions' => [
]
]
],
],
];
If you follow Kartik guide, he suggest to add EditableColumnAction to better handle the editable column:
The EditableColumnAction offers a quick easy way to setup your
controller action for updating, saving and managing the EditableColumn
output from GridView. This action class extends from yii\rest\Action
and hence all properties available with yii\rest\Action are applicable
here. The basic setup of the column involves setting up the controller
action and the EditableColumn.
So you need to add an EditableColumnAction in your controller to handle the update of the model:
public function actions()
{
return ArrayHelper::merge(parent::actions(), [
'edit-lead' => [
'class' => EditableColumnAction::class,
'modelClass' => Leads::class
]
]);
}
In your GridView editable column configuration, include the above
controller action for processing the Editable within editableOptions.
For example
And in your column code you need to add the action to editableOptions property:
'editableOptions' => [
...
'formOptions' => ['action' => ['/leads/edit-lead']]
]
Now, according to the guide, you can add to your action the outputValue property:
'outputValue' => function (Leads $model) {
return $model->status->related_value;
}

Laravel 5.4 passing undefined (yet) variable to another model's table

Could you please help me to handle this.
Controller:
$ad = Ad::create([
'title' => request('title'),
'body' => request('body'),
'cat_title' => $cat->title,
'price' => request('price'),
'city' => request('city')
]);
$cat = Category::create([
'title' => request('category'),
'slug' => str_slug(request('category'), '-'),
'ad_id' => $ad->id
]);
I'm getting an error - Undefined variable: cat - obviously? Since the $cat variable is not yet defined on the time of being requested? But how could I handle this? And generally - am I doing it pretty much right?
My ad belongsTo category, and category hasMany ads.
Thank you!
You are executing your 2nd portion after the insertion of the ad so, you can wrap it inside a condition something like this.
// Execute this portion if above statement executed succesfully.
if (!empty($ad->id)) {
$cat = Category::create([
'title' => request('category'),
'slug' => str_slug(request('category'), '-'),
'ad_id' => $ad->id
]);
}

Laravel Nested Relationship on Factory for Testing

I got a problem, i have to admit i don't find any solution.
I'm actually developping some testing for functionnalities and Factories are blocking me.
First I'm trying to add with factories an Entity called "Tasklist" which contains one or many "sections" which contains one or many "actions".
I have a 3 level deep relationship.
Here are my factories:
$factory->define(\App\V2\Models\Tasklist::class, function (\Faker\Generator $faker) {
return [
'id_course' => \App\V2\Models\Program::all()->random(1)->id,
'id_event' => \App\V2\Models\Stage::all()->random(1)->id,
'id_course_rounds' => \App\V2\Models\ProgramRound::all()->random(1)->id,
'name' => $faker->word,
'display_name' => $faker->word,
'color' => 0,
'key' => str_random(16),
'auto_active' => 1,
'status' => 1,
];
});
$factory->define(\App\V2\Models\TasklistSection::class, function (\Faker\Generator $faker) {
return [
'id_tasklist' => function(){
return factory(\App\V2\Models\Tasklist::class)->create()->id;
},
'number' => 1,
'title' => $faker->word,
'text' => $faker->text(100),
'status' => 1
];
});
$factory->define(\App\V2\Models\TasklistAction::class, function(\Faker\Generator $faker) {
return [
'id_tasklists_section' => factory(\App\V2\Models\TasklistSection::class)->create()->id,
'number' => rand(1, 10),
'title' => $faker->word,
'percent' => $faker->numberBetween(0, 100),
'status' => 1
];
});
In my testing class, i'm trying to generate a tasklist with 1 section with one action. The only way i found actually was something like that:
$task = factory(Tasklist::class, 2)->create()
->each(function($t){
$t->sections()->save(factory(TasklistSection::class)->create()
->each(function($s){
$s->actions()->save(factory(TasklistAction::class)->create());
})
);
});
To this code, if I delete the second each, it works, i got 2 tasklists with each 1 sections. In fact, the each is disturbing me.
I would like to create only one tasklist, with one or several sections with one or several actions on it.
But the each only accept Collection input the save method accepts only model input and not collection.
Does somebody have an idea how to deal with that ?
One approach can be this:
create task with sections and store them in the variable and then loop through each task section and add actions to it like this:
$tasklist = factory(App\Tasklist::class)->create();
$tasklist->sections()->saveMany(factory(App\TasklistSection::class, 3)->make());
foreach ($tasklist->sections as $section){
$section->actions()->saveMany(factory(App\TasklistAction::class, 3)->make());
}
this will work as expected.

Cannot set group price on new magento products from the xml-rpc api

I'm trying to use the xmlrpc api in magento 1.9 to add a list of products to the shop. I've got creating the products working with a lot of tinkering but I cannot add rows to the "Group price" field of the product.
This is the current version of my productCreate function:
public function productCreate(MagentoProduct $product)
{
$parameters = [
'simple',
'4', // attribute set
$product->sku,
[
'website_ids' => [2, 3, 4, 7],
'category_ids' => [7],
'name' => $product->name,
'description' => $product->description,
'short_description' => $product->short_description,
'weight' => $product->weight,
'url_key' => $product->url_key,
'url_path' => $product->url_path,
'price' => $product->price,
'tax_class_id' => $product->tax_class_id,
'meta_title' => $product->meta_title,
'meta_keyword' => $product->meta_keyword,
'meta_description' => $product->meta_description,
'status' => 1,
'group_price' => [
'website_id' => 1,
'cust_group' => 2,
'price' => '100.0',
],
]
];
return $this->client->call('product.create', $parameters);
}
I've tried using tier price with qty of 0 or 1 but those are saved to the wrong table. If I retrieve some existing products through the xmlrpc api then I do get the group prices in the tier price list without any quantity but creating them that way doesn't work.
In the function above I'm setting the values in the (undocumented) group_price field. The error I'm getting now is:
'fXmlRpc\Exception\ResponseException' with message 'Dubbele website
groep prijs klantengroep.'
which translates to:
Duplicate website group price customer group.
Does anybody know the correct way of setting the group price?
It looks like magento does not support group price updates within their api.
You have to create your own api for this.
Read this:
https://magento.stackexchange.com/questions/56481/use-api-v2-to-work-with-customer-group-prices
and this
How to update group price via SOAP api

Categories