Lines 100.00% 37 / 37
Methods 100.00% 3 / 3
Classes 100.00% 1 / 1
Name Lines Methods CRAP
 supportsDomain 100.00% 1 / 1 100.00% 1 / 1 1
 emitFile 100.00% 35 / 35 100.00% 1 / 1 5
 listReservedMemberNames 100.00% 1 / 1 100.00% 1 / 1 2
15final readonly class EntityStateEmitter implements DomainFileEmitter, ReservesMemberNames
16{
17    private const array RESERVED_MEMBER_NAMES = ['raw', 'value', 'fromNullableState', 'isOn', 'isOff', 'getStateAsFloat', 'isUnavailable', 'getFriendlyName'];
18
19    public function supportsDomain(DomainModel $domain): bool
20    {
21        return $domain->hasEntities();
22    }
23
24    public function emitFile(DomainModel $domain, EmitContext $context): GeneratedFile
25    {
26        $namespace = $context->createNamespace();
27        $context->importClass($namespace, EntityState::class, $domain->getStateClass());
28
29        $class = $namespace->addClass($domain->getStateClass())
30            ->setFinal()
31            ->setReadOnly()
32            ->addComment(\sprintf('What a `%s` entity is doing.', $domain->domain));
33
34        $class->addProperty('value')->setType('string');
35
36        $constructor = $class->addMethod('__construct');
37        $constructor->addPromotedParameter('raw')->setType(EntityState::class)->setPublic();
38        $constructor->setBody('$this->value = $raw->state;');
39
40        $class->addMethod('fromNullableState')
41            ->setStatic()
42            ->setReturnType('?self')
43            ->setBody('return $raw === null ? null : new self($raw);')
44            ->addParameter('raw')
45            ->setType('?' . EntityState::class);
46
47        if ($domain->isOnOff()) {
48            $class->addMethod('isOn')->setReturnType('bool')->setBody("return \$this->value === 'on';");
49            $class->addMethod('isOff')->setReturnType('bool')->setBody("return \$this->value === 'off';");
50        }
51
52        if ($domain->isNumeric()) {
53            $class->addMethod('getStateAsFloat')->setReturnType('?float')->setBody('return $this->raw->getStateAsFloat();');
54        }
55
56        $class->addMethod('isUnavailable')->setReturnType('bool')->setBody('return $this->raw->isUnavailable();');
57        $class->addMethod('getFriendlyName')->setReturnType('string')->setBody('return $this->raw->getFriendlyName();');
58
59        foreach ($domain->attributes as $attribute) {
60            $type = $attribute->kind->getPhpType();
61            $method = $class->addMethod($attribute->accessor)
62                ->setReturnType($type->native)
63                ->setBody(\sprintf(
64                    'return $this->raw->%s(%s);',
65                    $attribute->kind->getReaderMethodName(),
66                    var_export($attribute->name, true),
67                ));
68
69            if ($type->needsDocblock()) {
70                $method->addComment('@return ' . $type->docblock);
71            }
72        }
73
74        return $context->printFile($namespace, $domain->getStateClass());
75    }
76
77    public function listReservedMemberNames(MemberScope $scope): array
78    {
79        return $scope === MemberScope::StateView ? self::RESERVED_MEMBER_NAMES : [];
80    }
81}