Laravel - Iterating pivot data (Property does not exist on this collection instance) - laravel

I have a many-to-many relationship between Order and Product
Product.php
public function orders()
{
return $this->belongsToMany(Order::class)
->withTimestamps()
->withPivot('qty');
}
Order.php
public function products()
{
return $this->belongsToMany(Product::class)
->withTimestamps()
->withPivot('qty');
}
Now whenever I try to utilize an iteration in a view (in this case I am just trying to show the form which iterates through all available Products, I always receive the error...
Property [products] does not exist on this collection instance.
create.blade.php
#foreach ($products->orders as $product)
# Order inputs are here
{{ Form::text('qty', $product->pivot->qty, [
'type' => 'tel',
'min' => 0,
'max' => 20,
'step' => 1,
'placeholder' => '0',
'class' => 'meal'
]) }}
#endforeach
I have also attempted #foreach ($products->orders as $product) and both approaches give me that same error.
I have attempted many different ways in my Controller to fix this error, here is my last attempt:
OrderControlller.php
public function create()
{
$user = Auth::user();
$products = Product::get();
$orders = $user->orders;
return view('orders.create', compact('products', 'orders', 'user'));
}
UPDATE
#alan's answer is correct, I am sure, however...
I am still getting "Property [pivot] does not exist on this collection instance" whenever I try to run an iteration.
The concept of an iteration inside of an iteration in this instance is confusing for me.
I cannot visualize how Laravel is handling the pivot connection. In tinker when I load up just the Product table, there is no qty column. (This makes sense because that is on the pivot table). This also explains this new error.
Should I be doing something in the vein of this? :
changed create.blade.php
#foreach ($products as $product)
{{ Form::text('qty', $product->orders->pivot->qty }}
OrderController.php
$user = Auth::user();
$orders = $user->orders;
$products= []; #pass products to view as an array
$p = $orders->products; #this relationship brings in pivot data?
foreach ($p as $orders) {
#would I then somehow pass just this qty here?
}
Problem is I am always getting a "Property does not exist" error, be it with 'products', 'orders', or 'pivot'.

This should work. You were trying to access the orders property on the $products variable, which is a Laravel Collection (get method on model returns a collection). So instead of doing that you just iterate through the products and access the pivot table from the individual product model.
#foreach ($products as $product)
# Order inputs are here
{{ Form::text('qty', $product->orders->pivot->qty, [
'type' => 'tel',
'min' => 0,
'max' => 20,
'step' => 1,
'placeholder' => '0',
'class' => 'meal'
]) }}
#endforeach
Update:
Actually that makes sense. A record on the pivot table defines an association between an order and a product. So for you to access a record in the pivot table you must access the product or order from its relationship. This is what I would do.
OrderController.php
$user = Auth::user();
$user->load("orders.products"); // eager load relationship to avoid N+1 problem
$orders = $user->orders;
return view('orders.create', compact('orders', 'user'));
create.blade.php
#foreach ($orders as $order)
#foreach ($order->products as $product)
{{ Form::text('qty', $product->pivot->qty, [
'type' => 'tel',
'min' => 0,
'max' => 20,
'step' => 1,
'placeholder' => '0',
'class' => 'meal'
]) }}
#endforeach
#endforeach
Some resources:
Eager loading
Many to Many relations

Related

Laravel Illegal offset type on many to many with extra column

in Database i have a table of product and components
and i have a table for many to many relation which is component_product
it have an attributes of (product_id,component_id,quantity)
in model product
class Product extends Model
{
protected $fillable = [
'name','price','user_id','is_avilable','description'
];
public function components()
{
return $this->belongsToMany('App\Component')
->withPivot('quantity');
}
}
in view
{!! Form::select('component_id[]',$components,null !!}
{!! Form::select('component_id[]',$components,null !!}
{!! Form::number('quantity[]',null ]) !!}
{!! Form::number('quantity[]',null ]) !!}
in controller
public function store(Request $request)
{
$product= Product::create( $request->all() );
$product->components()->sync($request->component_id => ['quantity'=> $request->quantity ] );
}
It gives me an error of Illegal offset type
notice : if die dump $request->quantity or $request->component_id it will get the array correctly
Sync example in laravel docs (https://laravel.com/docs/5.5/eloquent-relationships)
$user->roles()->sync([1 => ['expires' => true], 2, 3]);
Try changing , with =>
So in your case:
$product->components()->sync([$request->component_id => ['quantity'=> $request->quantity]]);
this is how i solve my own problem
in Laravel documentation
$user->roles()->sync([1 => ['expires' => true], 2, 3]);
so to match this
$manyToMany = array();
for ( $i=0 ; $i< count($request->component_id); $i++ )
{
$manyToMany[ $request->component_id[$i] ] = ['quantity' =>$request->quantity[$i] ];
}
$product->components()->sync($manyToMany);
is their is a better solution

Laravel guzzel result implement to blade laravel

i have problem while displaying json data in laravel blade, i request data using guzzel and this is my code:
public function index(){
$client = new Client();
$schedules = $client->get('45.112.125.25:5500/md_data/schedules/', [
'query' => [
'vCategory' => '129',
'vStartDate' => '2017-07-01',
'vEndDate' => '2017-09-31',
'vReadKey' => 850601165,
'vRows' => 10,
'vOffset' => 0
]
]);
// return $schedules->getBody();
return view('trainingList')->with('schedules', $schedules->getBody());
}
this result :
[{"f_training_schedule_id":324,"f_training_category_id":129,"f_training_category":"Workshop Business","f_city_id":216,"f_city_name":"Kota Jakarta Selatan","f_training_schedule_startdate":"2017-08-11T17:00:00.000Z","f_training_schedule_enddate":"2017-08-12T17:00:00.000Z","f_training_schedule_batch":1,"f_training_schedule_trainer":58,"f_training_schedule_address":"<!--StartFragment-->JL TB Simatupang, Cilandak, RT.3/RW.3, Cilandak Tim., Ps. Minggu<!--EndFragment-->\r\n\r\n<br>"}]
how to get specific data from the above results.
for example I want to get value from f_training_schedule_id
You need json_decode():
return view('trainingList')->with('schedules', json_decode($schedules->getBody(), true));
In your blade template
$schedules[0]['f_training_schedule_id'];
Foreach:
#foreach ($schedules as $schedule)
<p>{{ $schedule['f_training_schedule_id'] }}</p>
#endforeach

cakephp3- table sorting not working

Version: 3.3.*
I’m using the $paginator->sort() method to create links in the column headers for tables of paginated search results in my CMS. You should be able to click them once to sort in ascending order, and then click again to reverse into descending order. But the reverse was never working for me.
But this is not for all fields. Let say I have 5 fields.
<tr class="design">
<th scope="col"><?= $this->Paginator->sort('Students.id','Id',array('class'=>'link')); ?></th>
<th scope="col"><?php echo $this->Paginator->sort('Students.userName','Name',array('class'=>'link')); ?></th>
<th scope="col"><?php echo $this->Paginator->sort('Students.age','Age',array('class'=>'link')); ?></th>
<th scope="col"><?php echo $this->Paginator->sort('Students.currentClass','Class',array('class'=>'link')); ?></th>
<th scope="col"><?php echo $this->Paginator->sort('Students.dateJoined','Joined Date',array('class'=>'link')); ?></th>
</tr>
I can sort the table both ways using username, age, and school but not using id and joined. When I fetch the list initially I have specified in my Model function to fetch result based on id and joined in ascending order.
Is it because of this, I'm not being able to sort it in descending order?
Is there any way I can achieve this?
Controller function
public function index()
{
//Listing Students
$this->paginate = [
'finder' => 'ListStudents',
'sortWhitelist' => ['Students.id',
'Students.userName',
'Students.age',
'Students.currentClass',
'Students.dateJoined',],
'limit' => 25,
];
$students = $this->paginate($this->Students);
$this->set(compact('students'));
$this->set('_serialize', ['students']);
}
Model Function
public function findListStudents(Query $query, array $options)
{
$query
->select(['id','userName','age','currentClass','dateJoined'
])
$query->group('Students.id');
$query->order(['status' => 'asc']);
$query->order(['Students.dateJoined' => 'asc']);
$query->order(['Students.id' => 'asc']);
return $query;
}
The issue mentioned in this link is similar to the one I'm facing.I tried the solution mentioned in it but it ain't working.
To achieve this, you have to modify your controller and model functions a little bit.
First of all, add extraOptions to your controller function
public function index()
{
//Listing Students
$this->paginate = [
'finder' => 'ListStudents',
'sortWhitelist' => ['Students.id',
'Students.userName',
'Students.age',
'Students.currentClass',
'Students.dateJoined',],
'limit' => 25,
'extraOptions' =>[
'params' => $params ]
];
$students = $this->paginate($this->Students);
$this->set(compact('students'));
$this->set('_serialize', ['students']);
}
Now you need to override your dateJoined and id sort order. By default, its asc.
If user passes a specific direction, it should be taken. So, for that you need to modify your model function a little.
public function findListStudents(Query $query, array $options)
{
$query
->select(['id','userName','age','currentClass','dateJoined'
])
$query->group('Students.id');
$direction = (!empty($options['extraOptions']['params']['direction'])) ? $options['extraOptions']['params']['direction'] : 'asc';
$query->order(['status' => 'asc']);
$query->order(['Students.dateJoined' => $direction]);
$query->order(['Students.id' => $direction]);
return $query;
}
Now sorting will work fine when you are passing a specific direction.
When I fetch the list initially I have specified in my Model function
to fetch result based on id and joined in ascending order. Is it
because of this, I'm not being able to sort it in descending order?
Yes, this is the case. You can verify that by commenting out the $query->order statements in your custom finder method. You will find out that descentant sorting Students.id will work then.
I would recommend to simply leave the sorting out of the custom finder method and define the default sorting options when configuring your $paginate variable instead.
StudentsController
public function index()
{
$this->paginate = [
'finder' => 'ListStudents',
'sortWhitelist' => [
'Students.id',
'Students.userName',
'Students.age',
'Students.currentClass',
'Students.dateJoined'
],
'limit' => 25,
// add custom sorting options here
'order' => [
'Students.status' => 'asc',
'Students.dateJoined' => 'asc',
'Students.id' => 'asc'
]
];
$students = $this->paginate($this->Students);
$this->set(compact('students'));
$this->set('_serialize', ['students']);
}
StudentsTable
public function findListStudents(Query $query, array $options)
{
$query ->select([
'id', 'userName', 'age', 'currentClass', 'dateJoined'
]);
$query->group('Students.id');
// remove the sorting here
/*
$query->order(['status' => 'asc']);
$query->order(['Students.dateJoined' => 'asc']);
$query->order(['Students.id' => 'asc']);
*/
return $query;
}

Form with has many relationship

What is the better way to create a model with has many relationship?
For example:
I have two models:
Client (id, name, ...)
Contact (id, type, value, description)
A client has many Contacts.
Example of create client view: http://laravel.io/bin/mGXEE
Problems:
how to deal with validations?
if validation fails, going back and fill in the contact with the respective errors?
With php artisan make:request you can make a request file that will validate your information. Take a look at the documentation:
https://laravel.com/docs/5.1/validation
Example:
public function rules()
{
return [
'name' => 'required|min:3|max:20',
'lastname' => 'required|min:3|max:20',
'adres' => 'required|min:3|max:20',
'zip' => 'required|min:3|max:20',
'city' => 'required|min:3|max:20'
];
}
View:
#foreach ($errors->all() as $error)
<p>{{ $error }}</p>
#endforeach

check if value already exists in db

I have an insert form and a dropdownbox which displays all cars names and when selected one it saves the id in column "car_id" which is unique. What I want is to check if this id already exists and if yes to display a validation message:
create controller
public function create() {
$cars = DB::table('cars')->orderBy('Description', 'asc')->distinct()->lists('Description', 'id');
return View::make('pages.insur_docs_create', array(
'cars' => $cars
));
}
insur_docs_blade.php
<div class="form-group">
{{ Form::label('car', 'Car', array('class'=>'control-label col-lg-4')) }}
<div class="col-lg-8">
{{ Form::select('car', $cars, Input::old('class'), array(
'data-validation' => 'required',
'data-validation-error-msg' => 'You did not enter a valid car',
'class' => 'form-control'))
}}
</div>
</div>
You can use Laravel's Validator class for this. These are a few snippits of how it works. This methods works by using your data model. Instead of writing everything out I added a few links that provide you all the information to complete your validation.
$data = Input::all();
$rules = array(
'car_id' => 'unique'
);
$validator = Validator::make($data, $rules);
if ($validator->passes()) {
return 'Data was saved.';
}
http://laravelbook.com/laravel-input-validation
http://laravel.com/docs/validation
http://daylerees.com/codebright/validation
You can use Laravel's "exists" method like this:
if (User::where('email', $email)->exists()) {
// that email already exists in the users table
}

Resources