'Laravel having column name in where clause static method
Recently I just realized that Laravel generates a static method with column name when joined in a where clause using camel case
example
$user = User::whereName('john')->first(); // added `name` as a column name
When called this code to SQL it generates
$user = User::whereName('john')->toSql();
//it returns
select * from `users` where `name` = ?
This indeed gives expected result as it returns a user with name john
.
I have searched Laravel documentation but can't find this function or where it was defined.
All I need is clarification if this method is good or best so that I can continue using it and as well know how the method is generated inside Laravel framework or any other means
Solution 1:[1]
If you're asking where is the code responsible for it to work, it's using the magic method __call()
(__callStatic()
before that to make an instance) in the class Illuminate\Database\Query\Builder
/**
* Handle dynamic method calls into the method.
*
* @param string $method
* @param array $parameters
* @return mixed
*
* @throws \BadMethodCallException
*/
public function __call($method, $parameters)
{
if (static::hasMacro($method)) {
return $this->macroCall($method, $parameters);
}
if (Str::startsWith($method, 'where')) {
return $this->dynamicWhere($method, $parameters);
}
static::throwBadMethodCallException($method);
}
precisely in the condition Str::startsWith($method, 'where')
which redirect the call to dynamicWhere()
/**
* Handles dynamic "where" clauses to the query.
*
* @param string $method
* @param array $parameters
* @return $this
*/
public function dynamicWhere($method, $parameters)
{
$finder = substr($method, 5);
$segments = preg_split(
'/(And|Or)(?=[A-Z])/', $finder, -1, PREG_SPLIT_DELIM_CAPTURE
);
// The connector variable will determine which connector will be used for the
// query condition. We will change it as we come across new boolean values
// in the dynamic method strings, which could contain a number of these.
$connector = 'and';
$index = 0;
foreach ($segments as $segment) {
// If the segment is not a boolean connector, we can assume it is a column's name
// and we will add it to the query as a new constraint as a where clause, then
// we can keep iterating through the dynamic method string's segments again.
if ($segment !== 'And' && $segment !== 'Or') {
$this->addDynamic($segment, $connector, $parameters, $index);
$index++;
}
// Otherwise, we will store the connector so we know how the next where clause we
// find in the query should be connected to the previous ones, meaning we will
// have the proper boolean connector to connect the next where clause found.
else {
$connector = $segment;
}
}
return $this;
}
Solution 2:[2]
This approach is completely legit, thou not well documented. In Query\Builder
it utilize the __call
function overwrite to produce the functionality and you can see the exact function here.
The subject of magic methods and the __call
function, is often highly debatable if they are for the better. If you utilize IDE helper. It will actually type hint the methods for you and therefor alleviate some of the magical approaches it takes and provide you with a smooth IDE experience.
An example of the generated type hints from a local project i have.
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereEmail($value)
Therefor i would not be worried that this is not the best approach. There are many ways of doing what you are doing, but this one is one of the correct ones.
Solution 3:[3]
Try This
$user = User::where('name','john')->first();
Solution 4:[4]
you need to define this function in your model
//controller
$userObj=new \App\User();
$userObj->whereName('john');
//model
function whereName($name){
return $this->where('name',$name)->first();
}
Solution 5:[5]
if you are concerned about whether this is a best practice or not, I'd say it is not, don't use these magic methods, why:
- when you do a global search of where that column is used, you will not have these magic methods in the results (unless you remember to do another search for the where explicitly).
- static code analysis tools will have a hard time identifying these methods, even if you are not using such a tool now, you may use it in the feature.
- this is an odd thing, you don't get IDE support for it unless you add a third party specifically for it.
- it is confusing, imagine you have a column with a capital letter for some reason, how you will deal with it?
- you can't do bulk where using this method, i.e
->where(['name' => 'moh', 'user_id'=> 2])
, thus, 1. if you have a lot of columns to query about, you will end up with with some lines instead of just passing an array 2. if you have an array to query about, let us say that comes from the frontend, then you end up using the normal where instead. - Based on the previous 2 points, you may have inconsistency in your code, sometimes using the magic methods and sometimes not.
- it lacks documentary.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | N69S |
Solution 2 | mrhn |
Solution 3 | Naeem Ijaz |
Solution 4 | PHP Geek |
Solution 5 |