Resource index parameters - php

I've wrote a controller to have it's index to output the DataTables plugin data.
A excerpt:
public function index() {
return Datatable::collection(\App\Slip::where('paid', '=', false)->get())
...
->make();
}
and the route:
Route::resource('api/slip', 'SlipsController');
everything works fine, the problem is that this index return only items with paid = false that's right for one view, but for the other view I need all items/rows.
so what's the best practice to make index function cover both cases (all and those with paid = false)?
A post param is the first thing that comes to my mind, but the data is loaded by the DataTables plugin.

Why not?. You need detect your specified view and send some extra param in ajax-request. Like:
$('...').DataTable({
....
"ajax": {
'type': 'GET',
'url': "....",
'data': {paid: false},
},
....
});
Now in action:
public function index(Request $request) {
$paid = $request->input('paid');
$items = [];
if ($paid){
$items = \App\Slip::all()->get();
}else{
$items = \App\Slip::where('paid', '=', false)->get();
}
return Datatable::collection($items)
...
->make();
}

Related

How to implement DataTable with parameter 'id' in Laravel (DataTables)?

I am trying to pass the ID value from the blade file into ajax so it the data table will be routed and will call the ProductActivities function in ProductController.
Here's my snippet code for show() function in ProductController:
public function show($id)
{
$product = Product::find($id);
$data = Product::with(['user_modify'], 'id', $product->user_modified)
->where('product_id', '=', $id)->first();
$category = Category::select('category_name')
->where('category_id', '=', $data->product_type)
->pluck('category_name')
->first();
if($data->count() > 0){
return view('product.view', compact('data', 'category'));
}else{
Toastr::error('Product cannot be retrieved.', 'Error');
return view('product.index');
}
}
And here's the snippet code of JavaScript for the DataTable initialization in view.blade.php file:
#push('js')
<script>
$(function () {
$("#prod_log_tbl").DataTable({
responsive:true,
stateSave:false,
scrollY:true,
autoWidth: false,
ajax: {{ url('product/activities', [Request::segment(3)]) }},
order:[0, 'desc'],
searchable: false,
sortable:false,
fixedColumns: true
});
});
</script>
#endpush
line of code for route in web.php:
Route::get('product/activities/{id}', 'Master\ProductController#ProductActivities')->name('product/activities/{id}');
snippet code for the ProductActivities() function in ProductController:
public function ProductActivities($id)
{
$dataAct = Activity::all()->where('subject_id', '=', $id);
return Datatables::of($dataAct)->make(true);
}
And here's the result of my current progress:
In the screenshot of result the URL that ajax shows has additional values after the ID which I think causes of the DataTable error.
I don't know How I am getting this error? How can I implement the passing of ID from the view blade file through DataTable ajax into the ProductController?
P.S. I use Yajra/DataTable package for Laravel.
I think you do not need php echo in you Ajax url, route helper syntax is
{{ route('routeName', ['id' => 1]) }}
you need route name and parameter, another way is using url helper
{{ url('product/activities/', [Request::segment(3)]) }}
Beside this if you want to use model refer documentation, using first() will give you only one object, you need a collection, better considering get().

Passing ID from Laravel show to Datatables route

