get many to many values and which of them are selected in laravel - laravel

Contacts:
id
name
Tags:
id
name
ContactTags:
contact_id
tag_id
In Contacts model:
public function tags()
{
return $this->belongsToMany(Tags::class, "contacts_tags", "contact_id", "tag_id");
}
So if I do
$contact = Contacts::findOrFail($id);
dd($contact->tags);
I successfully get the tags associated with the contact. But how can I get all tags and a flag indicating which one of those is associated?
I'm trying to prevent fetching all tags, loop them and with each iteration loop all contact_tags and check if tag_id matches. I want to display a list of checkboxes with all tags and check the ones that are in the relation.

This code can help you, but I'm using the SELECT multiple component. You can easily adapt it to use the CHECKBOX component.
Contacts model:
public function tags()
{
return $this->belongsToMany(Tags::class, "contacts_tags", "contact_id", "tag_id");
}
ContactController.php
public function edit(Contact $contact)
{
$tags = Tag::all();
return view('contacts.edit',compact('contact', 'tags'));
}
edit.blade.php
<div class="row">
<div class="col">
<div class="form-group">
<strong>Tags:</strong>
<select name="tags_id[]" multiple>
#foreach ($tags as $tag)
#if( $contact->tags->contains($tag) )
<option value="{{ $tag->id }}" selected>{{ $tag->name }}</option>
#else
<option value="{{ $tag->id }}">{{ $tag->name }}</option>
#endif
#endforeach
</select>
</div>
</div>
</div>
Update in ContactController.php
public function update(Request $request, Post $contact)
{
$validatedData = $request->validate([
'tags_id' => ['array'],
]);
$contact->update($request->all());
$contact->tags()->sync($validatedData['tags_id']);
return redirect()->route('contact.index')->with('success', 'Contact successfully updated!');
}
The validation is just an example. The $validatedData has no use here, but it can be used to update the contact if you validate the other fields.

Related

Insert a Form value from a select in a dynamic url

While using laravel to create a movie catalog, I am trying to extract the value from an HTML Form and insert it in the URL.
The objective is that, from the main page which is:
http://127.0.0.1:8000/index/
I want it to extract an ID value from the form and insert it in the url:
http://127.0.0.1:8000/index/1
http://127.0.0.1:8000/index/2
http://127.0.0.1:8000/index/3
As each one is a dynamic view that will display each movie information from the database.
The form is already recognizing the ids and is displaying them in the select form in page, but I am not able to have that value used to insert it in the url as shown above.
Please help me, here is my code:
index.blade.php
<form action=" WHAT TO PLACE HERE??? " method="POST">
#csrf
<select name="selector">
<option value="" disabled selected> --- ID --- </option>
#foreach($movies as $movie)
<option value="{{ $movie->id }}">{{ $movie->id }}</option>
#endforeach
</select>
<button>Buscar</button>
</form>
web.php
Route::get('/index', 'App\Http\Controllers\MovieController#index');
Route::get('/index/create','App\Http\Controllers\MovieController#create');
Route::post('/index','App\Http\Controllers\MovieController#store');
Route::get('/index/{id}','App\Http\Controllers\MovieController#show');
Route::delete('/index/{id}','App\Http\Controllers\MovieController#destroy');
MovieController.php
class MovieController extends Controller
{
public function index() {
$movies = Movie::all();
return view('movies.index', ['movies' => $movies,]);
}
public function show($id) {
$movie = Movie::findOrFail($id);
return view('movies.show', ['movie' => $movie]);
}
public function create() {
return view('movies.create');
}
public function store(){
$movie = new Movie();
$movie->title = request('title');
$movie->synopsis = request('synopsis');
$movie->year = request('year');
$movie->cover = request('cover');
$movie->save();
return redirect('/')->with('mssg','La pelĂ­cula a sido registrada');
}
public function destroy($id) {
$movie = Movie::findOrFail($id);
$movie->delete();
return redirect('/index/');
}
}
Replace you form as:
index.blade.php
<form action="" method="POST" id="form_id">
#csrf
<select name="selector" id="selector">
<option value="" disabled selected> --- ID --- </option>
#foreach($movies as $movie)
<option value="{{ $movie->id }}">{{ $movie->id }}</option>
#endforeach
</select>
<button type="submit">Buscar</button>
</form>
Add script after this :
<script>
$('#selector').change(function(){
var selected_value = $(this).val();
$('#form_id').attr('action', 'http://127.0.0.1:8000/'+selected_value);
});
</script>
This will set your action dynamic as per selection with your select tag

