php 如何解决laravel livewire错误Illuminate\View\ViewException:无法解析依赖项

ovfsdjhp  于 2023-09-29  发布在  PHP
关注(0)|答案(1)|浏览(114)

我试着把laravel/ui替换成livewire组件。php和ResetPasswordController.php是要替换的目标。
Laravel版本是10.21.0,Livewire版本是v3.0.5。
首先,下面是route/web.php的部分内容:

Auth::routes([
    'login' => true, 'logout' => true, 'confirm' => true, 'verify' => true,
]);

Route::middleware('guest')->group(function () {
    Route::get('register', App\Livewire\Auth\RegisterComponent::class)
        ->name('register');
    Route::post('register', [App\Livewire\Auth\RegisterComponent::class, 'register']);
    Route::get('password/reset/{token}', App\Livewire\Auth\ResetPasswordComponent::class)
        ->name('password.reset');
    Route::post('password/reset', [App\Livewire\Auth\ResetPasswordComponent::class, 'update'])
        ->name('password.update');
});

App\Livewire\Auth\RegisterComponent.php基于Illuminate\Foundation\Auth\RegistersUsers.php。更改是我需要验证$name、$email和$password而不是$request,如下所示:

<?php

namespace App\Livewire\Auth;

use ...

class RegisterComponent extends Component
{
    use RedirectsUsers;

    public string $title = '';
    public string $name = '';
    public string $email = '';
    public string $password = '';

    /**
     * Where to redirect users after registration.
     *
     * @var string
     */
    protected $redirectTo = '/email/verify';

    /**
     * Handle a registration request for the application.
     *
     * @param Request $request
     *
     * @return Application|\Illuminate\Foundation\Application|RedirectResponse|Redirector
     *
     * @throws ValidationException
     */
    public function register(Request $request)
    {
        $this->validator()->validate();

        event(new Registered($user = $this->create()));

        $this->guard()->login($user);

        return redirect($this->redirectPath());
    }

    /**
     * Get the password reset validation rules.
     *
     * @return array
     */
    public function rules(): array
    {
        return [
            User::NAME => ['required','string','max:255'],
            User::EMAIL => ['required','string','email','max:255','unique:users'],
            User::PASSWORD => ['required',Password::min(12)->letters()->mixedCase()->numbers()->symbols()->uncompromised(),'zxcvbn:3'],
        ];
    }

    public function render(): View
    {
        return view('livewire.auth.register-component')
            ->layout('components.layouts.auth');
    }

    public function mount(): void
    {
        $this->title = config('app.name') . ' - ' . 'Registration';
    }

    /**
     * Get a validator for an incoming registration request.
     */
    protected function validator(): \Illuminate\Contracts\Validation\Validator
    {
        return Validator::make([
            User::NAME => $this->name,
            User::EMAIL => $this->email,
            User::PASSWORD => $this->password,
        ], $this->rules());
    }

    /**
     * Get the guard to be used during registration.
     *
     * @return StatefulGuard
     */
    protected function guard(): StatefulGuard
    {
        return Auth::guard();
    }

    /**
     * The user has been registered.
     *
     * @param  mixed  $user
     * @return mixed
     */
    protected function registered($user)
    {
        //
    }

    /**
     * Create a new user instance after a valid registration.
     */
    protected function create(): User
    {
        return User::create([
            User::NAME => $this->name,
            User::EMAIL => $this->email,
            User::PASSWORD => Hash::make($this->password),
            User::API_TOKEN => Str::random(80),
            User::ROLE_ID => RoleType::USER,
        ]);
    }
}

该组件对应的视图部分如下:

