Skip to content

Commit

Permalink
First implementation (#1)
Browse files Browse the repository at this point in the history
  • Loading branch information
vjik committed Feb 12, 2022
1 parent ad5f908 commit d3478ec
Show file tree
Hide file tree
Showing 13 changed files with 296 additions and 23 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
@@ -1,4 +1,4 @@
# _____ Change Log
# Yii RBAC Rules Container Change Log

## 1.0.0 under development

Expand Down
25 changes: 13 additions & 12 deletions README.md
Expand Up @@ -2,20 +2,21 @@
<a href="https://github.com/yiisoft" target="_blank">
<img src="https://yiisoft.github.io/docs/images/yii_logo.svg" height="100px">
</a>
<h1 align="center">Yii _____</h1>
<h1 align="center">Yii RBAC Rules Container</h1>
<br>
</p>

[![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

Expand All @@ -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
Expand Down Expand Up @@ -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/).
Expand Down
33 changes: 25 additions & 8 deletions 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": [
{
Expand All @@ -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": {
Expand All @@ -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"
Expand Down
18 changes: 18 additions & 0 deletions config/common.php
@@ -0,0 +1,18 @@
<?php

declare(strict_types=1);

use Yiisoft\Rbac\Rules\Container\RulesContainer;
use Yiisoft\Rbac\RuleFactoryInterface;

/* @var array $params */

return [
RuleFactoryInterface::class => [
'class' => RulesContainer::class,
'__construct()' => [
'definitions' => $params['yiisoft/rbac-rules-container']['rules'],
'validate' => $params['yiisoft/rbac-rules-container']['validate'],
],
],
];
10 changes: 10 additions & 0 deletions config/params.php
@@ -0,0 +1,10 @@
<?php

declare(strict_types=1);

return [
'yiisoft/rbac-rules-container' => [
'rules' => [],
'validate' => true,
],
];
3 changes: 2 additions & 1 deletion phpunit.xml.dist
Expand Up @@ -18,13 +18,14 @@
</php>

<testsuites>
<testsuite name="Yii _____ tests">
<testsuite name="Yii RBAC Rules Container tests">
<directory>./tests</directory>
</testsuite>
</testsuites>

<coverage>
<include>
<directory>./config</directory>
<directory>./src</directory>
</include>
</coverage>
Expand Down
2 changes: 1 addition & 1 deletion psalm.xml
@@ -1,6 +1,6 @@
<?xml version="1.0"?>
<psalm
errorLevel="2"
errorLevel="1"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://getpsalm.org/schema/config"
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
Expand Down
Empty file removed src/.gitkeep
Empty file.
68 changes: 68 additions & 0 deletions src/RulesContainer.php
@@ -0,0 +1,68 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Rbac\Rules\Container;

use Psr\Container\ContainerInterface;
use Yiisoft\Definitions\Exception\CircularReferenceException;
use Yiisoft\Definitions\Exception\InvalidConfigException;
use Yiisoft\Definitions\Exception\NotInstantiableException;
use Yiisoft\Factory\Factory;
use Yiisoft\Factory\NotFoundException;
use Yiisoft\Rbac\Exception\RuleInterfaceNotImplementedException;
use Yiisoft\Rbac\Exception\RuleNotFoundException;
use Yiisoft\Rbac\RuleInterface;
use Yiisoft\Rbac\RuleFactoryInterface;

use function array_key_exists;

final class RulesContainer implements RuleFactoryInterface
{
private Factory $factory;

/**
* @var RuleInterface[]
* @psalm-var array<string,RuleInterface>
*/
private array $instances = [];

/**
* @psalm-param array<string, mixed> $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];
}
}
Empty file removed tests/.gitkeep
Empty file.
75 changes: 75 additions & 0 deletions tests/ConfigTest.php
@@ -0,0 +1,75 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Rbac\Rules\Container\Tests;

use PHPUnit\Framework\TestCase;

use Yiisoft\Definitions\Exception\InvalidConfigException;
use Yiisoft\Di\Container;
use Yiisoft\Di\ContainerConfig;
use Yiisoft\Rbac\Rules\Container\RulesContainer;
use Yiisoft\Rbac\Rules\Container\Tests\Support\AuthorRule;
use Yiisoft\Rbac\RulesFactoryInterface;

use function dirname;

final class ConfigTest extends TestCase
{
public function testBase(): void
{
$container = $this->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';
}
}
64 changes: 64 additions & 0 deletions tests/RulesContainerTest.php
@@ -0,0 +1,64 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Rbac\Rules\Container\Tests;

use PHPUnit\Framework\TestCase;
use stdClass;
use Yiisoft\Definitions\Exception\InvalidConfigException;
use Yiisoft\Rbac\Exception\RuleInterfaceNotImplementedException;
use Yiisoft\Rbac\Exception\RuleNotFoundException;
use Yiisoft\Rbac\RuleInterface;
use Yiisoft\Rbac\Rules\Container\RulesContainer;
use Yiisoft\Rbac\Rules\Container\Tests\Support\AuthorRule;
use Yiisoft\Test\Support\Container\SimpleContainer;

final class RulesContainerTest extends TestCase
{
public function testCreate(): void
{
$rulesContainer = new RulesContainer(new SimpleContainer(), []);

$rule = $rulesContainer->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');
}
}

0 comments on commit d3478ec

Please sign in to comment.