How to build conditional list of dropdown options in Laravel Voyager

I have a problem with Laravel Voyager v1.2. I need to filter list of related list of options in select dropdown easily by where condition. So let's say I have Post with relation to Category, but I don't want to list all Categories in select dropdown, but just that active ones.
I tried to force Voyager to take my own method to build an relationship in Post model:
public function category_id() {
return $this->belongsTo('Post::class')->where('active',1);
}
Also tried to define scope in BREAD JSON options for the category field:
{
"relationship": {
"key": "id",
"label": "name",
"scopes": [
"active"
]
}
}
Post Model part:
public function scopeActive($query) {
return $query->where('active', 1);
}
This is how my Post class look like (I don't actualy need to filter active categories, but food categories by it's IDs):
public function soup1() {
return $this->belongsTo('App\Meal')->where('meal_category_id',1);
}
public function soup2() {
return $this->belongsTo('App\Meal')->where('meal_category_id',1);
}
public function mealy() {
return $this->belongsTo('App\Meal')->where('meal_category_id',7);
}
public function scopeSoups($query)
{
return $query->where('meal_category_id', 1);
}
public function scopeMealy($query)
{
return $query->where('meal_category_id', 7);
}
I want to receive filtered list of options instead of all model rows.
You can do this easily by overriding the blades in voyager:
Step 1 :
Copy relationship.blade.php
from: /"YourProject"/vendor/tcg/voyager/resources/views/formfields/relationship.blade.php
To: /"YourProject"/resources/views/vendor/voyager/formfields/relationship.blade.php
This way voyager will use this file in your your project views instead of the package file in the vendor.
Read More: Voyager Documentations
Step 2 :
In the line 25 of relationship.blade.php you'll see this block of code:
<select
class="form-control select2-ajax" name="{{ $options->column }}"
data-get-items-route="{{route('voyager.' . $dataType->slug.'.relation')}}"
data-get-items-field="{{$row->field}}"
>
#php
$model = app($options->model);
$query = $model::where($options->key, $dataTypeContent->{$options->column})->get();
#endphp
#if(!$row->required)
<option value="">{{__('voyager::generic.none')}}</option>
#endif
#foreach($query as $relationshipData)
<option value="{{ $relationshipData->{$options->key} }}" #if($dataTypeContent->{$options->column} == $relationshipData->{$options->key}){{ 'selected="selected"' }}#endif>{{ $relationshipData->{$options->label} }}</option>
#endforeach
</select>
Which you should override it with this:
#if($options->table == 'categories')
<div class="ap-form-input">
#php
$model = app($options->model);
$query = $model::where('active', true)->get();
#endphp
<select class="form-control select2" id="language-select" name="{{ $options->column }}">
#if(!$row->required)
<option value="">{{__('voyager::generic.none')}}</option>
#endif
#foreach($query as $relationshipData)
<option value={{ $relationshipData->{$options->key} }} #if($dataTypeContent->{$options->column} == $relationshipData->{$options->key}){{ 'selected="selected"' }}#endif>{{ $relationshipData->{$options->label} }}</option>
#endforeach
</select>
</div>
#else
<div class="ap-form-input">
<select class="form-control select2" name="{{ $options->column }}">
#php
$model = app($options->model);
$query = $model::all();
#endphp
#if(!$row->required)
<option value="">{{__('voyager::generic.none')}}</option>
#endif
#foreach($query as $relationshipData)
<option value={{ $relationshipData->{$options->key} }} #if($dataTypeContent->{$options->column} == $relationshipData->{$options->key}){{ 'selected="selected"' }}#endif>{{ $relationshipData->{$options->label} }}</option>
#endforeach
</select>
</div>
#endif
This way when you're using categories relationship you will only get the active categories.
Click on the link and follow these simple steps, just now I solved my issue.
https://voyager.readme.io/docs/relationships