<form wire:submit="register">
                        <div class="form-group row py-2">
                            <label for="name" class="col-md-4 col-form-label text-md-end">{{ __('Name') }}</label>
                            <div class="col-md-6">
                                <input wire:model="name" required autofocus type="text" class="form-control @error('name') is-invalid @enderror" id="name" autocomplete="name" />
                                @error('name')
                                    <span class="invalid-feedback" role="alert">
                                        <strong>{{ $message }}</strong>
                                    </span>
                                @enderror
                            </div>
                        </div>

                        <div class="form-group row py-2">
                            <label for="email" class="col-md-4 col-form-label text-md-end">{{ __('E-Mail Address') }}</label>
                            <div class="col-md-6">
                                <input wire:model="email" required type="email" class="form-control @error('email') is-invalid @enderror" id="email" autocomplete="email" />
                                @error('email')
                                    <span class="invalid-feedback" role="alert">
                                        <strong>{{ $message }}</strong>
                                    </span>
                                @enderror
                            </div>
                        </div>

                        <div class="form-group row py-2">
                            <label for="password" class="col-md-4 col-form-label text-md-end">{{ __('Password') }}</label>
                            <div class="col-md-6 input-group">
                                <input wire:model="password" required type="password" class="form-control @error('password') is-invalid @enderror" id="password" autocomplete="current_password" />
                                <span class="mt-1 small">
                                    {{ __('application.user.columns.password.note') }}
                                </span>
                                @error('password')
                                    <span class="invalid-feedback" role="alert">
                                        <strong>{{ $message }}</strong>
                                    </span>
                                @enderror
                            </div>
                        </div>

                        <div class="form-group row py-2">
                            <div class="col-md-6 offset-md-4">
                                <button type="submit" class="btn btn-outline-warning">
                                    {{ __('Sign up') }}
                                </button>
                            </div>
                        </div>
                    </form>

App\Livewire\Auth\ResetPasswordComponent.php也基于Illuminate\Foundation\Auth\ResetsPasswords.php。这也是为了验证$token、$email和$password,而不是$request。
mount()方法尝试从路由中解析$token。

<?php

namespace App\Livewire\Auth;

use ...

class ResetPasswordComponent extends Component
{
    use RedirectsUsers;
    use RedirectByStatus;

    public const TOKEN = 'token';

    public string $token = '';
    public string $email = '';
    public string $password = '';

    /**
     * Where to redirect users after resetting their password.
     *
     * @var string
     */
    protected $redirectTo = '/home';

    public function update(Request $request)
    {
        $validated = $this->validator()->validate();

        // Here we will attempt to reset the user's password. If it is successful we
        // will update the password on an actual user model and persist it to the
        // database. Otherwise we will parse the error and return the response.
        $response = $this->broker()->reset(
            $this->credentials(), function ($user, $password) {
                $this->resetPassword($user, $password);
            }
        );

        // If the password was successfully reset, we will redirect the user back to
        // the application's home authenticated view. If there is an error we can
        // redirect them back to where they came from with their error message.
        return $response == \Illuminate\Support\Facades\Password::PASSWORD_RESET
            ? $this->sendResetResponse($request, $response)
            : $this->sendResetFailedResponse($request, $response);
    }

    /**
     * Get the password reset validation rules.
     *
     * @return array
     */
    public function rules(): array
    {
        return [
            self::TOKEN => ['required'],
            User::EMAIL => ['required','email'],
            User::PASSWORD => ['required',Password::min(12)->letters()->mixedCase()->numbers()->symbols()->uncompromised(),'zxcvbn:3'],
        ];
    }

    /**
     * Get the broker to be used during password reset.
     *
     * @return PasswordBroker
     */
    public function broker()
    {
        return \Illuminate\Support\Facades\Password::broker();
    }

    public function render(): View
    {
        return view('livewire.auth.reset-password-component')
            ->layout('components.layouts.auth');
    }

    public function mount(string $token): void
    {
        $this->token = $token;
        $this->title = config('app.name') . ' - ' . 'Reset Password';
    }

    /**
     * Get a validator for an incoming registration request.
     */
    protected function validator(): \Illuminate\Contracts\Validation\Validator
    {
        return Validator::make([
            self::TOKEN => $this->token,
            User::EMAIL => $this->email,
            User::PASSWORD => $this->password,
        ], $this->rules());
    }

    /**
     * Get the password reset validation error messages.
     *
     * @return array
     */
    protected function validationErrorMessages()
    {
        return [];
    }

    /**
     * Get the password reset credentials from the request.
     *
     * @param Request $request
     * @return array
     */
    protected function credentials()
    {
        return [
            self::TOKEN => $this->token,
            User::EMAIL => $this->email,
            User::PASSWORD => $this->password,
        ];
    }

    /**
     * Reset the given user's password.
     *
     * @param  \Illuminate\Contracts\Auth\CanResetPassword  $user
     * @param  string  $password
     * @return void
     */
    protected function resetPassword($user, $password)
    {
        $this->setUserPassword($user, $password);

        $user->setRememberToken(Str::random(60));

        $user->save();

        event(new PasswordReset($user));

        $this->guard()->login($user);
    }

    /**
     * Set the user's password.
     *
     * @param  \Illuminate\Contracts\Auth\CanResetPassword  $user
     * @param  string  $password
     * @return void
     */
    protected function setUserPassword($user, $password)
    {
        $user->password = Hash::make($password);
    }

    /**
     * Get the response for a successful password reset.
     *
     * @param Request $request
     * @param  string  $response
     * @return RedirectResponse|\Illuminate\Http\JsonResponse
     */
    protected function sendResetResponse(Request $request, $response)
    {
        return redirect($this->redirectPath())
            ->with('status', trans($response));
    }

    /**
     * Get the response for a failed password reset.
     *
     * @param Request $request
     * @param  string  $response
     * @return RedirectResponse
     */
    protected function sendResetFailedResponse(Request $request, $response)
    {
        return redirect()->back()
            ->withInput($request->only('email'))
            ->withErrors(['email' => trans($response)]);
    }

    /**
     * Get the guard to be used during password reset.
     *
     * @return StatefulGuard
     */
    protected function guard()
    {
        return Auth::guard();
    }
}

该组件对应的视图部分如下:

<form wire:submit="update">
                        <div class="form-group row">
                            <div class="col-md-6">
                                <input wire:model="token" type="hidden" class="form-control @error('token') is-invalid @enderror" id="token" />
                                @error('token')
                                    <span class="invalid-feedback" role="alert">
                                        <strong>{{ $message }}</strong>
                                    </span>
                                @enderror
                            </div>
                        </div>

                        <div class="form-group row py-2">
                            <label for="email" class="col-md-4 col-form-label text-md-right">{{ __('E-Mail Address') }}</label>
                            <div class="col-md-6">
                                <input wire:model="email" required autofocus type="email" class="form-control @error('email') is-invalid @enderror" id="email" autocomplete="email" />
                                @error('email')
                                    <span class="invalid-feedback" role="alert">
                                        <strong>{{ $message }}</strong>
                                    </span>
                                @enderror
                            </div>
                        </div>

                        <div class="form-group row py-2">
                            <label for="password" class="col-md-4 col-form-label text-md-right">{{ __('Password') }}</label>
                            <div class="col-md-6 input-group">
                                <input wire:model="password" required type="password" class="form-control @error('password') is-invalid @enderror" id="password" autocomplete="current_password" />
                                <span class="mt-1 small">
                                    {{ __('application.user.columns.password.note') }}
                                </span>
                                @error('password')
                                    <span class="invalid-feedback" role="alert">
                                        <strong>{{ $message }}</strong>
                                    </span>
                                @enderror
                            </div>
                        </div>

                        <div class="form-group row py-2 mb-0">
                            <div class="col-md-6 offset-md-4">
                                <button type="submit" class="btn btn-primary">
                                    {{ __('Reset Password') }}
                                </button>
                            </div>
                        </div>
                    </form>

我还为这些组件编写了一个测试。RegisterComponentTest.php用于RegisterComponent.php。

<?php

namespace Feature\Livewire\Auth;

use App\Livewire\Auth\RegisterComponent;
use App\Models\User;
use Livewire\Livewire;
use Tests\TestCase;

class RegisterComponentTest extends TestCase
{
    /**
     * @test
     */
    public function renders_successfully()
    {
        Livewire::test(RegisterComponent::class)
            ->assertStatus(200);
    }
}

而ResetPasswordComponentTest.php是ResetPasswordComponent.php的。

<?php

namespace Feature\Livewire\Auth;

use App\Livewire\Auth\ResetPasswordComponent;
use App\Models\User;
use Livewire\Livewire;
use Tests\TestCase;

