68publishers / smart-nette-component
Nette 组件和展示器的功能。通过注解实现授权,模板解析和重载等...
Requires
- php: ^8.1
- nette/application: ^3.1.0
- nette/di: ^3.0.10
- nette/security: ^3.1.4
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.13
- latte/latte: ^2.5 || ^3.0
- mockery/mockery: ^1.5
- nette/bootstrap: ^3.1
- nette/robot-loader: ^3.4
- nette/tester: ^2.4.3
- phpstan/phpstan: ^1.9
- phpstan/phpstan-nette: ^1.1
- roave/security-advisories: dev-latest
Conflicts
- nette/component-model: <3.0.2
README
此软件包为 Nette 展示器和组件添加了一些有用的功能,例如通过 PHP8 属性实现展示器的授权、动作和信号,通过属性实现组件信号的授权,以及解析组件模板文件。
安装
安装 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 容器时,属性可以被缓存以避免在运行时使用反射。该扩展将自动创建类映射和所有属性的映射,只需知道在哪里查找展示器和组件即可。这是通过 scanDirs
、scanComposer
和 scanFilters
选项完成的,它们的行为类似于 nette/application。
现在,将以下特质添加到您的 BasePresenter
和 BaseControl
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.latte
或 COMPONENT_DIRECTORY/templates/MyControl.latte
。
渲染方法 foo
的模板将被解析为 COMPONENT_DIRECTORY/templates/foo.myControl.latte
或 COMPONENT_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