From d3478ec9484895a8d2833449cb0f6e91a1c6cc79 Mon Sep 17 00:00:00 2001
From: Sergei Predvoditelev
Date: Sat, 12 Feb 2022 20:21:55 +0300
Subject: [PATCH] First implementation (#1)
---
CHANGELOG.md | 2 +-
README.md | 25 ++++++------
composer.json | 33 ++++++++++++----
config/common.php | 18 +++++++++
config/params.php | 10 +++++
phpunit.xml.dist | 3 +-
psalm.xml | 2 +-
src/.gitkeep | 0
src/RulesContainer.php | 68 ++++++++++++++++++++++++++++++++
tests/.gitkeep | 0
tests/ConfigTest.php | 75 ++++++++++++++++++++++++++++++++++++
tests/RulesContainerTest.php | 64 ++++++++++++++++++++++++++++++
tests/Support/AuthorRule.php | 19 +++++++++
13 files changed, 296 insertions(+), 23 deletions(-)
create mode 100644 config/common.php
create mode 100644 config/params.php
delete mode 100644 src/.gitkeep
create mode 100644 src/RulesContainer.php
delete mode 100644 tests/.gitkeep
create mode 100644 tests/ConfigTest.php
create mode 100644 tests/RulesContainerTest.php
create mode 100644 tests/Support/AuthorRule.php
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6a8fbfe..4b37b68 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,4 @@
-# _____ Change Log
+# Yii RBAC Rules Container Change Log
## 1.0.0 under development
diff --git a/README.md b/README.md
index 000fff9..4e3d523 100644
--- a/README.md
+++ b/README.md
@@ -2,20 +2,21 @@
- Yii _____
+ Yii RBAC Rules Container
-[![Latest Stable Version](https://poser.pugx.org/yiisoft/_____/v/stable.png)](https://packagist.org/packages/yiisoft/_____)
-[![Total Downloads](https://poser.pugx.org/yiisoft/_____/downloads.png)](https://packagist.org/packages/yiisoft/_____)
-[![Build status](https://github.com/yiisoft/_____/workflows/build/badge.svg)](https://github.com/yiisoft/_____/actions?query=workflow%3Abuild)
-[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/yiisoft/_____/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/yiisoft/_____/?branch=master)
-[![Code Coverage](https://scrutinizer-ci.com/g/yiisoft/_____/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/yiisoft/_____/?branch=master)
-[![Mutation testing badge](https://img.shields.io/endpoint?style=flat&url=https%3A%2F%2Fbadge-api.stryker-mutator.io%2Fgithub.com%2Fyiisoft%2F_____%2Fmaster)](https://dashboard.stryker-mutator.io/reports/github.com/yiisoft/_____/master)
-[![static analysis](https://github.com/yiisoft/_____/workflows/static%20analysis/badge.svg)](https://github.com/yiisoft/_____/actions?query=workflow%3A%22static+analysis%22)
-[![type-coverage](https://shepherd.dev/github/yiisoft/_____/coverage.svg)](https://shepherd.dev/github/yiisoft/_____)
+[![Latest Stable Version](https://poser.pugx.org/yiisoft/rbac-rules-container/v/stable.png)](https://packagist.org/packages/yiisoft/rbac-rules-container)
+[![Total Downloads](https://poser.pugx.org/yiisoft/rbac-rules-container/downloads.png)](https://packagist.org/packages/yiisoft/rbac-rules-container)
+[![Build status](https://github.com/yiisoft/rbac-rules-container/workflows/build/badge.svg)](https://github.com/yiisoft/rbac-rules-container/actions?query=workflow%3Abuild)
+[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/yiisoft/rbac-rules-container/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/yiisoft/rbac-rules-container/?branch=master)
+[![Code Coverage](https://scrutinizer-ci.com/g/yiisoft/rbac-rules-container/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/yiisoft/rbac-rules-container/?branch=master)
+[![Mutation testing badge](https://img.shields.io/endpoint?style=flat&url=https%3A%2F%2Fbadge-api.stryker-mutator.io%2Fgithub.com%2Fyiisoft%2Frbac-rules-container%2Fmaster)](https://dashboard.stryker-mutator.io/reports/github.com/yiisoft/rbac-rules-container/master)
+[![static analysis](https://github.com/yiisoft/rbac-rules-container/workflows/static%20analysis/badge.svg)](https://github.com/yiisoft/rbac-rules-container/actions?query=workflow%3A%22static+analysis%22)
+[![type-coverage](https://shepherd.dev/github/yiisoft/rbac-rules-container/coverage.svg)](https://shepherd.dev/github/yiisoft/rbac-rules-container)
-The package ...
+The package provides rules container for [Yii RBAC (Role-Based Access Control)](https://github.com/yiisoft/rbac) package
+based on [Yii Factory](https://github.com/yiisoft/factory).
## Requirements
@@ -26,7 +27,7 @@ The package ...
The package could be installed with composer:
```shell
-composer require yiisoft/_____ --prefer-dist
+composer require yiisoft/rbac-rules-container --prefer-dist
```
## General usage
@@ -60,7 +61,7 @@ The code is statically analyzed with [Psalm](https://psalm.dev/). To run static
## License
-The Yii _____ is free software. It is released under the terms of the BSD License.
+The Yii RBAC Rules Container is free software. It is released under the terms of the BSD License.
Please see [`LICENSE`](./LICENSE.md) for more information.
Maintained by [Yii Software](https://www.yiiframework.com/).
diff --git a/composer.json b/composer.json
index 8ff9ff9..ffe82b3 100644
--- a/composer.json
+++ b/composer.json
@@ -1,19 +1,23 @@
{
"name": "yiisoft/rbac-rules-container",
"type": "library",
- "description": "_____",
+ "description": "RBAC rules container based on \"yiisoft/factory\"",
"keywords": [
- "_____"
+ "yii",
+ "rbac",
+ "rules",
+ "factory",
+ "container"
],
"homepage": "https://www.yiiframework.com/",
"license": "BSD-3-Clause",
"support": {
- "issues": "https://github.com/yiisoft/_____/issues?state=open",
+ "issues": "https://github.com/yiisoft/rbac-rules-container/issues?state=open",
"forum": "https://www.yiiframework.com/forum/",
"wiki": "https://www.yiiframework.com/wiki/",
"irc": "irc://irc.freenode.net/yii",
"chat": "https://t.me/yii3en",
- "source": "https://github.com/yiisoft/_____"
+ "source": "https://github.com/yiisoft/rbac-rules-container"
},
"funding": [
{
@@ -28,22 +32,26 @@
"minimum-stability": "dev",
"prefer-stable": true,
"require": {
- "php": "^7.4|^8.0"
+ "php": "^7.4|^8.0",
+ "yiisoft/factory": "^1.0",
+ "yiisoft/rbac": "^3.0@dev"
},
"require-dev": {
"phpunit/phpunit": "^9.5",
"roave/infection-static-analysis-plugin": "^1.16",
"spatie/phpunit-watcher": "^1.23",
- "vimeo/psalm": "^4.18"
+ "vimeo/psalm": "^4.18",
+ "yiisoft/di": "^1.0",
+ "yiisoft/test-support": "^1.3"
},
"autoload": {
"psr-4": {
- "Yiisoft\\_____\\": "src"
+ "Yiisoft\\Rbac\\Rules\\Container\\": "src"
}
},
"autoload-dev": {
"psr-4": {
- "Yiisoft\\_____\\Tests\\": "tests"
+ "Yiisoft\\Rbac\\Rules\\Container\\Tests\\": "tests"
}
},
"config": {
@@ -53,6 +61,15 @@
"composer/package-versions-deprecated": true
}
},
+ "extra": {
+ "config-plugin-options": {
+ "source-directory": "config"
+ },
+ "config-plugin": {
+ "params": "params.php",
+ "common": "common.php"
+ }
+ },
"scripts": {
"test": "phpunit --testdox --no-interaction",
"test-watch": "phpunit-watcher watch"
diff --git a/config/common.php b/config/common.php
new file mode 100644
index 0000000..cbf1025
--- /dev/null
+++ b/config/common.php
@@ -0,0 +1,18 @@
+ [
+ 'class' => RulesContainer::class,
+ '__construct()' => [
+ 'definitions' => $params['yiisoft/rbac-rules-container']['rules'],
+ 'validate' => $params['yiisoft/rbac-rules-container']['validate'],
+ ],
+ ],
+];
diff --git a/config/params.php b/config/params.php
new file mode 100644
index 0000000..2a06bd2
--- /dev/null
+++ b/config/params.php
@@ -0,0 +1,10 @@
+ [
+ 'rules' => [],
+ 'validate' => true,
+ ],
+];
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index 976580a..6113945 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -18,13 +18,14 @@
-
+
./tests
+ ./config
./src
diff --git a/psalm.xml b/psalm.xml
index b899031..3f815b4 100644
--- a/psalm.xml
+++ b/psalm.xml
@@ -1,6 +1,6 @@
+ */
+ private array $instances = [];
+
+ /**
+ * @psalm-param array $definitions
+ *
+ * @throws InvalidConfigException
+ */
+ public function __construct(ContainerInterface $container, array $definitions, bool $validate = true)
+ {
+ $this->factory = new Factory($container, $definitions, $validate);
+ }
+
+ /**
+ * @param string $name
+ *
+ * @return RuleInterface
+ * @throws RuleInterfaceNotImplementedException
+ * @throws RuleNotFoundException
+ * @throws CircularReferenceException
+ * @throws InvalidConfigException
+ * @throws NotInstantiableException
+ */
+ public function create(string $name): RuleInterface
+ {
+ if (!array_key_exists($name, $this->instances)) {
+ try {
+ $rule = $this->factory->create($name);
+ } catch (NotFoundException $e) {
+ throw new RuleNotFoundException($name, 0, $e);
+ }
+
+ if (!$rule instanceof RuleInterface) {
+ throw new RuleInterfaceNotImplementedException($name);
+ }
+
+ $this->instances[$name] = $rule;
+ }
+
+ return $this->instances[$name];
+ }
+}
diff --git a/tests/.gitkeep b/tests/.gitkeep
deleted file mode 100644
index e69de29..0000000
diff --git a/tests/ConfigTest.php b/tests/ConfigTest.php
new file mode 100644
index 0000000..b2e93d8
--- /dev/null
+++ b/tests/ConfigTest.php
@@ -0,0 +1,75 @@
+createContainer();
+
+ $rulesContainer = $container->get(RulesFactoryInterface::class);
+
+ $this->assertInstanceOf(RulesContainer::class, $rulesContainer);
+ }
+
+ public function testDisableValidation(): void
+ {
+ $params = $this->getParams();
+ $params['yiisoft/rbac-rules-container']['rules'] = ['rule' => 42];
+ $params['yiisoft/rbac-rules-container']['validate'] = false;
+ $container = $this->createContainer($params);
+
+ $rulesContainer = $container->get(RulesFactoryInterface::class);
+
+ $this->expectException(InvalidConfigException::class);
+ $rulesContainer->create('rule');
+ }
+
+ public function testRules(): void
+ {
+ $params = $this->getParams();
+ $params['yiisoft/rbac-rules-container']['rules'] = ['rule' => AuthorRule::class];
+ $container = $this->createContainer($params);
+
+ $rulesContainer = $container->get(RulesFactoryInterface::class);
+ $rule = $rulesContainer->create('rule');
+
+ $this->assertInstanceOf(AuthorRule::class, $rule);
+ }
+
+ private function createContainer(?array $params = null): Container
+ {
+ return new Container(
+ ContainerConfig::create()->withDefinitions(
+ $this->getCommonDefinitions($params)
+ )
+ );
+ }
+
+ private function getCommonDefinitions(?array $params = null): array
+ {
+ if ($params === null) {
+ $params = $this->getParams();
+ }
+ return require dirname(__DIR__) . '/config/common.php';
+ }
+
+ private function getParams(): array
+ {
+ return require dirname(__DIR__) . '/config/params.php';
+ }
+}
diff --git a/tests/RulesContainerTest.php b/tests/RulesContainerTest.php
new file mode 100644
index 0000000..e1bcc47
--- /dev/null
+++ b/tests/RulesContainerTest.php
@@ -0,0 +1,64 @@
+create(AuthorRule::class);
+
+ $this->assertInstanceOf(AuthorRule::class, $rule);
+ }
+
+ public function testNotFound(): void
+ {
+ $rulesContainer = new RulesContainer(new SimpleContainer(), []);
+
+ $this->expectException(RuleNotFoundException::class);
+ $this->expectExceptionMessage('Rule "not-exists-rule" not found.');
+ $this->expectExceptionCode(0);
+ $rulesContainer->create('not-exists-rule');
+ }
+
+ public function testNotRuleInterface(): void
+ {
+ $rulesContainer = new RulesContainer(new SimpleContainer(), ['rule' => new stdClass()]);
+
+ $this->expectException(RuleInterfaceNotImplementedException::class);
+ $this->expectExceptionMessage('Rule "rule" should implement "' . RuleInterface::class . '".');
+ $this->expectExceptionCode(0);
+ $rulesContainer->create('rule');
+ }
+
+ public function testValidation(): void
+ {
+ $container = new SimpleContainer();
+ $definitions = ['rule' => 42];
+
+ $this->expectException(InvalidConfigException::class);
+ new RulesContainer($container, $definitions);
+ }
+
+ public function testDisableValidation(): void
+ {
+ $rulesContainer = new RulesContainer(new SimpleContainer(), ['rule' => 42], false);
+
+ $this->expectException(InvalidConfigException::class);
+ $rulesContainer->create('rule');
+ }
+}
diff --git a/tests/Support/AuthorRule.php b/tests/Support/AuthorRule.php
new file mode 100644
index 0000000..5bf4705
--- /dev/null
+++ b/tests/Support/AuthorRule.php
@@ -0,0 +1,19 @@
+