Skip to content

Commit

Permalink
Merge pull request #2 from atournayre/feature/new_architecture
Browse files Browse the repository at this point in the history
New architecture
  • Loading branch information
atournayre authored Dec 6, 2023
2 parents c6b103a + 48f52d0 commit f4b33d6
Show file tree
Hide file tree
Showing 88 changed files with 2,151 additions and 1,046 deletions.
29 changes: 23 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,32 @@ Here is an example of how to use it:
// phparkitect.php
use Arkitect\ClassSet;
use Arkitect\CLI\Config;
use Arkitect\Expression\ForClasses\IsFinal;
use Arkitect\Expression\ForClasses\ResideInOneOfTheseNamespaces;
use Arkitect\Rules\Rule;
use Atournayre\PHPArkitect\Builder\RuleBuilder;
use Atournayre\PHPArkitect\Rules\ListenerMustBeLoggableLog;
use Atournayre\PHPArkitect\Set\Sets;

return static function (Config $config): void {
$classSet = ClassSet::fromDir(__DIR__ . '/src');

$rules = \Atournayre\PHPArkitect\Sets::symfonyApiPlatform();
$rules[] = \Atournayre\PHPArkitect\Rule::uniformNamingForService();

$config
->add($classSet, ...$rules);

$rules = RulesBuilder::create
->add(new ListenerMustBeLoggableLog)
// Add rules for Symfony Command
->set(Sets::symfonyCommand())
// Add rules for Doctrine Naming
->set(Sets::doctrineUniformNaming())
// Add regular rules
->add(
Rule::allClasses()
->that(new ResideInOneOfTheseNamespaces('App'))
->should(new IsFinal())
->because('All classes in App namespace must be final')
)
->rules();

$config->add($classSet, ...$rules);
};
```
You can use sets or rules individually.
Expand Down
69 changes: 69 additions & 0 deletions src/Builder/RuleBuilder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?php
declare(strict_types=1);

namespace Atournayre\PHPArkitect\Builder;

use Arkitect\Rules\DSL\ArchRule;
use Arkitect\Rules\Rule;
use Atournayre\PHPArkitect\Contracts\AndThatInterface;
use Atournayre\PHPArkitect\Contracts\ExceptInterface;
use Atournayre\PHPArkitect\Contracts\RulesInterface;
use Webmozart\Assert\Assert;

final class RuleBuilder
{
private array $rules = [];

private function __construct()
{
}

public static function create(): self
{
return new self();
}

public function add(RulesInterface|ArchRule $rule): self
{
$this->rules[] = $rule instanceof ArchRule ? $rule : $this->buildArchRule($rule);
return $this;
}

public function set(array $rules): self
{
Assert::allIsInstanceOf($rules, RulesInterface::class);

foreach ($rules as $rule) {
$this->add($rule);
}
return $this;
}

public function rules(): array
{
return $this->rules;
}

private function buildArchRule(RulesInterface|ExceptInterface|AndThatInterface $rule): ArchRule
{
Assert::isInstanceOf($rule, RulesInterface::class);

$allClasses = Rule::allClasses();

if ($rule instanceof ExceptInterface) {
$allClasses = $allClasses->except(...$rule->except());
}

$allClasses = $allClasses->that($rule->that());

if ($rule instanceof AndThatInterface) {
foreach ($rule->andThat() as $andThatItem) {
$allClasses = $allClasses->andThat($andThatItem);
}
}

return $allClasses
->should($rule->should())
->because($rule->because());
}
}
14 changes: 14 additions & 0 deletions src/Contracts/AndThatInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php
declare(strict_types=1);

namespace Atournayre\PHPArkitect\Contracts;

use Arkitect\Expression\Expression;

interface AndThatInterface
{
/**
* @return array|Expression[]
*/
public function andThat(): array;
}
9 changes: 9 additions & 0 deletions src/Contracts/ExceptInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php
declare(strict_types=1);

namespace Atournayre\PHPArkitect\Contracts;

interface ExceptInterface
{
public function except(): array;
}
15 changes: 15 additions & 0 deletions src/Contracts/RulesInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php
declare(strict_types=1);

namespace Atournayre\PHPArkitect\Contracts;

use Arkitect\Expression\Expression;

interface RulesInterface
{
public function that(): Expression;

public function should(): Expression;

public function because(): string;
}
53 changes: 53 additions & 0 deletions src/Expression/ForClasses/DependsOnTheseNamespace.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php
declare(strict_types=1);

namespace Atournayre\PHPArkitect\Expression\ForClasses;

use Arkitect\Analyzer\ClassDescription;
use Arkitect\Exceptions\FailOnFirstViolationException;
use Arkitect\Expression\Description;
use Arkitect\Expression\Expression;
use Arkitect\Rules\Violation;
use Arkitect\Rules\ViolationMessage;
use Arkitect\Rules\Violations;

class DependsOnTheseNamespace implements Expression
{
private string $namespace;

public function __construct(string $namespace)
{
$this->namespace = $namespace;
}

public function describe(ClassDescription $theClass, string $because): Description
{
return new Description("should depend on class in these namespace: $this->namespace", $because);
}

/**
* @throws FailOnFirstViolationException
*/
public function evaluate(ClassDescription $theClass, Violations $violations, string $because): void
{
$dependencies = $theClass->getDependencies();

$filteredDependencies = array_filter($dependencies, function ($dependency) {
return $dependency->matches($this->namespace);
});

if (count($filteredDependencies) > 0) {
return;
}

$violation = Violation::create(
$theClass->getFQCN(),
ViolationMessage::withDescription(
$this->describe($theClass, $because),
"depends on {$this->namespace}"
)
);

$violations->add($violation);
}
}
56 changes: 0 additions & 56 deletions src/Expression/ForClasses/DependsOnTheseNamespaces.php

This file was deleted.

Loading

0 comments on commit f4b33d6

Please sign in to comment.