道歉,如果这是一个愚蠢的问题,因为很多Laravel 4对我来说都是新手。我试图覆盖核心密码功能中的几个方法,因为我想定义自己的密码验证规则(在发布时硬编码到核心),并更改错误报告的方法($ errors数组用于其他形式,而不是基于会话的。)
所以我的方法是在/ app / lib / MyProject / User中创建一个名为Password.php的新类,如下所示:
<?php namespace MyProject\User;
use Closure;
use Illuminate\Mail\Mailer;
use Illuminate\Routing\Redirector;
use Illuminate\Auth\UserProviderInterface;
class Password extends \Illuminate\Support\Facades\Password
{
/**
* Reset the password for the given token.
*
* @param array $credentials
* @param Closure $callback
* @return mixed
*/
public function reset(array $credentials, Closure $callback)
{
// If the responses from the validate method is not a user instance, we will
// assume that it is a redirect and simply return it from this method and
// the user is properly redirected having an error message on the post.
$user = $this->validateReset($credentials);
if ( ! $user instanceof RemindableInterface)
{
return $user;
}
$pass = $this->getPassword();
// Once we have called this callback, we will remove this token row from the
// table and return the response from this callback so the user gets sent
// to the destination given by the developers from the callback return.
$response = call_user_func($callback, $user, $pass);
$this->reminders->delete($this->getToken());
return $response;
}
}
我已经从/vendor/laravel/framework/src/Illuminate/Auth/Reminders/PasswordBroker.php复制了重置方法,这似乎是核心密码外观解析的位置。
然后在我的composer.json文件中,我将以下内容添加到autoload:classmap数组中:
"app/lib/MyProject/User"
最后,在我的/app/config/app.php文件中,我修改了密码别名:
'Password' => 'MyProject\User\Password',
行。在我的routes.php文件中,我有以下几个直接来自文档:
Route::post('password/reset/{token}', function()
{
$credentials = array('email' => Input::get('email'));
return Password::reset($credentials, function($user, $password)
{
$user->password = Hash::make($password);
$user->save();
return 'saved - login';
});
});
当这个reset()方法运行时,我收到以下错误:
非静态方法MyProject \ User \ Password :: reset()不应该静态调用
我扩展的类中的reset()方法不是静态的,所以让我感到惊讶,但是将我的reset方法设置为static会清除该错误。接下来,我收到以下错误:
不在对象上下文中时使用$ this
试图运行$ this-&gt; validateReset($ credentials)。
我现在已经完全脱离了我的深度。我是以正确的方式走这条路还是走完正确的道路?
感谢您的任何建议
答案 0 :(得分:2)
您应该扩展Illuminate\Auth\Reminders\PasswordBroker
课程,而不是\Illuminate\Support\Facades\Password
。
\Illuminate\Support\Facades\Password
类是Facade,而不是最终的类。
您可以通过以下方式查看外墙的最终类别:
get_class(Password::getFacadeRoot());
答案 1 :(得分:2)
此前的答案通常是正确的,但并不足以解释发生了什么,所以我会试一试。
可以说任何Facade方法访问通常是静态完成的,因此如果在外观上定义(公共)方法,则应确保它是静态方法。然而,外观实际上是底层非静态类的外观,使用魔术方法将外观上的静态调用传递给底层类上的实例方法。因此,您通常不希望通过在一个上定义静态方法来扩展外观,而是在底层类上定义实例方法。对于Password
外观,底层类是PasswordBroker
的实例。这个底层类决策通常是通过在IoC容器上注册一个实例来设置的,然后在外观中在facade类上定义一个getFacadeAccessor
方法,该方法返回用于查找实例的IoC密钥。 (对于Password
外观,IoC密钥为auth.reminder
。)
这是您遇到问题的地方,因为您无法覆盖Laravel核心类。最正确的做法是扩展PasswordBroker
,然后将类的版本设置为密码门面通常使用的IoC中的密钥(auth.reminder
)。这样,您添加的方法将在外观上可用,btu其他任何内容仍将遵循原始PasswordBroker
类。
您会注意到您不必创建新的外观,而只是覆盖现有外观的IoC密钥。什么时候这样做可能有点棘手。如果您没有使用自己的服务提供商,并在routes.php
或其他内容中执行此操作,那么您可能很安全。但是,如果您使用服务提供商来修改此密码行为,则您不能(不应该)实际上依赖于Laravel对服务提供商的呼叫顺序&#39; register
方法(实际上它似乎按照它在app/config/app.php
中设置的顺序排列,但是嘿忽略它,它的未定义行为所以不要依赖它)。因此,您不知道您的服务提供商是否在Laravel的核心身份验证服务提供商之前或之后调用了register
方法。
我不知道对此进行排序的正式方法,但我能想到的唯一方法是在服务提供商的boot
方法中进行注册,而不是{{1 }} 方法。您可以保证在所有其他服务提供商之后始终调用任何给定的register
方法&#39; boot
方法,因此您将覆盖Laravel核心密钥,并且您的密钥不会被任何正常的Laravel设置覆盖。但是,使用register
方法执行此操作意味着理论上您可能为时已晚,无法执行您想要的功能,如果您尝试扩充的功能可能会在其他服务提供商boot
中调用方法
或者,做创建自己的外观,使用您自己选择的密钥并将其全部设置为正常(即在boot
方法中注册实例)。然后用您的外观替换Password的别名。它是更多的样板,但工作更可靠。