Laravel checkbox problem which I cannot update the pivot table

I'm working on a laravel application. In laravel I'm trying to update a row from a pivot table. In this application I have three tables:
issues: id, title, description
categories: id, name
category_issues:(pivot table) id, issue_id, category_id
In laravel I'm trying to update a row from a pivot table. I have this relationships:
Issue.php
public function categories() {
return $this->belongsToMany('App\Category', 'category_issues');
}
Category.php
public function issues() {
return $this->belongsToMany('App\Issue', 'category_issues');
}
A issue can have many categories.
Html code for displaying category section:
<div class="form-group row">
<label for="category" class="col-md-4 col-form-label text-md-right">{{ __('Category :') }}</label>
<div class="form-check col-md-6">
#foreach ($categories as $category)
<input type="checkbox" name="category[]" id="{{ $category->id }}" value="{{ $category->id }}"
{{ in_array($category->id, $issue->categories->pluck('id')->toArray()) ? 'checked' : '' }}>
<label for="{{ $category->id }}"> {{ $category->name }} </label>
#endforeach
</div>
</div>
Here is the update function file:
public function update(Issue $issue)
{
request()->validate([
'title'=> ['required', 'min:3'],
'description'=> ['required', 'min:3'],
'category' => ['required']
]);
$issue->title = request('title');
$issue->description = request('description');
$issue->save();
//Category_Issue Update
$categoryIssue = new CategoryIssue;
$cats = request('category');
foreach ($cats as $cat) {
$categoryIssue->updateOrCreate([
'issue_id'=> $issue->id,
'category_id' => $cat
]);
}
return redirect('issues')->with('success', 'Issue has been updated');
}
Instead of doing the creation / update on the CategoryIssue model (do you even have a CategoryIssue model?), Laravel makes this really easy to update the pivots of a relationship all at once, with the sync() method. You've set up the relationships correctly already per your code above.
In your update() method, you already have your Issue model, and have saved it. You have a set of categories coming in from the form via the $request object (or none if user didn't choose any), so you can then update the pivot like this:
$issue->categories()->sync($request->get('category', []));
Leaving a blank array as the second argument is optional. One small suggestion: maybe make the name of the field on the form 'categories' instead of 'category' just to keep it easy to remember it is an array coming in.

dynamic select options depend on another select option in laravel

I have two tables as users and departements. My departments table have two columns as id and title and my users table contains users information columns and one exta column as dept_id which is related to department table id.
I want to create a dropdown select option for departement and when a departement is selected the users which have that related department id should be displayed into another dropdown, how can i do that..?
i am fetching all users and departments data in controller and sending it to view.
my controller is....
public function index()
{
$user = DB::table('users')->get();
$dept = DB::table('departments')->get();
return view('userview', compact('user', 'dept'));
}
and my view is....
<select class="form-control" id="department" name="department" >
#foreach($dept as $dept)
<option value="{{ $dept->id }}">{{ $dept->name }}</option>
#endforeach
</select>
<select class="form-control" id="user" name="user" >
<option> </option>
</select>
I would use an Ajax request to fetch the related users and populate the 2nd list. Set up the relation in the User and Department models like:
// Department.php
public function users() {
return $this->hasMany(User::class);
}
// User.php
public function department() {
return $this->belongsTo(Department::class);
}
In your controller:
// DepartmentController.php
public function index() {
return view('userview', [
'departments' => Department::all()
]);
}
public function users(Request $request, $id) {
if ($request->ajax()) {
return response()->json([
'users' => User::where('dept_id', $id)->get()
]);
}
}
Then in your view, setup an event listener for the change event on the first select:
<select class="form-control" id="department" name="department" >
#foreach($departments as $dept)
<option value="{{ $dept->id }}">{{ $dept->name }}</option>
#endforeach
</select>
<select class="form-control" id="user" name="user" ></select>
<script>
$('#department').on('change', e => {
$('#user').empty()
$.ajax({
url: `/departments/${e.value}/users`,
success: data => {
data.users.forEach(user =>
$('#user').append(`<option value="${user.id}">${user.name}</option>`)
)
}
})
})
</script>

Laravel | Save and display two relations

I'm close to finish my CMS but I have one minor problem.
I can create several teams, works perfectly fine.
I can create several games, works also perfectly fine.
Now I want to create matches between those teams, which means I have two pivot tables.
One called game_match and the other called match_team.
game_match consist of game_idand match_id
match_teamconsist of match_id, team1_idand team2_id
My match/create.blade.php has two dropdown fields for each team.
Saving a single relation to the database works fine for me as I've done this a couple of times, but I can't figure out how to save two relations.
This is what I got so far:
Inside match/create.blade.php
<div class="field m-t-20 is-inline-block">
<p class="control">
<label for="home" class="label"><b>{{ trans_choice('messages.home', 1) }}</b></label>
<input type="hidden" name="home" id="home" :value="homeSelected">
<div class="select">
<select v-model="homeSelected">
#foreach($teams as $team)
<option value="{{ $team->id }}">{{ $team->name }}</option>
#endforeach
</select>
</div>
</p>
</div>
<div class="field m-t-20 is-inline-block">
<p class="control">
<label for="opponent" class="label"><b>{{ trans_choice('messages.opponent', 1) }}</b></label>
<input type="hidden" name="opponent" id="opponent" :value="opponentSelected">
<div class="select">
<select v-model="opponentSelected">
#foreach($teams as $team)
<option value="{{ $team->id }}">{{ $team->name }}</option>
#endforeach
</select>
</div>
</p>
</div>
#section('scripts')
<script>
var app = new Vue({
el: '#app',
data: {
homeSelected: "",
opponentSelected: "",
gameSelected: ""
}
});
</script>
#endsection
MatchController.php
public function store(Request $request)
{
$this->validate($request, [
'title' => 'required|max:255',
'matchday' => 'required',
]);
$match = new Match();
$match->title = $request->title;
$match->matchday = $request->matchday;
if ($match->save()) {
$match->games()->sync($request->game);
$match->teams()->sync( [
['team1_id' => $request->home, 'team2_id' => $request->opponent],
]);
Session::flash('success', trans('messages.created', ['item' => $match->title]));
return redirect()->route('matches.show', $match->id);
} else {
Session::flash('error', trans('messages.error'));
return redirect()->route('matches.create')->withInput();
}
}
match.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Match extends Model
{
use SoftDeletes; // <-- Use This Instead Of SoftDeletingTrait
protected $fillable = [
'title'
];
protected $dates = ['deleted_at'];
public function setHomeTeam () {}
public function teams () {
return $this->belongsToMany('App\Team', 'match_team', 'match_id', 'team1_id');
}
public function games () {
return $this->belongsToMany('App\Game', 'game_match');
}
public function getHomeTeam() {
return $this->belongsToMany('App\Team', 'match_team', 'match_id', 'team1_id');
}
public function getOpponentTeam() {
return $this->belongsToMany('App\Team', 'match_team', 'match_id', 'team2_id');
}
}
Can someone help me?
You should better use firstOrCreate(), updateOrCreate or attach() methods.

Resources