Skip to content

Commit

Permalink
feat: install netlogix/coding-guidelines-php
Browse files Browse the repository at this point in the history
  • Loading branch information
Scarbous authored Nov 23, 2023
1 parent cdac9fc commit 35f2c0a
Show file tree
Hide file tree
Showing 11 changed files with 126 additions and 75 deletions.
5 changes: 4 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,17 @@
},
"require-dev": {
"phpunit/phpunit": "*",
"infection/infection": "*"
"infection/infection": "*",
"netlogix/coding-guidelines-php": "^1.0"
},
"config": {
"allow-plugins": {
"infection/extension-installer": true
}
},
"scripts": {
"lint": "ecs check",
"lint-fix": "ecs check --fix",
"test": "phpunit",
"infection": "infection",
"test-coverage": "XDEBUG_MODE=coverage phpunit --coverage-html=coverage"
Expand Down
17 changes: 17 additions & 0 deletions ecs.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

declare(strict_types=1);

use Netlogix\CodingGuidelines\Php\DefaultPhp;
use Symplify\EasyCodingStandard\Config\ECSConfig;

return static function (ECSConfig $ecsConfig): void {
(new DefaultPhp())->configure($ecsConfig);

$ecsConfig->paths(
[
__DIR__ . '/src',
__DIR__ . '/tests',
]
);
};
8 changes: 4 additions & 4 deletions src/ResettableTaskPoolInterface.php
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<?php

declare(strict_types=1);

namespace Netlogix\DependencyResolver;

interface ResettableTaskPoolInterface extends TaskPoolInterface {

function reset(): self;

interface ResettableTaskPoolInterface extends TaskPoolInterface
{
public function reset(): self;
}
18 changes: 10 additions & 8 deletions src/Task.php
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
<?php

declare(strict_types=1);

namespace Netlogix\DependencyResolver;

use JetBrains\PhpStorm\NoReturn;
use InvalidArgumentException;

class Task implements TaskInterface
{
Expand All @@ -15,13 +16,12 @@ class Task implements TaskInterface
/**
* @param array<string> $dependencies
*/
function __construct(
public function __construct(
private readonly string $name,
private readonly array $dependencies = []
)
{
if (array_filter($dependencies, fn($i) => !is_string($i))) {
throw new \InvalidArgumentException('Dependencies must be strings');
private readonly array $dependencies = []
) {
if (array_filter($dependencies, fn ($i) => !is_string($i))) {
throw new InvalidArgumentException('Dependencies must be strings');
}
}

Expand All @@ -40,12 +40,13 @@ public function getDependencies(): array
*/
public function checkDependencies(array $resolvedTasks): bool
{
return [] == array_diff($this->getDependencies(), $resolvedTasks);
return [] === array_diff($this->getDependencies(), $resolvedTasks);
}

public function resolve(): self
{
$this->resolved = true;

return $this;
}

Expand All @@ -57,6 +58,7 @@ public function isResolved(): bool
public function reset(): self
{
$this->resolved = false;

return $this;
}
}
27 changes: 15 additions & 12 deletions src/TaskGraph.php
Original file line number Diff line number Diff line change
@@ -1,23 +1,25 @@
<?php

declare(strict_types=1);

namespace Netlogix\DependencyResolver;

use Traversable;
use Exception;
use Generator;
use InvalidArgumentException;
use IteratorAggregate;

class TaskGraph implements \IteratorAggregate
class TaskGraph implements IteratorAggregate
{
function __construct(
public function __construct(
private readonly TaskPoolInterface $tasks
)
{
) {
}

/**
* @return \Generator<\Generator<Task>>
* @throws \Exception
* @return Generator<Generator<Task>>
*/
public function getIterator(): \Generator
public function getIterator(): Generator
{
$tasksToResolve = [];

Expand All @@ -41,17 +43,18 @@ public function getIterator(): \Generator
!$this->hasResolvableTasks($tasksToResolve, $resolvedTasks) &&
!empty($tasksToResolve)
) {
throw new \Exception("Dependency cycle detected. Cannot resolve dependencies.");
throw new Exception("Dependency cycle detected. Cannot resolve dependencies.");
}
}
}

private function hasResolvableTasks(iterable $tasksToResolve, array $resolvedTasks): bool
{
return $this->getResolvableTasks($tasksToResolve, $resolvedTasks)->valid();
return $this->getResolvableTasks($tasksToResolve, $resolvedTasks)
->valid();
}

private function getResolvableTasks(iterable $tasksToResolve, array $resolvedTasks): \Generator
private function getResolvableTasks(iterable $tasksToResolve, array $resolvedTasks): Generator
{
foreach ($tasksToResolve as $taskName) {
$task = $this->tasks->getTask($taskName);
Expand All @@ -64,7 +67,7 @@ private function getResolvableTasks(iterable $tasksToResolve, array $resolvedTas
public function resetPool(): self
{
if (!($this->tasks instanceof ResettableTaskPoolInterface)) {
throw new \InvalidArgumentException('TaskPool is not resettable');
throw new InvalidArgumentException('TaskPool is not resettable');
}

$this->tasks->reset();
Expand Down
14 changes: 7 additions & 7 deletions src/TaskInterface.php
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
<?php

declare(strict_types=1);

namespace Netlogix\DependencyResolver;

interface TaskInterface
{
function getName(): string;
public function getName(): string;

/**
* @return string[] Names of tasks that need to be resolved before this task can be resolved
*/
function getDependencies(): array;
public function getDependencies(): array;

/**
* @param string[] $resolvedTasks Names of tasks that are already resolved
* @return bool
*/
function checkDependencies(array $resolvedTasks): bool;
public function checkDependencies(array $resolvedTasks): bool;

function resolve(): self;
public function resolve(): self;

function reset(): self;
public function reset(): self;

function isResolved(): bool;
public function isResolved(): bool;
}
28 changes: 17 additions & 11 deletions src/TaskPool.php
Original file line number Diff line number Diff line change
@@ -1,47 +1,53 @@
<?php

declare(strict_types=1);

namespace Netlogix\DependencyResolver;

use ArrayIterator;
use InvalidArgumentException;
use Traversable;

class TaskPool implements ResettableTaskPoolInterface
{
private array $tasks = [];
function __construct(
iterable $tasks = []
)

public function __construct(iterable $tasks = [])
{
foreach ($tasks as $task) {
$this->addTask($task);
}
}

function addTask(TaskInterface $task): self
public function addTask(TaskInterface $task): self
{
if (isset($this->tasks[$task->getName()])) {
throw new \InvalidArgumentException('Task already exists');
throw new InvalidArgumentException('Task already exists');
}

$this->tasks[$task->getName()] = $task;

return $this;
}

function getTask(string $name): TaskInterface
public function getTask(string $name): TaskInterface
{
if (!isset($this->tasks[$name])) {
throw new \InvalidArgumentException(sprintf('Task "%s" does not exist', $name));
throw new InvalidArgumentException(sprintf('Task "%s" does not exist', $name));
}

return $this->tasks[$name];
}

function getIterator(): \Traversable
public function getIterator(): Traversable
{
return new \ArrayIterator($this->tasks);
return new ArrayIterator($this->tasks);
}

function reset(): self
public function reset(): self
{
array_map(fn($t) => $t->reset(), $this->tasks);
array_map(fn ($t) => $t->reset(), $this->tasks);

return $this;
}
}
12 changes: 8 additions & 4 deletions src/TaskPoolInterface.php
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
<?php

declare(strict_types=1);

namespace Netlogix\DependencyResolver;

interface TaskPoolInterface extends \IteratorAggregate {
use IteratorAggregate;
use Traversable;

interface TaskPoolInterface extends IteratorAggregate
{
/**
* @return \Traversable<TaskInterface>
* @return Traversable<TaskInterface>
*/
function getIterator(): \Traversable;
public function getIterator(): Traversable;

function getTask(string $name): TaskInterface;
public function getTask(string $name): TaskInterface;
}
25 changes: 15 additions & 10 deletions tests/Unit/TaskGraphTest.php
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
<?php

declare(strict_types=1);

namespace Netlogix\DependencyResolver\Tests\Unit;

use ArrayIterator;
use Exception;
use InvalidArgumentException;
use Netlogix\DependencyResolver\ResettableTaskPoolInterface;
use Netlogix\DependencyResolver\Task;
use Netlogix\DependencyResolver\TaskGraph;
Expand All @@ -14,7 +18,8 @@ class TaskGraphTest extends TestCase
public function testReset(): void
{
$taskPool = self::createMock(ResettableTaskPoolInterface::class);
$taskPool->expects($this->once())->method('reset');
$taskPool->expects($this->once())
->method('reset');

$graph = new TaskGraph($taskPool);
$graph->resetPool();
Expand All @@ -23,7 +28,7 @@ public function testReset(): void
public function testResetException(): void
{
$taskPool = self::createMock(TaskPoolInterface::class);
self::expectException(\InvalidArgumentException::class);
self::expectException(InvalidArgumentException::class);
$graph = new TaskGraph($taskPool);
$graph->resetPool();
}
Expand All @@ -33,13 +38,15 @@ public function testResolveDependencies(): void
$tasks = [
'TaskA' => new Task('TaskA'),
'TaskB' => new Task('TaskB', ['TaskC']),
'TaskC' => new Task('TaskC', ['TaskA'])
'TaskC' => new Task('TaskC', ['TaskA']),
];

$taskPool = self::createMock(TaskPoolInterface::class);

$taskPool->method('getIterator')->willReturn(new \ArrayIterator($tasks));
$taskPool->method('getTask')->willReturnCallback(fn($name) => $tasks[$name]);
$taskPool->method('getIterator')
->willReturn(new ArrayIterator($tasks));
$taskPool->method('getTask')
->willReturnCallback(fn ($name) => $tasks[$name]);

$graph = new TaskGraph($taskPool);

Expand All @@ -56,14 +63,12 @@ public function testResolveDependencies(): void

public function testResolveCycle(): void
{
$this->expectException(\Exception::class);
$this->expectException(Exception::class);

$taskPool = self::createMock(TaskPoolInterface::class);

$taskPool->method('getIterator')->willReturn(new \ArrayIterator([
new Task('TaskB', ['TaskA']),
new Task('TaskA', ['TaskB'])
]));
$taskPool->method('getIterator')
->willReturn(new ArrayIterator([new Task('TaskB', ['TaskA']), new Task('TaskA', ['TaskB'])]));

foreach ((new TaskGraph($taskPool))->getIterator() as $tasks) {
foreach ($tasks as $task) {
Expand Down
Loading

0 comments on commit 35f2c0a

Please sign in to comment.