how to save multiple dropdownlist yii2 - drop-down-menu

I'm trying to save multiple data from a dropdownlist, I have 2 tables Asistencia and Mecanico in the table Asistencia i have this in the _form
<?php
echo $form->field($model, 'mecanico_id[]')
->dropDownList(ArrayHelper::map(Mecanico::find()->all(), 'id_mecanico', 'nombre'),
[
'multiple'=>'multiple',
'class'=>'chosen-select input-md required',
]
)->label("Mecanicos");
?>
i know if i want to save multiple data i have to change in controllers-> actionCreate/Update but i dont know how. Here is my actionCreate
public function actionCreate()
{
$model = new Asistencia();
if ($model->load(Yii::$app->request->post()) && $model->save()) {
return $this->redirect(['view', 'id' => $model->id_asistencia]);
}
return $this->render('create', [
'model' => $model,
]);
}
I need sample controller code explaining how to save multiple items from a drop down list to the database, as well as update the list of saved items. Thanks.
here is my table of Asistencia
Asistencia table
Table of Mecanico
Mecanico table
and the relation of those 2 table
enter image description here

For example you have Product and Category many to many relation.
In your Product model,
Declare field:
public $categories_ids;
Put it in 'safe' in rules():
[['categories_ids'], 'safe']
3.Declare AfterSave function:
public function afterSave($insert, $changedAttributes) {
// If this is not a new record, unlink all records related through relationship 'categories'
if(!$this->isNewRecord) {
// We unlink all related records from the 'categories' relationship.
$this->unlinkAll('categories', true);
// NOTE: because this is a many to many relationship, we send 'true' as second parameter
// so the records in the pivot table are deleted. However on a one to many relationship
// if we send true, this method will delete the records on the related table. Because of this,
// send false on one to many relationships if you don't want the related records deleted.
}
foreach($this->categories_ids as $category_id) {
// Find and link every model from the array of ids we got from the user.
$category = Category::findOne($category_id);
$this->link('categories', $category);
}
parent::afterSave($insert, $changedAttributes);
}
Decare AfterFind function():
public function afterFind(){
parent::afterFind();
$this->categories_ids = ArrayHelper::getColumn($this->categories, 'id');
}
Declare relation:
public function getCategories() {
return $this->hasMany(Category::className(), ['id' => 'category_id'])->viaTable('product_category', ['product_id' => 'id']);
}
I hope it will help to you.

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,
]),

How to create data into junction table many to many relationship without create data into the junction point to

