I want to paginate a custom static function.
When using Eloquent goes like this People::paginate(5); and paginates the results.
I need to do the same for this static function People::getOwners();
Just do your query and pagination in the function, like this:
public function getOwners() {
return self::query()->paginate(5);
}
Depending on what is going on inside getOwners(), you could turn it into a query scope. On your People model, add the function:
public function scopeGetOwners($query) {
// $query->where(...);
// $query->orderBy(...);
// etc.
$return $query;
}
Now, getOwners() is treated like any other query scope modifier (e.g. where, orderBy, etc.):
People::getOwners()->paginate(5);
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.
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 have a function collectRows that accepts a sqli_result object, and returns the query results as a array of rows:
function collectRows($result) {
...
}
and have another function that accepts a function to decide what to do with the query results before returning them:
function execQuery($query, $resultsF=null) {
...
}
I want to use execQuery like so:
execQuery("SELECT * FROM...", collectRows);
But I get complaints that it can't find the constant "collectRows".
Obviously, I could do something like:
execQuery("SELECT * FROM...", function($result) {
return collectRows($result);
});
But it would be nice to be able to write it a more succinctly.
Is there a way to pass a named function without wrapping it in an anonymous function?
Function name instead of function itself should be passed to a function:
function execQuery($query, $functionName=null) {
if (is_callable($functionName)) {
$functionName();
}
}
And call it:
execQuery("SELECT * FROM...", 'collectRows');
More info about callable type.
Quite simply, you only have to pass the name as a string. PHP doesn't care, it'll deal with it anyway.
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.