Laravel Factory Can't Save Relation - laravel

I use Laravel 5.6, and I have a problem with my seeder.
I use this :
factory(\App\Models\Merchant::class)->create([
'email' => 'admin#domain.com',
])->each(function ($m) {
$m->stores()->save(factory(\App\Models\Store::class)->create()
->each(function ($s) {
$s->products()->save(factory(\App\Models\Product::class, 10)->create());
})
);
});
All are hasMany relations.
Doing this, I have this error :
General error: 1364 Field 'merchant_id' doesn't have a default value
(SQL: insert into stores ....)
It's like my first $stores->save( ... ) doesn't use the merchant created.
In my DB, I have one merchant created.
If I use ->make() instead of ->create(), it works for the Store, but I can't save products because it's not persisted...
Is it possible to use multiple save in factories like this ?

Your code may need a little refactoring as you may be chaining creation of models incorrectly:
factory(\App\Models\Merchant::class, 2)->create([
'email' => 'admin#domain.com',
])->each(function ($m) {
$store = factory(\App\Models\Store::class)->create(['merchent_id' => $m->id]);
factory(\App\Models\Product::class, 10)->create(['store_id' -> $store->id]);
);
});
Note: In order to use the ->each() method, you need to have a collection instance. I do not think creating only one merchant will return a collection. In the example, we create 2 merchents.

Related

How do I return the ID field in a related table in Laravel request

I have two related tables and I want to return all fields including the ID (key) field. My query below returns all fields except the ID. how do I return the ID field from one of the tables?
'programmes' => ProgrammeInstances::with('programmes')->get(),
the query below returns Unknown column 'programmes.programme_title' as it is looking for it in the table 'programme_instances'
'programmes' => ProgrammeInstances::with('programmes')->select('programmes.programme_title', 'programmeInstances.id', 'programmeInstances.name', 'programmeInstances.year')->get(),
Laravel provides multiple relationships, one of these is the hasMany() relationship which should return a collection where a User hasMany rows inside of your database
For example, inside your User model :
public function programmes() {
return $this->hasMany(Program::class);
}
Now in your controller, you can do :
public function edit($id) {
$programmes = User::find($id)->with('programmes')->get();
return view('user.edit')->with('programmes', $programmes);
}
And then you can loop over it inside your view
#forelse($programmes->programmes as $program)
// provide the data
#empty
// the user doesn’t have any programmes
#endforelse
a solution i found below - still not sure why ID isnt automatically returned when i get all fields, but works when i specify individual fields:
'programmes' => ProgrammeInstances::with('programmes')
->get()
->transform(fn ($prog) => [
'programme_title' => $prog->programmes->programme_title,
'id' => $prog->id,
'name' => $prog->name,
'year' => $prog->year,
]),

Laravel 8.0 facing issue while trying to update a table with vue form, 'Attempt to read property \"item_id\" on null'

So, i have a table called Items table and another table called item_quantities, on item_quantities ive a column named item_id which is connected to items table id. All the fillable properties on both tables are all in one form on the frontend, and i take care of the form fields on the backend
Whenever i try to update the quantity on the form which is from item_quantities's table with a form, i'm facing serious issue updating the item_quantities. getting Attempt to read property "item_id" on null.
It all started when i noticed a duplicate entries on the item-quantities table, so i deleted all the datas on it..
Here's is the form screenshot
The vue form
and the backend logic
public function saveData(Request $request, $id) {
// dd($request->name);
$updateGroceries = Item::where('id', $request->id)->get()->first();
$updateGroceries->update([
'name' => $request->name,
'description' => $request->description,
'price' => $request->price,
]);
if($updateGroceries) {
$item_quantity = ItemQuantity::where('item_id', $updateGroceries->id) ?
ItemQuantity::where('item_id', $updateGroceries->id)->get()->first() :
new ItemQuantity;
if($item_quantity->item_id == null) {
$item_quantity->item_id = $updateGroceries->id;
}
$item_quantity->quantity = $request->quantity;
$item_quantity->save();
}
}
I'M SO SORRY IF MY ENGLISH WAS'NT CLEARED ENOUGH
Thanks in anticipation
You can simply use firstOrNew() method. This will first find the item, if not exist create e new instance.
$item_quantity = ItemQuantity::firstOrNew(['item_id' => $updateGroceries->id]);
$item_quantity->quantity = $request->quantity;
$item_quantity->save();
Note that the model returned by firstOrNew() has not yet been persisted to the database. You will need to manually call the save method to persist it.
Actually your errors workflow as that:
$item_quantity=null;
$item_quantity->item_id;
You can do that with optional global helper:
optional($item_quantity)->item_id ?: 'default value';

How does Laravel generate SQL?

