Search code examples
laraveleloquentlaravel-query-builder

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

  • 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;
        }