Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,17 @@ Rule::allClasses()
->should(new HaveNameMatching('*Controller'))
->because('it\'s a symfony naming convention');
```

Since selecting classes by namespace is very common, there's a convenient shortcut:

```php
Rule::namespace('App\Controller')
->should(new HaveNameMatching('*Controller'))
->because('it\'s a symfony naming convention');
```

You can also specify multiple namespaces: `Rule::namespace('App\Controller', 'App\Service')`.

# Installation

## Using Composer
Expand Down
8 changes: 8 additions & 0 deletions src/Rules/Rule.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,18 @@

namespace Arkitect\Rules;

use Arkitect\Expression\ForClasses\ResideInOneOfTheseNamespaces;
use Arkitect\Rules\DSL\AndThatShouldParser;

class Rule
{
public static function allClasses(): AllClasses
{
return new AllClasses();
}

public static function namespace(string ...$namespaces): AndThatShouldParser
{
return self::allClasses()->that(new ResideInOneOfTheseNamespaces(...$namespaces));
}
}
148 changes: 148 additions & 0 deletions tests/Integration/RuleNamespaceShortcutTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
<?php
declare(strict_types=1);

namespace Arkitect\Tests\Integration;

use Arkitect\Expression\ForClasses\HaveNameMatching;
use Arkitect\Expression\ForClasses\ResideInOneOfTheseNamespaces;
use Arkitect\Rules\Rule;
use Arkitect\Tests\Utils\TestRunner;
use org\bovigo\vfs\vfsStream;
use PHPUnit\Framework\TestCase;

class RuleNamespaceShortcutTest extends TestCase
{
public function test_namespace_shortcut_works_same_as_full_syntax(): void
{
$dir = vfsStream::setup('root', null, $this->createDummyProject())->url();

$runner = TestRunner::create('8.4');

$rule = Rule::namespace('App\HappyIsland')

Check failure on line 21 in tests/Integration/RuleNamespaceShortcutTest.php

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Define a constant instead of duplicating this literal "App\HappyIsland" 5 times.

See more on https://sonarcloud.io/project/issues?id=phparkitect_arkitect&issues=AZqy8TNTd5LXpyF1MoUz&open=AZqy8TNTd5LXpyF1MoUz&pullRequest=539
->should(new HaveNameMatching('Happy*'))

Check failure on line 22 in tests/Integration/RuleNamespaceShortcutTest.php

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Define a constant instead of duplicating this literal "Happy*" 3 times.

See more on https://sonarcloud.io/project/issues?id=phparkitect_arkitect&issues=AZqy8TNTd5LXpyF1MoUy&open=AZqy8TNTd5LXpyF1MoUy&pullRequest=539
->because("that's what she said");

$runner->run($dir, $rule);

self::assertCount(0, $runner->getViolations());
self::assertCount(0, $runner->getParsingErrors());
}

public function test_namespace_shortcut_detects_violations(): void
{
$dir = vfsStream::setup('root', null, $this->createDummyProject())->url();

$runner = TestRunner::create('8.4');

$rule = Rule::namespace('App\HappyIsland')
->should(new HaveNameMatching('Sad*'))
->because('we want sad names');

$runner->run($dir, $rule);

self::assertCount(1, $runner->getViolations());
}

public function test_namespace_shortcut_supports_multiple_namespaces(): void
{
$dir = vfsStream::setup('root', null, $this->createDummyProject())->url();

$runner = TestRunner::create('8.4');

$rule = Rule::namespace('App\HappyIsland', 'App\BadCode')
->should(new HaveNameMatching('*Code'))
->because('we want Code suffix');

$runner->run($dir, $rule);

// HappyClass doesn't match *Code pattern, so we should have 1 violation
self::assertCount(1, $runner->getViolations());
}

public function test_namespace_shortcut_is_equivalent_to_full_syntax(): void
{
$dir = vfsStream::setup('root', null, $this->createDummyProject())->url();

$runner = TestRunner::create('8.4');

// Using shortcut
$shortcutRule = Rule::namespace('App\HappyIsland')
->should(new HaveNameMatching('Happy*'))
->because('test');

$runner->run($dir, $shortcutRule);
$shortcutViolations = $runner->getViolations();

// Using full syntax
$fullRule = Rule::allClasses()
->that(new ResideInOneOfTheseNamespaces('App\HappyIsland'))
->should(new HaveNameMatching('Happy*'))
->because('test');

$runner->run($dir, $fullRule);
$fullViolations = $runner->getViolations();

self::assertCount(\count($shortcutViolations), $fullViolations);
}

public function createDummyProject(): array
{
return [
'BadCode' => [
'BadCode.php' => <<<'EOF'
<?php

namespace App\BadCode;

class BadCode
{
private $happy;

public function __construct(HappyClass $happy)
{
$this->happy = $happy;
}
}
EOF,
],
'OtherBadCode' => [
'OtherBadCode.php' => <<<'EOF'
<?php

namespace App\BadCode;

class OtherBadCode
{
private $happy;

public function __construct(HappyClass $happy)
{
$this->happy = $happy;
}
}
EOF,
],

'HappyIsland' => [
'HappyClass.php' => <<<'EOF'
<?php

namespace App\HappyIsland;

class HappyClass
{
/**
* @var BadCode
*/
private $bad;

public function __construct(BadCode $bad)
{
$this->bad = $bad;
}
}
EOF,
],
];
}
}