I'm brand new to Laravel and am working my way through the Laravel 6 from Scratch course over at Laracasts. The course is free but I can't afford a Laracasts membership so I can't ask questions there.
I've finished Section 6 of the course, Controller Techniques, and am having unexpected problems trying to extend the work we've done so far to add a few new features. The course has students build pages that let a user show a list of articles, look at an individual article, create and save a new article, and update and save an existing article. The course work envisioned a very simple article containing just an ID (auto-incremented in the database and not visible to the web user), a title, an excerpt and a body and I got all of the features working for that. Now I'm trying to add two new fields: an author name and a path to a picture illustrating the article. I've updated the migration, rolled back and rerun the migration to include the new fields and got no errors from that. (I also ran a migrate:free and got no errors from that.) I've also updated the forms used to create and update the articles and added validations for the new fields. However, when I go to execute the revised create code, it fails because the SQL is wrong.
The error message complains that the author field doesn't have a default, which is true, I didn't assign a default. However, I did give it a value on the form. What perplexes me most is the SQL that it has generated: the column list doesn't show the two new columns. And that's not all: the values list is missing apostrophes around any of the string/text values. (All of the columns are defined as string or text.)
As I said, I'm completely new to Laravel so I don't know how to persuade Laravel to add the two new columns to the Insert statement nor how to make it put apostrophes around the strings in the values list. That hasn't come up in the course and I'm not sure if it will come up later. I was hoping someone could tell me how to fix this. All of my functionality was working fine before I added the two new fields/columns.
Here is the error message:
SQLSTATE[HY000]: General error: 1364 Field 'author' doesn't have a default value (SQL: insert into `articles` (`title`, `excerpt`, `body`, `updated_at`, `created_at`) values (Today in Canada, The ideal winter-beater, This car is the ideal winter-beater for the tough Canadian climate. It is designed to get you from A to B in style and without breaking the bank., 2020-02-15 17:37:54, 2020-02-15 17:37:54))
Here is ArticlesController:
<?php
namespace App\Http\Controllers;
use App\Article;
use Illuminate\Http\Request;
class ArticlesController extends Controller
{
public function index()
{
$articles = Article::latest()->get();
return view ('articles.index', ['articles' => $articles]);
}
public function show(Article $article)
{
return view('articles.show', ['article' => $article]);
}
public function create()
{
return view('articles.create');
}
public function store()
{
//Stores a NEW article
Article::create($this->validateArticle());
return redirect('/articles');
}
public function edit(Article $article)
{
return view('articles.edit', ['article' => $article]);
}
public function update(Article $article)
{
//Updates an EXISTING article
$article->update($this->validateArticle());
return redirect('/articles/', $article->id);
}
public function validateArticle()
{
return request()->validate([
'title' => ['required', 'min:5', 'max:20'],
'author' => ['required', 'min:5', 'max:30'],
'photopath' => ['required', 'min:10', 'max:100'],
'excerpt' => ['required', 'min:10', 'max:50'],
'body' => ['required', 'min:50', 'max:500']
]);
}
public function destroy(Article $article)
{
//Display existing record with "Are you sure you want to delete this? Delete|Cancel" option
//If user chooses Delete, delete the record
//If user chooses Cancel, return to the list of articles
}
}
Is there anything else you need to see?
It may be possible because of you don't have defined that column in fillable property, to use mass assignment you have to specify that columns.
Try after adding that columns in fillable property.
Laravel mass assignment
Hope this helps :)

Create a factory that doesn't return anything - Laravel

Intro
Hello everyone,
Recently I've picked Laravel and I'm still learning about the framework (which by the way I find amazing).
I'm working on a project in where i have a model called Order which I use for grouping other Order models (for example ClassicOrder, InstantOrder etc...) by using a one-to-one morph relationship.
The Orders table store an id, an order_id and the order_type which is used for the morph relationship.
The Problem
I've made a factory for each Order type and now I want to create a factory that generates n orders by randomly picking between all the order types.
I've done it like this:
$factory->define(Order::class, function (Faker $faker) {
$className = collect(Order::getModels())->random();
$order = factory($className)->create();
return [
'order_id' => $order->id,
'type' => get_class($order)
];
});
Now, this is working but the problem is that each order use a trait called Order which already register the order in the orders table so when I call the factory I'll get two rows in the order table for the same order.
This is the order trait:
Trait Order {
public static function boot()
{
parent::boot();
self::created(function ($model) {
// Add the order to the orders table to give him a public id
DB::table('orders')->insert(['order_id' => $model->id, 'type' => self::class]);
// Set and create the order path if the order isn't instant
if (!is_a($model, 'App\InstantOrder')) {
$orderType = explode('\\', get_class($model))[1]; // App\OrderType -> OrderType
$folderName = $orderType . '_' . $model->publicId . '_' . time() . '/';
$model->path = public_path() . '/storage/orders/' . $folderName;
$model->save();
File::makeDirectory($model->path, 0777, true);
}
});
self::creating(function ($model) {
$model->{$model->getKeyName()} = Uuid::generate()->string;
});
}
}
I can avoid this by calling factory()->make() instead of factory->create() but this doesn't seem right to me.
The Question
I've thought about some solutions and I've come out with the followings:
- Don't make the factory return anything, but looks like I can't.
- Delete the inserted rows before returning the data to store in the Orders table, and even if not really great, it looks like the only solution.
Can I make a factory without returning anything?
Thanks and wish a great day to everyone.
-Riccardo
Well lemme first welcome you, and then ask who said it wasn't a a good idea to make a factory that return anything, as it's mentioned in Laravel docs that's how it's written:-
use Illuminate\Support\Str;
use Faker\Generator as Faker;
$factory->define(App\User::class, function (Faker $faker) {
return [
'name' => $faker->name,
'email' => $faker->unique()->safeEmail,
'email_verified_at' => now(),
'password' => '$2y$10$TKh8H1.PfQx37YgCzwiKb.KjNyWgaHb9cbcoQgdIVFlYg7B77UdFm', // secret
'remember_token' => Str::random(10),
];
});
As mentioned Here
And then you can use it in Model factories as mentioned Here
I guess that's best practice as the Documentation says i guess.
And this is also a quick intro that you should check out for seeding data with Relationships

User::all show relationship items

I Laravel 5.5 I am returning users information like this...
$users = User::all();
return Response::json(array(
'error' => false,
'response' => $users,
));
I have a belongs to many categories relationship setup and would like to also show all of the categories each user belongs to.
Anyone have an example I can see?
Use the with() method to load categories for each user:
$users = User::with('categories')->get();
If you don't need to load all the columns from the categories table, use select() inside the with() closure. Also, since you're using Laravel 5.5 you could use Resource classes for formatting JSON.

Resources