It inserts both table inside tags and tagables, what i want is just to insert into tagables ( junction ) table. Cause before it insert into tagables, theres code to check first if tag will insert into tags table already exist or not, if exist just grab the id. To make it simple to my problem. i just don't include code to check if tags is exist or not.
post model
public function tags(){ return $this->morphToMany( Tag::class, 'tagable', 'tagables', null, 'tag_id ); }
post controller
// tags table theres a row id 1 with name greeting
$post = Post::create( ['body' => 'Hello World'] );
$post->tags()->create( ['tag_id' => 1] );
Tables
// posts table
$table->mediumIncrements('post_id');
$table->string('body');
// tags table
$table->mediumIncrements('tag_id');
$table->string('tag_name');
//tagables table
$table->unsignedMediumInteger('tag_id');
$table->unsignedMediumInteger('tagable_id');
$table->string('tagable_type');
I think the simplest way do this to start by creating the tag with the eloquent method 'firstOrCreate', and then when you already have a new tag or existing tag you can add this tag to a new Post. The code may look like something like this:
class Tag extends Model
{
protected $guarded = [];
public function posts()
{
return $this->morphedByMany(Post::class, 'taggable');
}
}
$tag = Tag::firstOrCreate(
['tag_name' => 'traveling'],
);
$post = $tag->posts()->create([
'body' => 'My new interesting post',
]);

Eloquent relationship: return just one value not entire row

In my laravel project I built a comment section and want to display the names of the people commenting beside their comment.
Initially I have just the userID, so I built a relationship (hasOne) linking the comment table (comment & authorID) to the users table (id (authorID) & username)
Comment.php (model) is:
[..]
public function author()
{
return $this->hasOne(User::class, 'id', 'Author');
}
The User.php model is:
<?php
[..]
public function author()
{
return $this->hasMany(Comment::class, 'Author', 'id');
}
In the controller I get the data with:
$comments= Comments::where('LinkID', (string) $id)->with('author')->orderBy('updated_at', 'ASC')->get()->all();
This works but it gives me the entire row of the user per comment. For security reasons I just want to return the 'name' field of the row (username) without the rest (email, timestamps etc.).
How can I achieve this?
please try:
$comments= Comments::where('LinkID', (string) $id)->with(['author' => function ($q) {
$q = $q->select('name', 'id');
return $q;
}
])->orderBy('updated_at', 'ASC')->get()->all();
or another way:
$comments= Comments::where('LinkID', (string) $id)->with('author:id,name')->orderBy('updated_at', 'ASC')->get()->all();
see eager loading (section Eager Loading Specific Columns)
https://laravel.com/docs/7.x/eloquent-relationships#eager-loading
note that including 'id' is necessary because it 's responsible for the relation

How to make shortest code?

I use the following code to insert multi array to database:
foreach($request->category as $k => $v){
$category[] = array(
"category_id" => $v,
"announcement_id" => $announcement->id
);
}
AnnouncementCategory::insert($category);
So, input data is POST array $request->category.
I need to refactoring this code
I tried this code:
$announcement->categories()->attach($request->category);
In model Announcement I have:
public function categories()
{
return $this->hasMany("App\AnnouncementCategory", "announcement_id", "id");
}
If you define in your Announcement model relationship like this:
public function categories()
{
return $this->belongsToMany(AnnouncementCategory::class);
}
you can do it like this:
$announcement->categories()->attach($request->category);
EDIT
I see you updated your question and added categories relationship. But looking at your code, AnnounceCategory is rather pivot table, so you should use belongsToMany as I showed instead of hasMany
You can do it in one line if the request matches the columns:
AnnouncementCategory::insert($request->all());
Then in your AnnouncementCategory model, make sure you declare the protected $fillable array where you specify which field could be populated.

UpdateExistingPivot for multiple ids

In order to update single record in pivot table I use updateExistingPivot method. However it takes $id as the first argument. For example:
$step->contacts()->updateExistingPivot($id, [
'completed' => true,
'run_at' => \Carbon\Carbon::now()->toDateTimeString()
]);
But how can I update multiple existing rows in pivot table at once?
There's an allRelatedIds() method in the BelongsToMany relation that you can access, which will return a Collection of the related model's ids that appear in the pivot table against the initial model.
Then a foreach will do the job:
$ids = $step->contacts()->allRelatedIds();
foreach ($ids as $id){
$step->contacts()->updateExistingPivot($id, ['completed' => true]);
}
You can update only by using a looping statement as there updateExistingPivot function only accept one dimensional params, See the core function for laravel 5.3.
File: yoursite\vendor\laravel\framework\src\Illuminate\Database\Eloquent\Relations\BelongsToMany.php
Function: updateExistingPivot
public function updateExistingPivot($id, array $attributes, $touch = true)
{
if (in_array($this->updatedAt(), $this->pivotColumns)) {
$attributes = $this->setTimestampsOnAttach($attributes, true);
}
$updated = $this->newPivotStatementForId($id)->update($attributes);
if ($touch) {
$this->touchIfTouching();
}
return $updated;
}
So, You should follow the simple process:
$step = Step::find($stepId);
foreach(yourDataList as $youData){
$step->contacts()->updateExistingPivot($youData->contract_id, [
'completed' => true,
'run_at' => \Carbon\Carbon::now()->toDateTimeString()
]);
}

Resources