Last active
September 17, 2017 18:32
-
-
Save matej21/7f4c8ac42732ba09a5dc1994cf7467b4 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php declare(strict_types = 1); | |
namespace AppTests\PhpStan\NextrasOrm; | |
use Nextras\Orm\Entity\Entity; | |
use PhpParser\Node; | |
use PhpParser\Node\Expr\MethodCall; | |
use PHPStan\Analyser\Scope; | |
use PHPStan\Broker\Broker; | |
use PHPStan\Rules\Rule; | |
class NextrasOrmSetValueRule implements Rule | |
{ | |
/** @var Broker */ | |
private $broker; | |
public function __construct(Broker $broker) | |
{ | |
$this->broker = $broker; | |
} | |
public function getNodeType(): string | |
{ | |
return MethodCall::class; | |
} | |
/** | |
* @param \PhpParser\Node\Expr\MethodCall $node | |
*/ | |
public function processNode(Node $node, Scope $scope): array | |
{ | |
if (!is_string($node->name) || !in_array($node->name, ['setValue', 'setReadOnlyValue'], TRUE)) { | |
return []; | |
} | |
$args = $node->args; | |
if (!isset($args[0], $args[1])) { | |
return []; | |
} | |
$valueType = $scope->getType($args[1]->value); | |
$varType = $scope->getType($node->var); | |
if ($varType->getClass() === NULL) { | |
return []; | |
} | |
$firstValue = $args[0]->value; | |
if (!$firstValue instanceof Node\Scalar\String_) { | |
return []; | |
} | |
$fieldName = $firstValue->value; | |
$class = $this->broker->getClass($varType->getClass()); | |
if (!in_array(Entity::class, $class->getParentClassesNames(), TRUE)) { | |
return []; | |
} | |
if (!$class->hasProperty($fieldName)) { | |
return [sprintf('Entity %s has no field named %s', $varType->getClass(), $fieldName)]; | |
} | |
$property = $class->getProperty($fieldName); | |
$propertyType = $property->getType(); | |
if (!$propertyType->accepts($valueType)) { | |
return [sprintf('Entity %s: field $%s (%s) does not accept %s', $varType->getClass(), $fieldName, $propertyType->describe(), $valueType->describe())]; | |
} | |
if ($node->name === 'setReadOnlyValue' && (!$scope->isInClass() || !$scope->hasVariableType('this') || !$varType->accepts($scope->getVariableType('this')))) { | |
return [sprintf('You cannot set readonly field $%s on entity %s', $fieldName, $varType->getClass())]; | |
} | |
return []; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment