68publishers/smart-nette-component

Nette 组件和展示器的功能。通过注解实现授权,模板解析和重载等...

v1.0.0 2022-12-12 01:30 UTC

This package is auto-updated.

Last update: 2024-09-12 05:15:41 UTC


README

此软件包为 Nette 展示器和组件添加了一些有用的功能,例如通过 PHP8 属性实现展示器的授权、动作和信号,通过属性实现组件信号的授权,以及解析组件模板文件。

Checks Coverage Status Total Downloads Latest Version PHP Version

安装

安装 68publishers/smart-nette-component 的最佳方式是使用 Composer

$ composer require 68publishers/smart-nette-component

授权属性

要使用授权属性,您需要注册一个编译器扩展。

extensions:
    component_authorization: SixtyEightPublishers\SmartNetteComponent\Bridge\Nette\DI\ComponentAuthorizationExtension

# The default configuration (you don't need to define it) is as follows:
component_authorization:
    cache: %debugMode%
    scanDirs:
    	- %appDir%
    scanComposer: yes
    scanFilters:
    	- *Presenter
    	- *Control
    	- *Component

在折叠 DI 容器时,属性可以被缓存以避免在运行时使用反射。该扩展将自动创建类映射和所有属性的映射,只需知道在哪里查找展示器和组件即可。这是通过 scanDirsscanComposerscanFilters 选项完成的,它们的行为类似于 nette/application

现在,将以下特质添加到您的 BasePresenterBaseControl

use Nette\Application\UI\Presenter;
use SixtyEightPublishers\SmartNetteComponent\Bridge\Nette\Application\AuthorizationTrait;

abstract class BasePresenter extends Presenter
{
    use AuthorizationTrait;
}
use Nette\Application\UI\Control;
use SixtyEightPublishers\SmartNetteComponent\Bridge\Nette\Application\AuthorizationTrait;

abstract class BaseControl extends Control
{
    use AuthorizationTrait;
}

从现在开始,您可以在展示器和组件中使用授权属性

use SixtyEightPublishers\SmartNetteComponent\Attribute\LoggedIn;
use SixtyEightPublishers\SmartNetteComponent\Attribute\Allowed;

#[LoggedIn]
final class AdminProductPresenter extends BasePresenter
{
    #[Allowed('product_resource', 'add')]
    public function actionAdd(): void {}

    #[Allowed('product_resource', 'delete')]
    public function handleDelete(): void {}
}
use SixtyEightPublishers\SmartNetteComponent\Attribute\LoggedIn;
use SixtyEightPublishers\SmartNetteComponent\Attribute\Allowed;

final class EditOrderControl extends BaseControl
{
    #[Allowed('order_resource', 'delete_item')]
    public function handleDeleteItem(): void {}
}

如果属性中的任何条件未满足,展示器/组件将抛出异常 SixtyEightPublishers\SmartNetteComponent\Exception\ForbiddenRequestException

此软件包包括以下属性

  • Allowed
  • InRole
  • LoggedIn
  • LoggedOut

如果您想以某种方式对抛出的异常做出反应,可以在展示器/组件中重写 onForbiddenRequest() 方法。

protected function onForbiddenRequest(ForbiddenRequestException $exception): void
{
    # `$exception->rule` contains failed attribute
    
    $this->flashMessage('You don\'t have access here!', 'error');
    $this->redirect('Homepage:');
}

自定义授权属性

您可以通过以下方式注册自己的属性

use SixtyEightPublishers\SmartNetteComponent\Attribute\AttributeInterface;
use SixtyEightPublishers\SmartNetteComponent\Authorization\RuleInterface;
use SixtyEightPublishers\SmartNetteComponent\Authorization\RuleHandlerInterface;
use SixtyEightPublishers\SmartNetteComponent\Exception\ForbiddenRequestException;

final class CustomRule implements AttributeInterface, RuleInterface
{
    # ...
}

final class CustomRuleHandler implements RuleHandlerInterface
{
    public function canHandle(RuleInterface $rule): bool
    {
        return $rule instanceof CustomRule;
    }

    public function __invoke(RuleInterface $rule): void
    {
        assert($rule instanceof CustomRule);

        if (...) {
            throw new ForbiddenRequestException($rule);
        }
    }
}
services:
    -
        autowired: no
        factory: CustomRuleHandler

模板解析

要使用此功能,无需注册任何编译器扩展,只需在 BaseControl 中使用 TemplateResolverTrait 特质。

use Nette\Application\UI\Control;
use SixtyEightPublishers\SmartNetteComponent\Bridge\Nette\Application\TemplateResolverTrait;

abstract class BaseControl extends Control
{
    use TemplateResolverTrait;
}

基本 render() 方法已在特质中声明。要向模板分配变量,我们可以使用 beforeRender() 方法。您还可以定义自定义 render*() 方法,该方法在调用 {control myControl:foo} 时用于渲染。

final class MyControl extends BaseControl
{
    protected function beforeRender(): void
    {
        # assign variables into the template here
    }

    public function renderFoo(): void
    {
        $this->doRender('foo');
    }
}

基本渲染方法的模板将被解析为 COMPONENT_DIRECTORY/templates/myControl.latteCOMPONENT_DIRECTORY/templates/MyControl.latte

渲染方法 foo 的模板将被解析为 COMPONENT_DIRECTORY/templates/foo.myControl.latteCOMPONENT_DIRECTORY/templates/foo.MyControl.latte

当然,您可以手动设置模板文件

final class MyPresenter extends BasePresenter
{
    protected function createComponentMyControl() : FooControl
    {
        $control = $this->myControlFactory->create();

        $control->setFile(__DIR__ . '/path/to/file.latte');
        # or relatively from a component's directory:
        $control->setRelativeFile('templates/new/myControl.latte');

        # you can change the template for a specific render type:
        $control->setFile(__DIR__ . '/path/to/myControl.latte', 'foo'); # template for `renderFoo()`

        return $control;
    }
}

贡献

在打开拉取请求之前,请使用以下命令检查您的更改

$ make init # to pull and start all docker images

$ make cs.check
$ make stan
$ make tests.all