if I have a model Student and it has three properties:
name
age
classroom_id
name and age are in fillable array.
So if I want to create a new student and assign his/her classroom_id, I have to do this:
$student = App\Student::create(
[
'name'=>$request->input('name'),
'age'=>$request->input('age')
]
);
$student->classroom_id = 1;//for example
$student->save();
is this right? And if this is right, actually I do insert action twice, right?
You can just update your $fillable array inside your model to include classroom_id and it will become mass assignable, meaning you don't need to do two inserts to get all the data in there.
As such, your $fillable array will look similar to this:
protected $fillable = ['name', 'age', 'classroom_id'];
And your create method similar to this:
$student = App\Student::create(
[
'name' => $request->input('name'),
'age' => $request->input('age'),
'classroom_id' => 1
]
);
This is the correct way, rather than running your insert twice which is unnecessary.
Related
I'm sure I'm doing something wrong but can't figure out what it is.
In a controller I have a method which executes:
$estimate = Estimate::create(
['session_id' => 'test']
);
Model:
use HasFactory;
protected $fillable = ['width, height, direction_id, media_id, coating_id, shape_id, amount, qty, session_id'];
Estimate is related to estimates in my db.
When triggered an estimate record is created but the field 'session_id' is blank.
session_id is a VARCHAR 191.
Any idea why this is happening?
You define your $fillable wrong. It should be an array of strings:
protected $fillable = [
'width',
'height',
'direction_id',
'media_id',
'coating_id',
'shape_id',
'amount',
'qty',
'session_id',
];
I have a table with columns like "name", "surname", "user_id", and I need to check if entry exists first by id, and then by name and surname together, if there is none, create it. How do I do it neatly, instead of making two update statements, and if both return 0 just create a new one (which seems too bulky)
I thought of using firstOrNew, but it seems that it only can work while matching all of the parameters.
Is there any method I've missed that would apply well to my situation?
You could try something like this (assuming you want to create a model [saved to the database]):
$attributes = [
'name' => ...,
'surname' => ...,
];
$model = Model::where('id', $id)
->orWhere(fn ($q) => $q->where($attributes))
->firstOr(fn () => Model::create($attributes));
This would search for a record by id OR name and surname. If it doesn't find one it will create a new record with the name and surname (assuming those attributes are fillable on the Model).
Laravel 8.x Docs - Eloquent - Retrieving Single Models / Aggregates firstOr
In laravel if i want to insert all the form input and i want to add text in one of the column why cant i use this code?
Example
$B2 = new B2;
$B2::create([
request()->all(),
$B2->column9 = "aaaa",
]);
The inserted database only insert column9, the other column is Null.
Because create() accepts an array as the only parameter:
public static function create(array $attributes = [])
You can do this:
$data = request()->all();
$data['column9'] = 'aaaa';
B2::create($data);
When ever you use request all you must first make sure that you have either fillable fields in your model or guarded = to an empty array so for example:
class B2 extends Model
{
protected $table = 'db_table';
protected $fillable = [
'email',
'name',
];
}
or you can use
protected $guarded = [];
// PLEASE BE CAREFUL WHEN USING GUARDED AS A POSE TO FILLABLE AS IT OPENS YOU TO SECURITY ISSUES AND SHOULD ONLY REALLY BE USED IN TEST ENVIRONMENTS UNLESS YOU REALLY KNOW WHAT YOU ARE DOING!
As for your create method you should make sure its an associative array like this:
$B2::create([
$B2->column9 => "aaaa",
]);
Or you could do something like:
$data = $request->except('_token');
$B2::create($data);
You'll have to merge the array.
$B2::create(array_merge(request()->all(), ['column9' => 'text']));
When you are adding to a database in that was it is called mass assignment. Laravel Automatically protects against this so you need to add the firld names to a fillable attribute in your model
protected $fillable = ['field1', 'column9'] //etc
https://laravel.com/docs/5.4/eloquent#mass-assignment
You also need to make sure you pass an array to the create method
$my_array = $request->all()
$my_array['column9'] = 'aaaa';
$B2::create(
$my_array
);
I'm trying to retrieve data from database and bind them to a html select tag, and to bind them i need to use pluck so i get the field i want to show in a array(key => value), because of FORM::select. The normal pluck gets all the results, while i want to use distinct. My model is Room and it looks like:
class Room extends Eloquent
{
public $timestamps = false;
protected $casts = [
'price' => 'float',
'floor' => 'int',
'size' => 'float'
];
protected $fillable = [
'capacity',
'description',
'price',
'floor',
'size',
'type',
'photo_name'
];
}
While my function I'm using in the controller look like:
public function getRooms()
{
$roomType = Room::pluck('type','type');
$roomFloor = Room::pluck('floor','floor');
return view('roomgrid')->with('type',$roomType)->with('floor',$roomFloor);
}
And my view contains this piece of code to get floors:
{{FORM::select('floor', $floor, null,['class'=>'basic'])}}
Like this i get duplicated floors, that i don't want. Is there any way so i can get distinct floors and pluck them? Thanks in advance.
Why not use groupBy()?
$roomType = Room::groupBy('type')->pluck('type','type');
Room::unique('floor')->pluck('floor', 'floor');
distinct can do the trick:
Room::query()->distinct()->pluck('type');
Which will be translated into the following SQL:
SELECT DISTINCT type FROM rooms
2019 Update
You don't need to use 2 arguments with pluck()
simply do:
$roomType = Room::groupBy('type')->pluck('type');
of course for getting it into array:
$roomType = Room::groupBy('type')->pluck('type')->toArray();
Sometimes I use the result for whereIn clause, its useful for that.
you can do this
$roomType = Room::pluck('type')->unique();
$roomFloor = Room::pluck('floor')->unique();
You can use KeyBy or pluck with same key-Value pair to pick Distinct Values.
PHP array can only have unique keys.From this Idea we can get Unique models based on Array key.
Room::keyBy('floor')->pluck('floor');
or
Room::pluck('floor', 'floor');
I have a CMS that allows the user to save and create bike tours. Each bike tour also has categories, which are definined using Laravel's Many to Many relationship utilising an intermediary pivot table. At the point of saving a tour, we don't know if the tour is an existing one being edited, or a new one.
I think I should be using Laravel's firstOrNew method for saving the tour, and the sync method for saving categories. However, all the tutorials very simplistically just give the example of passing a single object to the function like so:
$tour = Tour::firstOrNew($attributes);
But what happens when my $attributes also contains extra stuff, like the categories which are linked to a relationship table, and which I will need to save in the next step? For example this very good tutorial gives the following example:
$categories = [7, 12, 52, 77];
$tour = Tour::find(2);
$tour->categories()->sync($categories);
But what happens if the category data is bundled with the data for the rest of the tour, and instead of using find I need to use firstOrNew to create the tour? Should I keep the categories in the $attributes while I instantiate the tour, then run the sync, then unset them before saving the tour, or...? Is there a better way to achieve this?
EDIT: To be clear, the $attributes variable in my example here is essentially the tour object data bundled together- just as the Laravel/Eloquent system would return it from the transaction using the belongsToMany method- with subequent modifications from the user). ie: here is a snapshot of what it contains:
array (
'id' => 1,
'uid' => '03ecc797-f47e-493a-a85d-b5c3eb4b9247',
'active' => 1,
'code' => '2-0',
'title' => 'Tour Title',
'url_title' => 'tour_title',
'distance_from' => 20,
'distance_to' => 45,
'price_from' => '135.00',
'price_to' => '425.00',
'created_at' => '2013-12-31 15:23:19',
'updated_at' => '2015-07-24 16:02:50',
'cats' => // This is not a column name!
array (
0 => 1,
1 => 7
),
)
All of these attributes are column names in my tours table, other than cats, which references another table via a hasMany relationship. Do I need to unset it manually before I can set this object class and save it with $tour->save?
I am looking for the cleanest most Laravel way to do it?
EDIT2: Here is the relationship defined in the Tours model:
class Tour extends Model
{
protected $guarded = [];
public function cats(){
return $this->belongsToMany('App\TourCategory', 'tour_cat_assignments', 'tour_id', 'cat_id');
}
}
you need to define $fillable property of your Tour model to tell eloquent which attributes to consider when using mass assignment so it will ignore categories related attributes silently. for ex.
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Tour extends Model {
protected $fillable = ['name'] //... other attributes which are part of this model only and laravel will consider only these attributes and ignore category related attributes which you can consider later use.
}
You can use firstOrCreate. The data actually gets persisted using this method.
$categories = [7, 12, 52, 77];
$tour = Tour::firstOrCreate($attributes)->cats()->sync($categories);
Got to make sure the fields are mass-assignable to be able to use the firstOrCreate method though. So either set the fieldnames in the $fillable property or put this in the Tour model:
protected $guarded = [];
Since you have mentioned "CMS" and "subsequent modifications from user", I guess that you are getting your attributes from a Form which means you are getting a Request object/collection.
If that is the case then you can try
$tour = Tour::firstOrCreate($request->except('cats'));
$categories = [];
foreach($request->get('cats') as $key=>$value){
$categories[] = $value;
}
$tour->cats()->sync($categories);
However, if your $attributes us constructed as an array (probably with some manipulations on form data) as per your EDIT then in that case you may try:
$tour = Tour::firstOrCreate(array_except($attributes, ['cats']);
$categories = [];
foreach($attributes['cats'] as $key=>$value){
$categories[] = $value;
}
$tour->cats()->sync($categories);
In any case, you must have the mass assignable fields declared in $fillable property in your model i.e. Tour.
Hope this helps.