I'm trying to write a custom phpstan rule to not allow other devs to call Cart::save() ($cart->save()) from everywhere in the codebase, but to call only from CartRepository, and if it's called outside of repository I want to see an error like Calling Cart::save() method outside of CartRepository class is not allowed.
I tried to do something like this
class CartSaveRule implements Rule
{
public function getNodeType(): string
{
return MethodCall::class;
}
/**
* @param MethodCall $node
* @param Scope $scope
* @return array
*/
public function processNode(Node $node, Scope $scope): array
{
// Check if the method call is to the "save" method
if ($node->name->toString() === 'save') {
$className = $scope->getClassReflection()->getName();
// Check if the method call is made from the Product class
if ($className === 'Cart') {
// Get the method call location
$line = $node->getLine();
$file = $scope->getFile();
// Check if the method call is not made from inside the ProductRepository class
if (!$this->isCalledFromProductRepository($scope)) {
return [
RuleErrorBuilder::message('Calling save() method of Cart class outside of CartRepository class is not allowed.')
->line($line)
->file($file)
->build()
];
}
}
}
return [];
}
private function isCalledFromRepository(Scope $scope): bool
{
// Check if the calling class is CartRepository or its subclass
return $scope->getClassReflection()->isSubclassOf('CartRepository');
}
}
but it's not working as I expect, let's say in Cart I have a method :
private function updateVariant()
{
$variant = Variant::
->where('id', '=', $this->variantId)
->first();
// logic to update variant
$variant->save();
}
and my rule will scream on line $variant->save(); because save is called by Cart, but it's not Cart related save
Why not just override the
save()method of the cart instead? Something like this:This will output:
You can try it here https://3v4l.org/uHW1e