I have variable sets all my views in AppServiceProvider when I use that variable in the controller it says:
Undefined variable
Code
AppServiceProvider.php
View::composer('*', function ($view) {
$ProductSettings = ProductSetting::all();
foreach($ProductSettings as $psetting){
$show_unavailable = $psetting->show_unavailable;
$show_quantities = $psetting->show_quantities;
$product_pagination = $psetting->pagination;
$max_short_desc = $psetting->max_short_desc;
$allow_delivery_time = $psetting->allow_delivery_time;
$addtocart_on_attribute = $psetting->addtocart_on_attribute;
$outofstock_lable = $psetting->outofstock_lable;
$product_orderby = $psetting->orderby;
}
$view->with('show_unavailable', $show_unavailable);
$view->with('show_quantities', $show_quantities);
$view->with('product_pagination', $product_pagination);
$view->with('max_short_desc', $max_short_desc);
$view->with('allow_delivery_time', $allow_delivery_time);
$view->with('addtocart_on_attribute', $addtocart_on_attribute);
$view->with('outofstock_lable', $outofstock_lable);
$view->with('product_orderby', $product_orderby);
});
Controller
//codes...
$products = Product::whereHas('categories', function ($query) use ($slug) {
$query->where('slug', $slug);
})->paginate($product_pagination);
//codes...
Based on my database values product_pagination is set to 12 which means my code is like: ->paginate(12);
Question
Any idea why I get undefined error?
Update
table
Based on the comments, I am going to assume this will work:
$products = Product::whereHas('categories', function ($query) use ($slug) {
$query->where('slug', $slug);
})->paginate(ProductSetting::first()->pagination);
Since you are only ever having one row in your product_settings table you can simply access the first row of that table, from there you can access any columns you need.
Edit 1
Based on the response, apparently the above is "too long".
The only other alternative I have for this question is the following:
App::singleton('product_settings', function () {
return ProductSetting::first();
});
Write this method within the AppServiceProvider (or any provider of your choice), within the boot method.
Then, this can then be used anywhere with the following code:
app('product_settings')->pagination;
// or, more simply:
app('product_settings')-><some column name>;
If you think that there is still too much code then you can register your original variables using the same format with the singleton method and just add the -><some column name> after the first method call.
Edit 2
The above edit doesn't do anything different from the original solution and will still query with each call to the app method.
If you want to keep the database calls to one per controller, then you can store the ProductSetting::first() onto the BaseController:
class BaseController extends \Controller
{
protected $product_settings;
public function __construct()
{
// Fetch the Site Settings object
$this->product_settings = ProductSetting::first();
}
}
Then within every controller you can call $this->product_settings->pagination.
Related
Edit function:
public function editCheck($id, LanguagesRequest $request)
{
try{
$language = language::select()->find($id);
$language::update($request->except('_token'));
return redirect()->route('admin.languages')->with(['sucess' => 'edit done by sucsses']);
} catch(Exception $ex) {
return redirect()->route('admin.addlanguages');
}
}
and model or select function
public function scopeselect()
{
return DB::table('languages')->select('id', 'name', 'abbr', 'direction', 'locale', 'active')->get();
}
This code is very inefficient, you're selecting every record in the table, then filtering it to find your ID. This will be slow, and is entirely unnecessary. Neither are you using any of the Laravel features specifically designed to make this kind of thing easy.
Assuming you have a model named Language, if you use route model binding, thing are much simpler:
Make sure your route uses the word language as the placeholder, eg maybe your route for this method looks like:
Route::post('/languages/check/{language}', 'LanguagesController#editCheck');
Type hint the language as a parameter in the method:
public function editCheck(Language $language, LanguagesRequest $request) {
Done - $language is now the single model you were afer, you can use it without any selecting, filtering, finding - Laravel has done it all for you.
public function editCheck(Language $language, LanguagesRequest $request) {
// $language is now your model, ready to work with
$language::update($request->except('_token'));
// ... etc
If you can't use route model binding, or don't want to, you can still make this much simpler and more efficient. Again assuming you have a Language model:
public function editCheck($id, LanguagesRequest $request) {
$language = Language::find($id);
$language::update($request->except('_token'));
// ... etc
Delete the scopeselect() method, you should never be selecting every record in your table. Additionally the word select is surely a reserved word, trying to use a function named that is bound to cause problems.
scopeselect() is returning a Collection, which you're then trying to filter with ->find() which is a method on QueryBuilders.
You can instead filter with ->filter() or ->first() as suggested in this answer
$language = language::select()->first(function($item) use ($id) {
return $item->id == $id;
});
That being said, you should really find a different way to do all of this entirely. You should be using $id with Eloquent to get the object you're after in the first instance.
in my controller in my show function in laravel i want the get the id that shows in browser show when i browse it it shows like this
http://localhost:8000/admin/invoices/1
i want to get that "1" and use it in show controller like below
public function show(Invoice $invoice)
{
$clients = Invoice::with('user','products')->get();
$invoice_id = 1;
$invoices = Invoice::with('products')->where('id', '=', $invoice_id)->firstOrFail();
return view('admin.invoices.show', compact('invoice','invoices'),compact('clients'));
}
and put it instead of $invoice_id so when every my client visit this page only sees the related invoice products . thanks you for help
If you're actually getting an instance of Invoice passed to your show method then it likely means you have Route-Model Binding set up for your project. Laravel is looking at the defined route and working out that the ID part (1) should map to an instance of Invoice and is doing the work to grab the record from the database for you.
The Invoice object passed through should refer to an item in your database with the ID of 1, so to get the ID that was mapped in the route you can simply just do:
public function show(Invoice $invoice)
{
echo $invoice->id; // This should be 1
Laravel supports route model binding out of the box these days, but in earlier versions you had to set it up in app/Providers/RouteServiceProvider.php. If you don't want it, try replacing your show method signature with this:
public function show($id)
{
echo $id; // Should be 1
By removing the type-hint you're simply expecting the value that was given in the route parameter and Laravel won't try to resolve it out of the database for you.
Simple way you may try this.
//Define query string in route
Route::get('admin/invoice/{id}','ControllerName#show')
//Get `id` in show function
public function show(Invoice $invoice,$id)
{
$invoice_id = $id;
}
Try using $invoiceId
public function show(Invoice $invoice, $invoiceId)
{
$clients = Invoice::with('user','products')->get();
$invoices = Invoice::with('products')->findOrFail($invoiceId);
return view('admin.invoices.show', compact('invoice','invoices'),compact('clients'));
}
do this if you want to get the url segment in controller.
$invoice_id = request()->segment(3);
if you want this in view
{{ Request::segment(3) }}
Goodluck!
Usually happens when giving a route name different from the controller name
Example:
Route::resource('xyzs', 'AbcController');
Expected:
Route::resource('abcs', 'AbcController');
I'm looking for a way to make a dynamic & global model filter in Laravel.
I'm imagining a function like the following in my User.php model:
public function filter() {
return ($someVariable === true);
}
Whenever I do a query using Eloquent's query builder, I only want users to show up in the collection when the filter above returns true. I would have thought a feature like that existed, but a quick look at the documentation suggests otherwise. Or did I miss it?
I believe what you're looking for is Query Scopes.
They are methods that may be defined in a global or local context, that mutate the current query for a given model.
https://laravel.com/docs/5.5/eloquent#query-scopes
For example:
Lets say I have a database table called "Teams" and it has a column on it called "Wins." If I wanted to retrieve all Teams that had a number of Wins between Aand B I could write the following Local scope method on the teams model:
public function scopeWinsBetween($query, int $min, int $max)
{
return $query->whereBetween('wins', $min, $max);
}
And it could be invoked as such:
$teams = Teams::winsBetween(50, 100)->get();
I think you could use Collection macro but you will need to suffix all your eloquent get(); to get()->userDynamicFilter();
Collection::macro('userDynamicFilter', function () {
//$expected = ...
return $this->filter(function ($value) use($expected) {
return $value == $expected;
});
});
Thanks. For now I've simply added a post filter option to the models using the following code:
// Apply a post filter on the model collection
$data = $data->filter(function($modelObject) {
return (method_exists($modelObject, 'postFilter')) ? $modelObject->postFilter($modelObject) : true;
});
in Illuminate/Database/Eloquent/Builder.php's get() function, after creating the collection. This allows me to add a function postFilter($model) into my model which returns either true or false.
Probably not the cleanest solution but a working one for now.
I want the $searchName value passed to the executeMapSearch() function.
And run the query in executeMapSearch() function.
This is my MainController class.
In the search() function , I am getting the $name value from a Blade View.
class MainController extends Controller {
public function search() {
$name = Input::get('input-16');
$searchName = $name . "%";
//some code
}
public function executeMapSearch() {
$markers = DB::table('markers')
->leftJoin('locations','markers.locations_id', '=', 'locations.id')
->select('markers.*')
->whereRaw('locations.name LIKE "'.$searchName.'"')
->get();
return View::make('main.results')
->with('title','marks')
->with('mark',$markers);
}
}
My Route file is as follows:
Route::any('main/search', 'Main\MainController#search');
Route::any('main/executeMapSearch', 'Main\MainController#executeMapSearch');
Am I missing something here? Should be able to just set the controller like so:
public function executeMapSearch($searchname)
Then in search()
return $this->executeMapSearch($searchname);
First of all, I don't understand if you really need to use search in controller. Looking at your code, you don't need at all:
Route::any('main/search', 'Main\MainController#search');
but you put only a piece of code so i's hard to say.
If you want to run any function in your controller, you can use it the same as you use methods in PHP classes, so in this case, you could use:
->whereRaw('locations.name LIKE "'.$this->search().'"')
instead of
->whereRaw('locations.name LIKE "'.$searchName.'"')
However if your search method returns Response, you should probably create one extra function to calculate searchName only and use it in both search and executeMapSearch methods.
I'm trying to implement an "approved' state for a table I have, it's pretty straightforward, basically, if the row's approve column equals 1; that row should be retrieved, otherwise it shouldn't.
The problem is, now I have to go through the whole codebase and add a WHERE statement(i.e., function call) which is not only time consuming but also inefficient(if I ever want to remove that feature, etc.)
How can I do that? Is it as easy as adding $this->where(..) inside the Eloquent child class' constructor? Wouldn't that affect other CRUD operations? such as not updating an unapproved row?
The answer was given when there was no query scope feature available.
You can override the main query, only for the Post model, like
class Post extends Eloquent
{
protected static $_allowUnapprovedPosts = false;
public function newQuery()
{
$query = parent::newQuery();
if (!static::$_allowUnapprovedPosts) {
$query->where('approved', '=', 1);
} else {
static::$_allowUnapprovedPosts = false;
}
return $query;
}
// call this if you need unapproved posts as well
public static function allowUnapprovedPosts()
{
static::$_allowUnapprovedPosts = true;
return new static;
}
}
Now, simply use anything, but unapproved users won't appear in the result.
$approvedPosts = Post::where('title', 'like', '%Hello%');
Now, if you need to retrieve all posts even unapproved ones then you can use
$approvedPosts = Post::allowUnapprovedPosts()->where('title', 'like', '%Hello%');
Update (Using the query scope):
Since, Laravel now provides Global Query Scopes, leverage that instead of this hacky solution, notice the date of this answer, it's too old and so much things changed by now.
// Using a local query scope
class Post extends Eloquent
{
public function scopeApproved($query)
{
return $query->where('approved', 1);
}
}
You can use it like:
$approvedPosts = Post::approved()->get();
The closest thing I found is Eloquent query scope.
Even though it requires a minor change in my code(prefixing queries) it still gives me what I'm looking with great flexibility.
Here's an example:
Create a function within the Eloquent child class:
class Post extends Eloquent {
public function scopeApproved($query)
{
return $query->where('approved', '=', 1/*true*/);
}
}
Then simply use it like this:
$approvedPosts = Post::approved()-><whatever_queries_you_have_here>;
Works perfectly. No ugly repeated WHERE function calls. easy to modify. Much easier to read(approved() makes much more sense than where('approved', '=', 1) )
You can use global scope for your need, docs for that are here : https://laravel.com/docs/5.6/eloquent#query-scopes
Good example is SoftDeletingScope which is applied to all queries by default on models which use SoftDeletes trait.