Passed
Push — trunk ( 04b0a9...ad65a5 )
by Christian
24:30 queued 13:01
created

DomainExceptionRule   A

Complexity

Total Complexity 18

Size/Duplication

Total Lines 99
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 47
dl 0
loc 99
rs 10
c 1
b 0
f 0
wmc 18

4 Methods

Rating   Name   Duplication   Size   Complexity  
B processNode() 0 27 7
B validateDomainExceptionClass() 0 40 9
A getNodeType() 0 3 1
A __construct() 0 3 1
1
<?php declare(strict_types=1);
2
3
namespace Shopware\Core\DevOps\StaticAnalyze\PHPStan\Rules;
4
5
use PhpParser\Node;
6
use PhpParser\Node\Stmt\Throw_;
7
use PHPStan\Analyser\Scope;
0 ignored issues
show
Bug introduced by
The type PHPStan\Analyser\Scope was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
8
use PHPStan\Reflection\ReflectionProvider;
0 ignored issues
show
Bug introduced by
The type PHPStan\Reflection\ReflectionProvider was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
9
use PHPStan\Rules\Rule;
0 ignored issues
show
Bug introduced by
The type PHPStan\Rules\Rule was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
10
use PHPStan\Rules\RuleError;
0 ignored issues
show
Bug introduced by
The type PHPStan\Rules\RuleError was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
11
use PHPStan\Rules\RuleErrorBuilder;
0 ignored issues
show
Bug introduced by
The type PHPStan\Rules\RuleErrorBuilder was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
12
use Shopware\Core\Framework\HttpException;
13
use Shopware\Core\Framework\Log\Package;
14
use Shopware\Core\Framework\Plugin\Exception\DecorationPatternException;
15
use Shopware\Core\Framework\Validation\Exception\ConstraintViolationException;
16
17
/**
18
 * @internal
19
 *
20
 * @implements Rule<Throw_>
21
 */
22
#[Package('core')]
23
class DomainExceptionRule implements Rule
24
{
25
    use InTestClassTrait;
26
27
    private const VALID_EXCEPTION_CLASSES = [
28
        DecorationPatternException::class,
29
        ConstraintViolationException::class,
30
    ];
31
32
    private const VALID_SUB_DOMAINS = [
33
        'Cart',
34
        'Payment',
35
        'Order',
36
    ];
37
38
    public function __construct(
39
        private ReflectionProvider $reflectionProvider
40
    ) {
41
    }
42
43
    public function getNodeType(): string
44
    {
45
        return Throw_::class;
46
    }
47
48
    public function processNode(Node $node, Scope $scope): array
49
    {
50
        if ($this->isInTestClass($scope) || !$scope->isInClass()) {
51
            return [];
52
        }
53
54
        if (!$node instanceof Throw_) {
55
            return [];
56
        }
57
58
        if ($node->expr instanceof Node\Expr\StaticCall) {
59
            return $this->validateDomainExceptionClass($node->expr, $scope);
60
        }
61
62
        if (!$node->expr instanceof Node\Expr\New_) {
63
            return [];
64
        }
65
66
        \assert($node->expr->class instanceof Node\Name);
67
        $exceptionClass = $node->expr->class->toString();
68
69
        if (\in_array($exceptionClass, self::VALID_EXCEPTION_CLASSES, true)) {
70
            return [];
71
        }
72
73
        return [
74
            RuleErrorBuilder::message('Throwing new exceptions within classes are not allowed. Please use domain exception pattern. See https://github.com/shopware/platform/blob/v6.4.20.0/adr/2022-02-24-domain-exceptions.md')->build(),
75
        ];
76
    }
77
78
    /**
79
     * @return list<RuleError>
0 ignored issues
show
Bug introduced by
The type Shopware\Core\DevOps\Sta...lyze\PHPStan\Rules\list was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
80
     */
81
    private function validateDomainExceptionClass(Node\Expr\StaticCall $node, Scope $scope): array
82
    {
83
        \assert($node->class instanceof Node\Name);
84
        $exceptionClass = $node->class->toString();
85
86
        if (!\str_starts_with($exceptionClass, 'Shopware\\Core\\')) {
87
            return [];
0 ignored issues
show
Bug Best Practice introduced by
The expression return array() returns the type array which is incompatible with the documented return type Shopware\Core\DevOps\Sta...lyze\PHPStan\Rules\list.
Loading history...
88
        }
89
90
        $exception = $this->reflectionProvider->getClass($exceptionClass);
91
        if (!$exception->isSubclassOf(HttpException::class)) {
92
            return [
0 ignored issues
show
Bug Best Practice introduced by
The expression return array(PHPStan\Rul...eptionClass))->build()) returns the type array which is incompatible with the documented return type Shopware\Core\DevOps\Sta...lyze\PHPStan\Rules\list.
Loading history...
93
                RuleErrorBuilder::message(\sprintf('Domain exception class %s has to extend the \Shopware\Core\Framework\HttpException class', $exceptionClass))->build(),
94
            ];
95
        }
96
97
        $reflection = $scope->getClassReflection();
98
        \assert($reflection !== null);
99
        if (!\str_starts_with($reflection->getName(), 'Shopware\\Core\\')) {
100
            return [];
0 ignored issues
show
Bug Best Practice introduced by
The expression return array() returns the type array which is incompatible with the documented return type Shopware\Core\DevOps\Sta...lyze\PHPStan\Rules\list.
Loading history...
101
        }
102
        $parts = \explode('\\', $reflection->getName());
103
104
        $expected = \sprintf('Shopware\\Core\\%s\\%s\\%sException', $parts[2], $parts[3], $parts[3]);
105
106
        if ($exceptionClass !== $expected && !$exception->isSubclassOf($expected)) {
107
            // Is it in a subdomain?
108
            if (isset($parts[5]) && \in_array($parts[4], self::VALID_SUB_DOMAINS, true)) {
109
                $expectedSub = \sprintf('\\%s\\%sException', $parts[4], $parts[4]);
110
                if (\str_starts_with(strrev($exceptionClass), strrev($expectedSub))) {
111
                    return [];
0 ignored issues
show
Bug Best Practice introduced by
The expression return array() returns the type array which is incompatible with the documented return type Shopware\Core\DevOps\Sta...lyze\PHPStan\Rules\list.
Loading history...
112
                }
113
            }
114
115
            return [
0 ignored issues
show
Bug Best Practice introduced by
The expression return array(PHPStan\Rul...eptionClass))->build()) returns the type array which is incompatible with the documented return type Shopware\Core\DevOps\Sta...lyze\PHPStan\Rules\list.
Loading history...
116
                RuleErrorBuilder::message(\sprintf('Expected domain exception class %s, got %s', $expected, $exceptionClass))->build(),
117
            ];
118
        }
119
120
        return [];
0 ignored issues
show
Bug Best Practice introduced by
The expression return array() returns the type array which is incompatible with the documented return type Shopware\Core\DevOps\Sta...lyze\PHPStan\Rules\list.
Loading history...
121
    }
122
}
123