Using Laravel 4.1.30 I got this following code which test a sign-in attempt via Auth.
//... more codes here ... $auth = Auth::attempt(array( 'email' => Input::get('email'), 'password' => Input::get('password'), 'active' => 1 ), $remember); if ($auth) { //... more codes here ... }
I like to implement a conditional value such as:
->active > 0
I am using the active (field) as a level of authentication for users signing in. Anything above 0 (zero) should satisfy the next condition.
How can it be done in one statement?
Advertisement
Answer
tl;dr
You can’t do this within the array passed to Auth::attempt()
, because in the framework it is hard coded to use equality comparison in the generated query.
Full review
Framework implementation
The attempt()
function is implemented in Illuminate/Auth/Guard.php
.
public function attempt(array $credentials = array(), $remember = false, $login = true) { $this->fireAttemptEvent($credentials, $remember, $login); $this->lastAttempted = $user = $this->provider->retrieveByCredentials($credentials); // If an implementation of UserInterface was returned, we'll ask the provider // to validate the user against the given credentials, and if they are in // fact valid we'll log the users into the application and return true. if ($this->hasValidCredentials($user, $credentials)) { if ($login) $this->login($user, $remember); return true; } return false; }
Here you can see a call for $this->provider->retrieveByCredentials($credentials);
. The retrieveByCredentials()
function is implemented in Illuminate/Auth/DatabaseUserProvider.php
.
public function retrieveByCredentials(array $credentials) { // First we will add each credential element to the query as a where clause. // Then we can execute the query and, if we found a user, return it in a // generic "user" object that will be utilized by the Guard instances. $query = $this->conn->table($this->table); foreach ($credentials as $key => $value) { if ( ! str_contains($key, 'password')) { $query->where($key, $value); } } // Now we are ready to execute the query to see if we have an user matching // the given credentials. If not, we will just return nulls and indicate // that there are no matching users for these given credential arrays. $user = $query->first(); if ( ! is_null($user)) { return new GenericUser((array) $user); } }
Here you can see that the array you pass to Auth::attempt()
is processed in a foreach
and every key-value pairs are added as a WHERE
clause to the query. Because it done with a $query->where($key, $value);
call, it is limited to equality comparison.
Possible solutions
A workaround would be to change this line to something like:
$query->where($key, $value['operator'], $value['value']);
Then you could restructure the array given to Auth::attempt()
.
$auth = Auth::attempt(array( 'email' => array( 'value' => Input::get('email'), 'operator' => '=' ), 'password' => array( 'value' => Input::get('password'), 'operator' => '=' ), 'active' => array( 'value' => 0, 'operator' => '>' ) ), $remember);
The problem with this is that you have to override every other function that uses this array, so you end up with a custom solution. With this effort you could write your own authentication query or do a check on active
after Auth::attempt()
.