I am building a class for a laravel system. It is for casting the Ramsey\Uuid\Uuid
type in laravel models. I also use phpstan
and I seem to be having problems with the generics/templating.
Ramsey\Uuid\UuidInterface
is enforcedThe laravel vendor package has the following interface:
/**
* @template TGet
* @template TSet
*/
interface CastsAttributes
{
/**
* Transform the attribute from the underlying model values.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @param string $key
* @param mixed $value
* @param array $attributes
* @return TGet|null
*/
public function get($model, string $key, $value, array $attributes);
/**
* Transform the attribute to its underlying model values.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @param string $key
* @param TSet|null $value
* @param array $attributes
* @return mixed
*/
public function set($model, string $key, $value, array $attributes);
}
My class Uuid
implements this
// ...
use Ramsey\Uuid\Uuid as RamseyUuid;
use Ramsey\Uuid\UuidInterface;
// ...
class Uuid implements CastsAttributes // ...
{
/**
* Cast the given value.
*
* @param Model $model
* @param string $key
* @param string $value
* @param array<mixed> $attributes
* @return UuidInterface
*/
public function get($model, string $key, $value, array $attributes)
{
$uuid = RamseyUuid::fromBytes($value);
return $uuid;
}
/**
* Prepare the given value for storage.
*
* @param Model $model
* @param string $key
* @param UuidInterface $value
* @param array<mixed> $attributes
* @return string
* @throws Exception
*/
public function set($model, string $key, $value, array $attributes)
{
if (!$value instanceof (UuidInterface::class)) {
throw new Exception('The uuid property is not an instance of Ramsey - UuidInterface');
}
return $value->getBytes();
}
When I run phpstan (above level 6), I get the following error:
Class Uuid implements generic interface Illuminate\Contracts\Database\Eloquent\CastsAttributes but does not specify its types: TGet, TSet
I have read the phpstan documentation (generics section, generics by example) several times and I'm simply not sure how it relates to the issue I'm facing. I've also used the playground and it also didn't help me understand the issue.
How do you specify the types of an interface in phpstan
Following a response from the author of phpstan (thanks!) the part I was missing was using the @implements
tag.
/**
* @implements CastsAttributes<Uuid, UuidInterface>
*/
class Uuid implements CastsAttributes
This solves the issue up to phpstan max level.