Problems with Laravel Pivot Table - laravel

I am working on a medical lab application in laravel where I have the following tables:
1. Test table: This is a table which stores all the information related to medical tests:
2: Checkup: This is a page which contains all the patient information along with the tests he/she takes.
This is the test page:
This is the Checkup page where the tests and their results are selected:
Here can be many tests and user can check any number of them and will write the result of the test in the textfield below the checkbox.
I get this data in the controller like below code and save it to the database:
$this->validate($request,
[
'patient_name' => 'required|max:50',
'patient_age' => 'required',
'gender' => 'required',
'patient_type' => 'required',
'technition_id' => 'required',
'result' => 'required',
'test' => 'required',
'amount' => 'required'
]);
if( ($request->patient_type == 2) && ($request->doctor_id==0) )
{
return redirect()->back()->withInput(Input::all())->withErrors(['message' => 'Please select a valid Doctor.']);
}
$checkup = new Checkup;
$checkup->patient_name = $request->patient_name;
$checkup->patient_age = $request->patient_age;
$checkup->gender = $request->gender;
$checkup->patienttype_id = $request->patient_type;
$checkup->technition_id = $request->technition_id;
if(isset($request->doctor_id))
{
$checkup->doctor_id = $request->doctor_id;
}
$checkup->amount = $request->amount;
// $checkup->result = $request->result;
$checkup->save();
$tests =[];
$tests = $request->test;
$results =[];
$results = $request->result;
//$checkup->tests()->attach($tests->id, ['result' => $result]);
$sync_data = [];
for($i = 0; $i < count($tests); $i++)
$sync_data[$tests[$i]] = ['result' => $results[$i]];
$checkup->tests()->sync($sync_data);
Session::flash('success', 'The record was successfully saved.');
return redirect()->route('checkups.index');
Now the problem is that when I check all the checkboxes and write the result of all the tests then it is fine but when I select some and leave some of them then it gives error and the error comes because the result textbox for the unchecked test is empty.
This is the case when I select one test and leave the others:
When I check on test and write the result of it and then var_dump both test and result arrays i get the below output:
In the above image we can see that the test array contains one item because only one checkbox was checked but the result array contains two items and the first one is NULL which belongs to the unchecked checkbox.
This is the view file of the checkboxes and the textfields:
{{ Form::label('tests', 'Tests Taken') }}
#foreach(App\Test::all() as $test)
<div class="checkbox checkbox-switchery">
{{ Form::label('test', $test->name) }}
<input name="test[]" value="{{ $test->id }}" type="checkbox" class="switchery-primary">
</div>
<div>
{{ Form::label('result', "Result") }}
<input name="result[]" type="text" class="form-control">
</div>
#endforeach
<div class="form-group">
{{ Form::label('amount', 'Amount') }}
{{ Form::text('amount', null, ['class' => 'form-control']) }}
</div>
<div class="form-group">
{{Form::button('<i class="fa fa-save"> Save</i>', ['type' => 'submit', 'class' => 'btn btn-success'])}}
</div>
{!! Form::close() !!}
Please help me on this and show me how to insert the pivot table data properly to the system.
Thanks in advance for any help.