class ResetPasswordComponentTest extends TestCase
{
    /**
     * @test
     */
    public function renders_successfully()
    {
        $token = 'token';

        Livewire::test(ResetPasswordComponent::class)
            ->call('mount', $token)
//            ->set('token', $token)
            ->assertStatus(200);
    }
}

最后,一切都摆在桌面上。当我运行./vendor/bin/phpunit tests/Feature/Livewire/Auth/RegisterComponentTest.php时,所有测试都通过了,但当我运行./vendor/bin/phpunit tests/Feature/Livewire/Auth/ResetPasswordComponentTest.php时,抛出了以下错误。

There was 1 error:

1) Feature\Livewire\Auth\ResetPasswordComponentTest::renders_successfully
Illuminate\View\ViewException: Unable to resolve dependency [Parameter #0 [ <required> string $token ]] in class App\Livewire\Auth\ResetPasswordComponent (View: /var/www/html/storage/framework/views/a168b0ebcff266df6b662fc4b6d06e88.blade.php)

/var/www/html/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php:188
/var/www/html/vendor/livewire/livewire/src/Mechanisms/ExtendBlade/ExtendedCompilerEngine.php:60
/var/www/html/vendor/laravel/framework/src/Illuminate/View/Engines/PhpEngine.php:60
/var/www/html/vendor/livewire/livewire/src/Mechanisms/ExtendBlade/ExtendedCompilerEngine.php:22
/var/www/html/vendor/laravel/framework/src/Illuminate/View/Engines/CompilerEngine.php:72
/var/www/html/vendor/livewire/livewire/src/Mechanisms/ExtendBlade/ExtendedCompilerEngine.php:10
/var/www/html/vendor/laravel/framework/src/Illuminate/View/View.php:195
/var/www/html/vendor/laravel/framework/src/Illuminate/View/View.php:178
/var/www/html/vendor/laravel/framework/src/Illuminate/View/View.php:147
/var/www/html/vendor/laravel/framework/src/Illuminate/View/Compilers/BladeCompiler.php:333
/var/www/html/vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php:353
/var/www/html/vendor/livewire/livewire/src/Features/SupportTesting/InitialRender.php:26
/var/www/html/vendor/laravel/framework/src/Illuminate/Routing/CallableDispatcher.php:40
/var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Route.php:237
/var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Route.php:208
/var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Router.php:799
/var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:141
/var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:116
/var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Router.php:800
/var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Router.php:777
/var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Router.php:741
/var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Router.php:730
/var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php:200
/var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:141
/var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:116
/var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php:175
/var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php:144
/var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Testing/Concerns/MakesHttpRequests.php:564
/var/www/html/vendor/livewire/livewire/src/Features/SupportTesting/InitialRender.php:32
/var/www/html/vendor/livewire/livewire/src/Features/SupportTesting/RequestBroker.php:30
/var/www/html/vendor/livewire/livewire/src/Features/SupportTesting/InitialRender.php:33
/var/www/html/vendor/livewire/livewire/src/Features/SupportTesting/Render.php:24
/var/www/html/vendor/livewire/livewire/src/Features/SupportTesting/InitialRender.php:34
/var/www/html/vendor/livewire/livewire/src/Features/SupportTesting/InitialRender.php:17
/var/www/html/vendor/livewire/livewire/src/Features/SupportTesting/Testable.php:35
/var/www/html/vendor/livewire/livewire/src/LivewireManager.php:157
/var/www/html/vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php:353
/var/www/html/tests/Feature/Livewire/Auth/ResetPasswordComponentTest.php:19
/var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Testing/TestCase.php:174

Caused by
Illuminate\Contracts\Container\BindingResolutionException: Unable to resolve dependency [Parameter #0 [ <required> string $token ]] in class App\Livewire\Auth\ResetPasswordComponent

/var/www/html/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php:188
/var/www/html/vendor/livewire/livewire/src/ImplicitlyBoundMethod.php:21
/var/www/html/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php:36
/var/www/html/vendor/laravel/framework/src/Illuminate/Container/Util.php:41
/var/www/html/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php:93
/var/www/html/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php:37
/var/www/html/vendor/livewire/livewire/src/Wrapped.php:23
/var/www/html/vendor/livewire/livewire/src/Features/SupportLifecycleHooks/SupportLifecycleHooks.php:125
/var/www/html/vendor/livewire/livewire/src/Features/SupportLifecycleHooks/SupportLifecycleHooks.php:20
/var/www/html/vendor/livewire/livewire/src/ComponentHook.php:19
/var/www/html/vendor/livewire/livewire/src/ComponentHookRegistry.php:45
/var/www/html/vendor/livewire/livewire/src/EventBus.php:60
/var/www/html/vendor/livewire/livewire/src/helpers.php:100
/var/www/html/vendor/livewire/livewire/src/Mechanisms/HandleComponents/HandleComponents.php:57
/var/www/html/vendor/livewire/livewire/src/LivewireManager.php:72
/var/www/html/storage/framework/views/d76adc34f3e5651d58b1e86454689044.php:7
/var/www/html/vendor/laravel/framework/src/Illuminate/Filesystem/Filesystem.php:124
/var/www/html/vendor/laravel/framework/src/Illuminate/Filesystem/Filesystem.php:125
/var/www/html/vendor/laravel/framework/src/Illuminate/View/Engines/PhpEngine.php:58
/var/www/html/vendor/livewire/livewire/src/Mechanisms/ExtendBlade/ExtendedCompilerEngine.php:22
/var/www/html/vendor/laravel/framework/src/Illuminate/View/Engines/CompilerEngine.php:72
/var/www/html/vendor/livewire/livewire/src/Mechanisms/ExtendBlade/ExtendedCompilerEngine.php:10
/var/www/html/vendor/laravel/framework/src/Illuminate/View/View.php:195
/var/www/html/vendor/laravel/framework/src/Illuminate/View/View.php:178
/var/www/html/vendor/laravel/framework/src/Illuminate/View/View.php:147
/var/www/html/vendor/laravel/framework/src/Illuminate/View/Compilers/BladeCompiler.php:333
/var/www/html/vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php:353
/var/www/html/vendor/livewire/livewire/src/Features/SupportTesting/InitialRender.php:26
/var/www/html/vendor/laravel/framework/src/Illuminate/Routing/CallableDispatcher.php:40
/var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Route.php:237
/var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Route.php:208
/var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Router.php:799
/var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:141
/var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:116
/var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Router.php:800
/var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Router.php:777
/var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Router.php:741
/var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Router.php:730
/var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php:200
/var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:141
/var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:116
/var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php:175
/var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php:144
/var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Testing/Concerns/MakesHttpRequests.php:564
/var/www/html/vendor/livewire/livewire/src/Features/SupportTesting/InitialRender.php:32
/var/www/html/vendor/livewire/livewire/src/Features/SupportTesting/RequestBroker.php:30
/var/www/html/vendor/livewire/livewire/src/Features/SupportTesting/InitialRender.php:33
/var/www/html/vendor/livewire/livewire/src/Features/SupportTesting/Render.php:24
/var/www/html/vendor/livewire/livewire/src/Features/SupportTesting/InitialRender.php:34
/var/www/html/vendor/livewire/livewire/src/Features/SupportTesting/InitialRender.php:17
/var/www/html/vendor/livewire/livewire/src/Features/SupportTesting/Testable.php:35
/var/www/html/vendor/livewire/livewire/src/LivewireManager.php:157
/var/www/html/vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php:353
/var/www/html/tests/Feature/Livewire/Auth/ResetPasswordComponentTest.php:19
/var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Testing/TestCase.php:174

正如您所看到的,RegisterComponent.php和ResetPasswordComponent.php非常相似,但我不知道为什么RegisterComponentTest.php通过,而ResetPasswordComponentTest.php失败。
谁能告诉我错误的原因是什么,我应该如何修复它。
先谢了。

zour9fqk

zour9fqk1#

当我查看文档时,似乎不应该通过call调用mount方法,而是应该在最初设置测试组件时传递数据:

Livewire::test(ResetPasswordComponent::class, ['token' => $token])
    ->assertStatus(200);

相关问题