Lines
97.36%
74 / 76
Methods
50.00%
2 / 4
Classes
0.00%
0 / 1
| Name | Lines | Methods | CRAP | ||||
|---|---|---|---|---|---|---|---|
| __construct | 0.00% | 0 / 1 | 0.00% | 0 / 1 | 2 | ||
| supportsDomain | 100.00% | 1 / 1 | 100.00% | 1 / 1 | 1 | ||
| emitFile | 98.63% | 72 / 73 | 0.00% | 0 / 1 | 5 | ||
| listReservedMemberNames | 100.00% | 1 / 1 | 100.00% | 1 / 1 | 2 | ||
| 31 | final readonly class EntityHandleEmitter implements DomainFileEmitter, ReservesMemberNames | |
| 32 | { | |
| 33 | private const array RESERVED_MEMBER_NAMES = ['id', 'getDomain', 'isGeneratedEntityId', 'getState', 'requireState', 'watchStateChanges', 'getHistory', 'waitForState', 'listAttributes', 'getEntity', 'toServiceTarget', 'ha']; | |
| 34 | ||
| 35 | private const string ENTITY_IDS_CONSTANT = 'GENERATED_ENTITY_IDS'; | |
| 36 | ||
| 37 | public function __construct(private ServiceMethodEmitter $services) {} | |
| 38 | ||
| 39 | public function supportsDomain(DomainModel $domain): bool | |
| 40 | { | |
| 41 | return $domain->hasEntities(); | |
| 42 | } | |
| 43 | ||
| 44 | public function emitFile(DomainModel $domain, EmitContext $context): GeneratedFile | |
| 45 | { | |
| 46 | $namespace = $context->createNamespace(); | |
| 47 | $declared = $domain->getHandleClass(); | |
| 48 | $stateException = $context->importClass($namespace, StateException::class, $declared); | |
| 49 | $identifierException = $context->importClass($namespace, IdentifierException::class, $declared); | |
| 50 | $historyException = $context->importClass($namespace, HistoryException::class, $declared); | |
| 51 | $waitException = $context->importClass($namespace, WaitException::class, $declared); | |
| 52 | ||
| 53 | foreach ([Entity::class, EntityId::class, HaContext::class, EntityStateHistory::class, HistoryQuery::class, StateChangeStream::class, ServiceTarget::class, TypedEntity::class, Duration::class] as $import) { | |
| 54 | $context->importClass($namespace, $import, $declared); | |
| 55 | } | |
| 56 | ||
| 57 | if (array_any($domain->handleServices, static fn(ServiceModel $service): bool => $service->definition->returnsResponse)) { | |
| 58 | $context->importClass($namespace, ServiceResponse::class, $declared); | |
| 59 | } | |
| 60 | ||
| 61 | if (array_any($domain->handleServices, static fn(ServiceModel $service): bool => !$service->definition->returnsResponse)) { | |
| 62 | $context->importClass($namespace, EventContext::class, $declared); | |
| 63 | } | |
| 64 | ||
| 65 | $class = $namespace->addClass($declared) | |
| 66 | ->setFinal() | |
| 67 | ->setReadOnly() | |
| 68 | ->addImplement(TypedEntity::class) | |
| 69 | ->addComment(\sprintf('One `%s` entity.', $domain->domain)); | |
| 70 | ||
| 71 | $class->addConstant(self::ENTITY_IDS_CONSTANT, array_fill_keys($domain->entityIds->toStrings(), true)) | |
| 72 | ->setType('array') | |
| 73 | ->setPrivate(); | |
| 74 | ||
| 75 | $class->addProperty('entity')->setType(Entity::class)->setPrivate(); | |
| 76 | ||
| 77 | $constructor = $class->addMethod('__construct')->addComment('@throws ' . $identifierException); | |
| 78 | $constructor->addParameter('ha')->setType(HaContext::class); | |
| 79 | $constructor->addPromotedParameter('id')->setType(EntityId::class)->setPublic(); | |
| 80 | $constructor->setBody(\sprintf( | |
| 81 | "if (!self::isGeneratedEntityId(\$id)) {\n throw %s::entityNotGenerated(\$id->value, self::getDomain());\n}\n\n\$this->entity = \$ha->getEntity(\$id);", | |
| 82 | $identifierException, | |
| 83 | )); | |
| 84 | ||
| 85 | $class->addMethod('getDomain') | |
| 86 | ->setStatic() | |
| 87 | ->setReturnType('string') | |
| 88 | ->setBody('return ?;', [$domain->domain]); | |
| 89 | ||
| 90 | $class->addMethod('isGeneratedEntityId') | |
| 91 | ->setStatic() | |
| 92 | ->setReturnType('bool') | |
| 93 | ->setBody(\sprintf('return isset(self::%s[$id->value]);', self::ENTITY_IDS_CONSTANT)) | |
| 94 | ->addParameter('id') | |
| 95 | ->setType(EntityId::class); | |
| 96 | ||
| 97 | $class->addMethod('getState') | |
| 98 | ->setReturnType('?' . $context->resolveClassName($domain->getStateClass())) | |
| 99 | ->setBody(\sprintf('return %s::fromNullableState($this->entity->getState());', $domain->getStateClass())); | |
| 100 | ||
| 101 | $class->addMethod('requireState') | |
| 102 | ->setReturnType($context->resolveClassName($domain->getStateClass())) | |
| 103 | ->addComment('@throws ' . $stateException) | |
| 104 | ->setBody(\sprintf('return new %s($this->entity->requireState());', $domain->getStateClass())); | |
| 105 | ||
| 106 | $class->addMethod('watchStateChanges') | |
| 107 | ->setReturnType(StateChangeStream::class) | |
| 108 | ->setBody('return $this->entity->watchStateChanges();'); | |
| 109 | ||
| 110 | $class->addMethod('getHistory') | |
| 111 | ->setReturnType(EntityStateHistory::class) | |
| 112 | ->addComment('@throws ' . $historyException) | |
| 113 | ->setBody('return $this->entity->getHistory($query);') | |
| 114 | ->addParameter('query') | |
| 115 | ->setType(HistoryQuery::class); | |
| 116 | ||
| 117 | $waitForState = $class->addMethod('waitForState') | |
| 118 | ->setReturnType('?' . $context->resolveClassName($domain->getStateClass())) | |
| 119 | ->addComment('@throws ' . $waitException) | |
| 120 | ->setBody(\sprintf('return %s::fromNullableState($this->entity->waitForState($state, $timeout));', $domain->getStateClass())); | |
| 121 | $waitForState->addParameter('state')->setType('string'); | |
| 122 | $waitForState->addParameter('timeout', null)->setType(Duration::class)->setNullable(); | |
| 123 | ||
| 124 | $class->addMethod('listAttributes') | |
| 125 | ->setReturnType('array') | |
| 126 | ->addComment('@return array<string, mixed>') | |
| 127 | ->setBody("\$state = \$this->entity->getState();\n\nreturn \$state === null ? [] : \$state->attributes;"); | |
| 128 | ||
| 129 | $class->addMethod('getEntity') | |
| 130 | ->setReturnType(Entity::class) | |
| 131 | ->setBody('return $this->entity;'); | |
| 132 | ||
| 133 | $class->addMethod('toServiceTarget') | |
| 134 | ->setReturnType(ServiceTarget::class) | |
| 135 | ->setBody('return $this->entity->toServiceTarget();'); | |
| 136 | ||
| 137 | foreach ($domain->handleServices as $service) { | |
| 138 | $this->services->addHandleMethod($class, $service); | |
| 139 | } | |
| 140 | ||
| 141 | return $context->printFile($namespace, $declared); | |
| 142 | } | |
| 143 | ||
| 144 | public function listReservedMemberNames(MemberScope $scope): array | |
| 145 | { | |
| 146 | return $scope === MemberScope::EntityHandle ? self::RESERVED_MEMBER_NAMES : []; | |
| 147 | } | |
| 148 | } |