I believe I am close but struggling on how to pass a given ID from my show method into the associated showdata one so that datatables can manifest with the associated data for just that ID.
The code works when I hardcode an ID or just remove the where statement altogether. My objective is to have the datatable manifest associated items for just a given collection.
Routes:
Route::resource('collections', 'CollectionsController');
Route::get('collectionsdata/{id}', 'CollectionsController#showdata');
Show.blade.php:
var id = {{ $collection->id }}
$(function () {...
$('#item-table').DataTable({
//processing: true,
serverSide: true,
ajax: "/collectionsdata/"+ id,
columns: [
//{data: 'id', name: 'id'},
{data: 'id', name: 'id'},
{data: 'collection_id', name: 'collection_id'},
{data: 'type_id', name: 'type_id'},
{data: 'collection.title', name: 'collection.title'},
{data: 'type.name', name: 'type.name'},
{data: 'updated_at', name: 'updated_at'},
]
});
Collections Controller:
public function show(Collection $collection)
{
$collection->load('items.type')->get();
//dd($collection);
return view ('collections.show', compact('collection'));
}
public function showdata()
{
$data = Item::with('collection', 'type')->where('collection_id', $id);
return Datatables::of($data)->make(true);
}
SHOW itself function well, var id works well in the blade - I think I am just missing something in the controller to take in the id and ultimately create the desired query on $data for return to the datatable.
Yes. You are missing the Request $request in your show method to retrieve the $id from the route.
use Illuminate\Http\Request;
public function showdata(Request $request)
{
$collection_id = $request->id;
$data = Item::with('collection', 'type')->where('collection_id', $id);
return Datatables::of($data)->make(true);
}
You can also retrieve id directly from the controller instead of using $request.
public function showdata($id)
{
$data = Item::with('collection', 'type')->where('collection_id', $id);
return Datatables::of($data)->make(true);
}
You only have to have one parameter in showdata that is one for id you are passing from URL
public function showdata($id)
{
$data = Item::with('collection', 'type')->where('collection_id', $id);
return Datatables::of($data)->make(true);
}

create a query that will check the quantity is between a quantity range and output a certain amount base from the product id using jquery in laravel

I am working with sale invoice app which has an autocomplete jquery script.
it autoload the product id which placed in a hidden field. here's my autocomplete script
//autocomplete script
$(document).on('focus','.autocomplete_txt',function(){
type = $(this).data('type');
if(type =='product_code' )autoType='product_code';
if(type =='product_name' )autoType='name';
if(type =='product_price' )autoType='price';
if(type =='product_cost' )autoType='cost';
if(type =='quantity' )autoType='quantity';
if(type =='product_id' )autoType='id';
$(this).autocomplete({
minLength: 0,
source: function( request, response ) {
$.ajax({
url: "{{ route('searchaSaleItems') }}",
dataType: "json",
data: {
term : request.term,
type : type,
},
success: function(data) {
if(!data.length){
var notFound = [
{
label: 'No matches found',
value: response.term
}
];
response(notFound);
} else {
var array = $.map(data, function (item) {
return {
label: item[autoType],
value: item[autoType],
data : item
}
});
response(array)
}
}
});
},
select: function( event, ui ) {
var data = ui.item.data;
var arr = [];
id_arr = $(this).attr('id');
id = id_arr.split("_");
elementId = id[id.length-1];
$('.product_code').each(function() {
arr.push($(this).val());
});
// added logic to check if there are duplicates in the array we just populated with product codes, checked against the passed in product code
if(arr.includes(data.product_code)) {
$('#add').prop('disabled', true);
$('#submit').prop('disabled', true);
$('#row'+rowCount+'').addClass('danger');
// $('#duplicate_entry_'+elementId).text('Duplicate entry. Replace product code to continue. ');
alert('Duplicate entry. Replace product code to continue. ');
} else {
$('#add').prop('disabled', false);
$('#submit').prop('disabled', false);
$('#row'+rowCount+'').removeClass('danger');
$('#product_code_'+elementId).val(data.product_code).prop('readonly', true);
$('#product_name_'+elementId).val(data.name).prop('readonly', true);
$('#product_cost_'+elementId).val(data.cost);
$('#product_price_'+elementId).val(data.price).prop('min', data.price);
$('#product_id_'+elementId).val(data.id);
$('#quantity_'+elementId).prop('max', data.quantity);
$('#quantity_warning_'+elementId).text('You have '+data.quantity+' in your stocks');
$('#price_minimum_'+elementId).text('The minimum price is '+data.price);
}
}
});
});
and here's the query from my controller
public function salesResponse(Request $request){
$query = $request->get('term','');
$wh2Summaries=Warehouse2StockSummaries::with('product');
if($request->type == 'product_code'){
$wh2Summaries->whereHas('product', function ($q) use ($query) {
$q->where('product_code', 'LIKE', '%' . $query . '%');
});
}
$wh2Summaries=$wh2Summaries->get();
$data=array();
foreach ($wh2Summaries as $wh2Summary) {
$data[]=array(
'product_code'=>$wh2Summary->product->product_code,
'name'=>$wh2Summary->product->name,
'price'=>$wh2Summary->product->selling_price,
'cost'=>$wh2Summary->product->price,
'quantity'=>$wh2Summary->qty_in-$wh2Summary->qty_out,
'id'=>$wh2Summary->product->id
);
}
if(count($data))
return $data;
else
return [
'product_code'=>''
];
}
the whole process is working until my boss wants to add another feature which he calls "quantity range" where in a certain range has its own price and that price should dynamically appear in the price field, so let say 1-10 pcs the price is $100, 11-20 the price will be $200 and so on... So I create another table which I called "price ranges" which give a certain product a multiple quantity range
and I create a relation between products and priceranges
products model
class Products extends Model
{
// use SoftDeletes;
protected $fillable = [
'product_code',
'name',
'categories_id',
'wh1_limit_warning',
'wh2_limit_warning',
'price',
'selling_price',
'user_id'
];
// protected $dates = ['deleted_at'];
public function priceRanges()
{
return $this->hasMany('App\Priceranges', 'product_id', 'id');
}
}
priceranges model
class Priceranges extends Model
{
protected $table = 'priceranges';
protected $fillable = [
'product_id',
'qty_from',
'qty_to',
'amount',
];
public function products()
{
return $this->belongsTo('App\Products', 'id', 'product_id');
}
}
from there I don't know what to do next :(
The condition that I want to achieve is, once the user input a quantity, check if the product_id from the hidden field (provided by the autocomplete)
is available in priceranges table, if it is, check which range the quantity is belong then output the amount.
Please can you help me to accomplish this using jQuery? I do not know much about jQuery. Thank you so much in advance!
The first thing that I believe you should modify in your Model, is the price in the product table, you should remove it. In this way, all product prices will be in one place: The Priceranges table. So, you can set the default "qty_from" to 0 and the "qty_to" to "nullable ()". If "qty_to" is null, it means that the price is "X" between "qty_from" and infinity.
Changed that, let's go to the Controller.
public function salesResponse(Request $request){
$query = $request->get('term','');
$wh2Summaries=Warehouse2StockSummaries::with('product');
if($request->type == 'product_code'){
$wh2Summaries->whereHas('product', function ($q) use ($query) {
$q->where('product_code', 'LIKE', '%' . $query . '%');
});
}
$wh2Summaries=$wh2Summaries->get();
$data=array();
foreach ($wh2Summaries as $wh2Summary) {
$qty = $wh2Summary->qty_out;
$price = $wh2Summary->product->priceRanges()
->where('qty_from', '<=', $qty)
->where(function ($q) use($qty){
$q->where('qty_to', '>=', $qty)->orWhere('qty_to', null);
})->first();
//in this way, you need every product has their priceRange
if(isset($price->id)){
$price = $price->amount; // the price in range chosen
}else{ //get the price from original table, if you does not has removed that
$price = $wh2Summary->product->selling_price;
}
$data[]=array(
'product_code'=>$wh2Summary->product->product_code,
'name'=>$wh2Summary->product->name,
'price'=> $price,
'cost'=>$wh2Summary->product->price,
'quantity'=>$wh2Summary->qty_in-$wh2Summary->qty_out,
'id'=>$wh2Summary->product->id
);
}
if(count($data))
return $data;
else
return [
'product_code'=>''
];
}
This way, you only need to change the Controller, requiring no changes to your JQuery.
Hope this helps you!
I would add a function in my Product model that, given a number, returns the correct price.
public function getCorrectPrice($number) {
$priceRanges = $this->priceRanges;
foreach($priceRanges as $range) {
if ($number >= $range->qty_from && $number < $range->qty_to) {
return $range->amount;
}
}
return $this->price; // If there is no valid range returns the default producr price
}
Now modify your ajax call to include the quantity inserted by the user:
data: {
term : request.term,
type : type,
quantity: quantity, // Get the quantity from the user
},
And in your controller:
$quantity = $request->get('quantity');
$price = $wh2Summary->product->getCorrectPrice($quantity);
NOTE: to get better performance, I suggest you to eager load the price ranges with the products:
$wh2Summaries=Warehouse2StockSummaries::with('product.priceRanges');

Post Data not working correctly Laravel

I have a Route as below that will display a profile depending on the data in the url:
Route::get('/{region}/{summonername}', function () {
return 'Summoner Profile';
});
I have a Form on the Home page which consists of a Input Box and Region Selector. I am posting this data to:
Route::post('/summoner/data');
The problem is that i don't know how i can convert the form data eg. Summoner Name and Region into the url format where the user will be displayed with the profile page and the url would be /{region}/{summonername}. Am i supposed to use a Redirect::to inside my controller? I feel like that is a crappy way of doing it. Any Suggestions?
Right now when i post the data the url displays as '/summoner/data'.
I hope this makes sense, let me know if you need more clarification.
Routes :
Route::post('/summoner/data','ControllerName#FunctionName');
Route::get('/{region}/{summonername}', function () {
return view('SummonerProfile');
});
Controller:
public function FunctionName()
{
$SummonerName = Input::get('SummonerName');
$Region = Input::get('Region');
return Redirect::to('/{$Region}/{$SummonerName}');
}
Hope this will work. Try it!
Using Routes:
Route::post('/summoner/data',function () {
$SummonerName = Input::get('SummonerName');
$Region = Input::get('Region');
return Redirect::to('/{'.$Region.'}/{'.$SummonerName.'}');
});
Route::get('/{region}/{summonername}', function () {
return view('SummonerProfile');
});
Yes, you will need to redirect:
Route::post('/summoner/data', function (Request $request) {
return redirect()->url($request->region .'/'. $request->summonername);
});
If you want to take the data from URL, just do the following
use Illuminate\Http\Request;
Route::post('/summoner/data', function (Request $request) {
echo $request->segment(1); // gives summoner
echo $request->segment(2); // gives data
});

Laravel 4 routes going to wrong route

I've set up routes for a resource and added additional routes for the same controller. I've had this route working and don't think I've changed anything but now it's routing to the wrong method in the controller.
I'm aware of the first in and first out principle of the routes and have this set up at the moment:
Route::post('products/addItemToCart', array('uses' => 'ProductsController#addItemToCart'));
Route::post('products/editItemInCart', array('uses' => 'ProductsController#editItemInCart'));
//Product Related Routes
Route::get('products/saletotal/{id}', function ($id) {
return Product::groupedSales($id);
});
Route::get('products/itemValue/{id}', array('uses' => 'ProductsController#itemValue'));
Route::get('products/cartitem/{id}', array('uses' => 'ProductsController#getCartItem'));
Route::resource('products', 'ProductsController');
I have a form which POSTS to products/addItemToCart for some reason this no longer uses the method addItemToCart but is going to the controllers show method and treating the 2nd parameter as an ID of the record to find.
I placed a var_dump at the start of the show method to identify the value being passed to the show method which is addItemToCart
It's as if the routes file is ignoring the previous routes and skipping to the defaults in the resource route.
Any ideas what mistakes I've made?
Thanks
Update: additional code for fuller picture:
The POST is generated by javascript with this method:
if($('#rowId').val() !=="") {
postUrl = "/products/editItemInCart";
} else {
postUrl = "/products/addItemToCart";
}
$.ajax({
type: "POST",
url: postUrl,
data: item,
dataType: 'json',
success: function(result) {
//update the displayed Cart
var data = result;
updateCart();
}
});
item is an array
The method in Products controller are:
<?php
//updated 08-11-2013
class ProductsController extends BaseController {
/**
* Product Repository
*
* #var Product
*/
protected $product;
public function __construct(Product $product)
{
$this->product = $product;
}
public function addItemToCart() {
$product = Product::find( Input::get( 'id' ) );
//method code
}
**
* Display the specified resource.
*
* #param int $id
* #return Response
*/
public function show($id)
{
dd($id);
$product = $this->product->findOrFail($id);
return View::make('products.show', compact('product'));
}
the show method is being used instead of the expected addToCart method as specified in the URL and route
I can see the exected items in the POST from within firebug
You need to add the parameter expectation to the route string.
Route::post('products/addItemToCart/{id}', array('uses' => 'ProductsController#addItemToCart'));
Otherwise the resource controller interprets this as products/{param}/{param} hence why it goes to the default post implementation of the controller.

Categories