Try this..
In your blade file :
#foreach(App\Test::all() as $index => $test)
<div class="checkbox checkbox-switchery">
{{ Form::label('test', $test->name) }}
<input name="test[{{ $index }}]" value="{{ $test->id }}" type="checkbox" class="switchery-primary">
</div>
<div>
{{ Form::label('result', "Result") }}
<input name="result[{{ $index }}]" type="text" class="form-control">
</div>
#endforeach
Instead of the for loop you can use foreach lopp.
$sync_data = [];
foreach($tests as $index => $value) {
if(!empty($results[$index]) {
$sync_data[$value] = ['result' => $results[$index]]
}
}
$checkup->tests()->sync($sync_data);

Related

Updating many-to-many relational data with attach() from multiple checkboxes in Laravel

I am creating an online bookstore in Laravel, and upon creating a new book, the administrator is able to define which warehouses that are able to stock this book, by checking the specific warehouses checkboxes.
To give insight in how it works, this is my create function:
public function create()
{
$authors = Author::all();
$selectedAuthor = Book::first()->author_id;
$publishers = Publisher::all();
$selectedPublisher = Book::first()->publisher_id;
$warehouses = Warehouse::all();
$selectedWarehouse = Book::first()->warehouse_id;
return view('books.create', compact(['authors', 'publishers', 'warehouses'],
['selectedAuthor', 'selectedPublisher', 'selectedWarehouse']
));
}
and my store method:
public function store(Request $request)
{
$request->validate([
'ISBN' => 'required',
'author_id' => 'required',
'publisher_id' => 'required',
'year' => 'required',
'title' => 'required',
'price' => 'required',
]);
try {
$book = Book::create($request->all());
foreach ($request->checked as $value){
$book->warehouses()->attach([$value]);
}
return redirect()->route('books.index')
->with('success','Book created successfully.');
} catch (\Illuminate\Database\QueryException $e) {
var_dump($e->errorInfo);
}
}
But when an administrator edits a book, the checkboxes that were checked upon creating the book, should be "checked", and the administrator should be able to attach more warehouses, and be able to "unselect" a warehouse, so if an already checked value gets unchecked and sumbitted, it should get detached from the many-to-many table.
This is what i currently have:
My edit method:
public function edit(Book $book)
{
$authors = Author::all();
$selectedAuthor = Book::first()->author_id;
$publishers = Publisher::all();
$selectedPublisher = Book::first()->publisher_id;
$warehouses = Warehouse::all();
$selectedWarehouse = Book::first()->warehouse_id;
return view('books.edit', compact(['book', 'authors', 'publishers', 'warehouses'],
['selectedAuthor', 'selectedPublisher', 'selectedWarehouse']));
}
And my update method:
public function update(Request $request, Book $book)
{
$request->validate([
'ISBN' => 'required',
'publisher_id' => 'required',
'author_id' => 'required',
'year' => 'required',
'title' => 'required',
'price' => 'required',
]);
try {
$book->update($request->all());
// TODO: Update warehouses
return redirect()->route('books.index')
->with('success','Book updated successfully.');
} catch (\Illuminate\Database\QueryException $e) {
var_dump($e->errorInfo);
}
}
And the checkboxes in my edit.blade view:
#foreach($warehouses as $warehouse)
<input type="checkbox" name="checked[]" value="{{ $warehouse->id }}">
{{ $warehouse->address }}
<br/>
#endforeach
My Book model:
public function warehouses()
{
return $this->belongsToMany(Warehouse::class);
}
And my warehouse model:
public function books()
{
return $this->belongsToMany(Book::class);
}
Any help on being able to attach / detach upon editing an existing book, would be highly appreciated!
Try this on create and update method for storing
// Your method
foreach ($request->checked as $value){
$book->warehouses()->attach([$value]);
}
// Try This
$book->warehouses()->sync($request->checked); // $request->checked must be an array
Update Blade
#foreach($warehouses as $warehouse)
<input #if($book->warehouses()->where('warehouse_id', $warehouse->id)->exists()) checked #endif type="checkbox" name="checked[]" value="{{ $warehouse->id }}">
{{ $warehouse->address }}
<br/>
#endforeach
I will left this example with a logic according your problem. In this case are roles:
public function edit(Role $role){
//get roles ids
$permission_role = [];
foreach($role->permissions as $permission){
$permission_role[] = $permission->id;
}
//get permissions
$permissions = Permission::all();
return view("role.edit", compact('role', 'permission_role', 'permissions'));
}
In the blade:
<div class="row">
<div class="col-md-8">
<div class="form-group">
<label>Select the permissions for the current role</label>
#foreach ($permissions as $permission)
<div class="valid-feedback d-block" style="font-size: 15px !important;">
<input type="checkbox" value="{{ $permission->id }}" name="permissions[]"
#if(is_array(old('permissions')) && in_array("$permission->id", old('permissions')))
checked
#elseif(is_array($permission_role) && in_array("$permission->id", $permission_role))
checked
#endif>
<strong> {{ $permission->description }} </strong>
</div>
#endforeach
</div>
<div class="invalid-feedback d-block">
#foreach ($errors->get('permissions') as $error)
{{ $error }}
#endforeach
</div>
</div>
</div>
Of this way you can also keep the old checkboxes when nothing is select. You should validate it as required.

Show checkbox checked from database

Hope you're all fine.
I have an article, and I want to be able to edit it. Inside the article, I have checkboxs, and what I want is to check the ones I've checked when I first create the article (Im using a pivot table).
I have this code for now.
public function createArticle(Request $request)
{
$data = $request->validate([
'titreArticle' => 'bail|required|between:5,40',
'typeArticle' => 'bail|required',
'themeCheckbox' => 'required',
'themeCheckbox.*' => 'required',
'contenuArticle' => 'bail|required',
]);
$type_articles = Type_article::findOrFail($data['typeArticle']);
$article = new Article();
$article->type_article()->associate($type_articles);
$themes = Theme::whereIn('theme_id', array_keys($data['themeCheckbox']))->get();
$article->titre = $data['titreArticle'];
$article->contenu = $data['contenuArticle'];
$article->save();
$article->theme()->attach( $themes);
return view('admin');
}
And inside my view :
#foreach ($themes as $theme)
<div class="form-check form-check-inline">
<input class="form-check-input" type="checkbox" name="themeCheckbox[{{$theme->theme_id}}]" value="1" >
<label class="form-check-label">{{ $theme->nom_theme }}</label>
</div>
#endforeach
I've seen I must use contains but don't really know how to use it...
Cordially

Photo don't display in shop cart LARAVEL 6

i'm using laravel in my project , so when i add a product in the shop cart all the data is displayed except the product image.
This is the cartcontroller.php:
public function add(Request $request) {
$produit=productmodel::find($request->id);
Cart::add(array(
'id' =>$request->id, // inique row ID
'name' =>$request->product_name,
'price' => $request->product_price,
'quantity' =>$request->product_quantity,
'attributes' => array('photo'=>$request->product_image)));
return redirect ('shop-cart');
}
and this is the shop-cart.blade.php
<tbody>
#foreach(\Cart::getContent() as $item)
<tr>
<td class="cart__product__item">
<div class="cart__product__item__title">
<img src="{{asset('storage/product/September2020/'.$item->attributes['photo'])}}" alt="">
<h6> {{Str::words($item->name,20) }}</h6>
#foreach($item->attributes as $key => $value)
<dl class="dlist-inline small">
<dt>{{ ucwords($key) }}: </dt>
<dd>{{ ucwords($value) }}</dd>
</dl>
#endforeach
</div>
</td>
<td class="cart__price"> {{$item->price}} TND</td>
<td class="cart__quantity">
{{ $item->quantity }}
</td>
<td class="cart__total"> {{ $item->price * $item->quantity }} TND</td>
<td class="cart__close"><i class="fa fa-times"></i>
</td>
</td>
</tr>
#endforeach
</tbody>
</table>
</div>
#endif
If you are using darryldecode/cart for cart. You can go to your vendor folder and make some slight changes to add method of Cart.php file.
public function add($id, $name = null, $price = null, $quantity = null, $image = null, $attributes = array(), $conditions = array(), $associatedModel = null)
{
// if the first argument is an array,
// we will need to call add again
if (is_array($id)) {
// the first argument is an array, now we will need to check if it is a multi dimensional
// array, if so, we will iterate through each item and call add again
if (Helpers::isMultiArray($id)) {
foreach ($id as $item) {
$this->add(
$item['id'],
$item['name'],
$item['price'],
$item['quantity'],
$item['image'],
Helpers::issetAndHasValueOrAssignDefault($item['attributes'], array()),
Helpers::issetAndHasValueOrAssignDefault($item['conditions'], array()),
Helpers::issetAndHasValueOrAssignDefault($item['associatedModel'], null)
);
}
} else {
$this->add(
$id['id'],
$id['name'],
$id['price'],
$id['quantity'],
$id['image'],
Helpers::issetAndHasValueOrAssignDefault($id['attributes'], array()),
Helpers::issetAndHasValueOrAssignDefault($id['conditions'], array()),
Helpers::issetAndHasValueOrAssignDefault($id['associatedModel'], null)
);
}
return $this;
}
$data = array(
'id' => $id,
'name' => $name,
'price' => Helpers::normalizePrice($price),
'quantity' => $quantity,
'image'=>$image,
'attributes' => new ItemAttributeCollection($attributes),
'conditions' => $conditions
);
if (isset($associatedModel) && $associatedModel != '') {
$data['associatedModel'] = $associatedModel;
}
// validate data
$item = $this->validate($data);
// get the cart
$cart = $this->getContent();
// if the item is already in the cart we will just update it
if ($cart->has($id)) {
$this->update($id, $item);
} else {
$this->addRow($id, $item);
}
$this->currentItemId = $id;
return $this;
}
Now you can simply store image in cart as below
$userId = auth()->user()->id;
\Cart::session($userId)->add(array(
'id' => $request->id,
'name' =>$request->item_name,
'price' =>$request->item_price,
'quantity' => $request->quantity,
'image'=>$request->image,
'attributes' => array(),
));
And view your stored image from path like
#foreach(Cart::session(auth()->user()->id)->getContent() as $items)
<div class="row pt-5">
<div class="col-md-3 offset-md-2">
<img class="card-img-top" src="{{asset('photos').'/'.$items->image}}"
style="height:120px; width:120px;"alt="Card image cap">
</div>
<div class="col-md-6 ">
<h5 class="font-weight-bold">{{$items->name}}</h5>
Rate: Rs {{$items->price}}<br>
Qty: {{$items->quantity}}<br>
<?php
$price="";
$price=$items->quantity*$items->price;
?>
Price: Rs {{$price}}<br>
<button class="btn-sm btn-outline-danger"><i class="far fa-trash-alt"></i></button>
</div>
</div>
<hr>
#endforeach

Return Redirect Laravel

I want to return to the page with Link : localhost:8000/order/show/O1/T1.
O1 is $order->id_order and T1 is $trip->id_trip.
Here's my code.
Route::get('/order/show/{id_order}/{id_trip}', 'OrderController#show');
Route::get('/order/update_driver/{id_order}/{id_trip}', 'OrderController#update_driver');
Order Controller
public function show($id_order, $id_trip){
$trip = Trip::find($id_trip);
$order = Order::where(['id_order' => $id_order, 'id_trip' => $id_trip])->first();
$detail_order = Detail_Order::where(['id_order' => $id_order, 'id_trip' => $id_trip])->first();
$detail = Order::join('detail_order', 'order.id_order', '=', 'detail_order.id_order')
->where('order.id_order', $id_order)
->select('order.id_trip as order_trip',
'order.id_order as order_id',
'order.id_users as order_users',
'order.date_order as order_date',
'detail_order.id_seat as detail_seat',
'detail_order.users as detail_users')
->get();
$driver = Driver::all();
return view('travel.order.show', ['trip' => $trip, 'order' => $order, 'detail' => $detail, 'detail_order' => $detail_order, 'driver' => $driver]);
}
public function update_driver($id_order, $id_trip){
$driver = Input::get('id_users_driver');
Detail_Order::where('id_order', $id_order)
->update(['id_users_driver' => $driver]);
session()->flash('flash_success', 'Data has been updated');
return redirect('/order/show/{id_order}/{id_trip}');
}
View
<form method="get" action="/order/update_driver/{{ $order->id_order}}/{{ $order->id_trip}}">
<label>Driver</label>
<select class="form-control" name="id_users_driver" id="id_users_driver">
<option value=""> Driver </option>
#foreach($driver as $d)
<option value="{{$d->id_users}}"{{$detail_order->id_users_driver == $d->id_users ? 'selected' : ''}}>{{$d->name}}</option>
#endforeach
</select>
#if($errors->has('id_users_driver'))
<div class="text-danger">
{{ $errors->first('id_users_driver')}}
</div>
#endif
<input type="submit" class="btn btn-primary" value="Save">
</form>
It returned error Trying to get property 'id_order' of non-object.
Do you know how to make it return to localhost:8000/order/show/O1/T1? Thank you

Laravel use sync on a many to many that includes a multiple extra fields

I'm trying to use sync on a many to many that includes a status and a comment. I can sync the applications without status and comment just fine.
NewUserAccount Model
public function applications()
{
return $this->belongsToMany('App\Application', 'new_user_account_applications', 'new_user_id')->withPivot('application_comment', 'status');
}
Application Model
public function newUserAccounts()
{
return $this->belongsToMany('App\NewUserAccount', 'new_user_accounts_applications', 'new_user_id')->withPivot('application_comment', 'status');
}
My NewUserAccountController
public function store(StoreRequest $request)
{
$userAccount = NewUserAccount::create(array_merge(
$request->all(),
['submitted_by' => $requester->id],
['start_date' => Carbon::parse($request->input('start_date'))],
['account_expires' => $request->accountExpires('newAccountExpireDate')],
['company_id' => $requester->company_id],
['username' => $request->manuallyAssignId()]
));
// Here I sync applications and include application comment and status
$userAccount->applications()->sync($request->applications, ['application_comment' => $request->application_comment, 'status' => 0]);
....
}
My pivot showing status and comment correctly
My form. Here is where I'm not sure how to handle the comment and get it to save with each application pivot record.
#foreach($applications as $application)
<label class="k-checkbox">
<input value="{{ $application->id }}" name="applications[]" type="checkbox">{{ $application->application_name }} <span></span>
</label>
<div class="form-group col-lg-4 mb-3">
<label>Comments</label>
<textarea name="application_comment[]" class="form-control" rows="2"></textarea>
</div>
#endforeach
First, you need to set the correct index for the application_comment attribute in your textarea. It's needed to correctly determine the comment for each application.
#foreach($applications as $application)
...
<textarea name="application_comment[{{ $application->id }}]" class="form-control" rows="2"></textarea>
...
#endforeach
Then, you just need to format your data to:
$userAccount->applications()->sync([
application_id_1 => ['application_comment' => 'comment for application_id 1'],
application_id_2 => ['application_comment' => 'comment for application_id 2'],
...
]);
So, here it is
$applications = collect($request->applications)->mapWithKeys(function ($appId) use ($request) {
return [$appId => [
'application_comment' => $request->input('application_comment')[$appId],
'status' => 0,
]];
});
$userAccount->applications()->sync($applications);

Resources