5

抱歉,如果这是一个愚蠢的问题,因为很多 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->validateReset($credentials) 时会出现这种情况。

我现在完全超出了我的深度。我是以正确的方式去做这件事还是完全偏离了正确的道路?

感谢您的任何建议

4

2 回答 2

2

您应该扩展Illuminate\Auth\Reminders\PasswordBroker类,而不是\Illuminate\Support\Facades\Password.

该类\Illuminate\Support\Facades\Password是一个门面,而不是最终类。

您可以通过以下方式查看外墙的最终类:

get_class(Password::getFacadeRoot());
于 2013-05-26T23:57:48.943 回答
2

这里之前的答案通常是正确的,但并不足以解释发生了什么,所以我会试一试。

只需说任何外观方法访问通常都是静态完成的,因此如果您在外观上定义(公共)方法,则应确保它是静态方法。然而,外观实际上是底层非静态类的外观,使用魔法方法将外观上的静态调用传递给底层类的实例方法。因此,您通常不想通过在一个外观上定义一个静态方法来扩展外观,而是在底层类上定义一个实例方法。在Password外观的情况下,底层类是PasswordBroker. 这个底层类dealio通常是通过在IoC容器上注册一个实例来设置的,然后在外观中定义一个getFacadeAccessor外观类的方法,该方法返回查找实例的IoC键。(在这种情况下Password门面,IoC 键是auth.reminder.)

不过,这就是你遇到问题的地方,因为你不能只覆盖 Laravel 核心类。最正确的做法可能是扩展PasswordBroker类的版本,然后将其设置为 IoC 中 Password 门面通常使用的键(auth.reminder)。这样,您添加的方法将在外观上可用,btu 任何其他内容仍将遵循原始PasswordBroker类。


您会注意到您不必创建新外观,而只需覆盖现有外观的 IoC 键。何时执行此操作可能有点棘手。如果您没有使用自己的服务提供商,而是在其中做这些routes.php事情,那么您可能是安全的。但是,如果您使用服务提供商来修改此密码行为,您不能(不应该)实际上依赖 Laravel 调用服务提供商register方法的顺序(实际上它似乎按照设置的顺序进行在app/config/app.php,但嘿忽略这一点,这是未定义的行为,所以不要依赖它)。因此,您不知道您的服务提供者是否register在 Laravel 的核心身份验证服务提供者之前或之后调用了它的方法。

我不知道解决这个问题的官方方法,但我能想到的唯一方法是在服务提供者的boot方法而不是它的register方法中进行注册。您可以保证任何给定boot的方法总是在所有其他服务提供者的register方法之后被调用,因此您将覆盖 Laravel 核心密钥,并且您的密钥不会被任何正常的 Laravel 设置覆盖。但是,在boot方法中执行它意味着理论上您可能为时已晚,如果您尝试增强的功能可能在另一个服务提供者的boot方法中被调用,则无法执行您想要的操作。

或者,创建自己的外观,使用您自己选择的键并将其设置为正常(即在您的register方法中注册实例)。然后用你的外观替换密码的别名。它更像样板,但工作更可靠。

于 2014-03-26T14:22:22.190 回答