entityClass = $entityClass; $this->reflectedClass = ObjectReflection::fromClass($entityClass, $cache)->reflectClass(); } public function field($name, $fieldKey = self::KEY_ENTITY_NAME, $throwException = true) : null|ReflectedProperty { try{ return $this->fieldList($fieldKey)[$name] ?? null; } catch(\Throwable $e) { if ( $throwException) { throw new \InvalidArgumentException("Can't find entity field's column named `$name` from entity {$this->entityClass}"); } } return null; } public function searchField($name) : null|ReflectedProperty { return $this->field($name, self::KEY_ENTITY_NAME, false) ?: $this->field($name, self::KEY_COLUMN_NAME, false); } public function fieldList($fieldKey = self::KEY_ENTITY_NAME, bool $skipVirtual = false) : array { $fieldList = []; foreach($this->reflectedClass->getProperties(true) as $item) { foreach($item->getAttributes() as $tag) { if ( $tag->object instanceof Field ) { if ( $skipVirtual && $tag->object instanceof Virtual ) { break; } switch($fieldKey) { case static::KEY_LC_ENTITY_NAME: $key = strtolower($item->name); break; case static::KEY_ENTITY_NAME: $key = $item->name; break; case static::KEY_COLUMN_NAME: $key = strtolower($tag->object->name ?? $item->name); break; default: throw new \InvalidArgumentException("Given `fieldKey` is unknown to the EntityResolver"); } $fieldList[$key] = $item; break; } } } return $fieldList; } public function relation(string $name) : array { $property = $this->reflectedClass->getProperties(true)[$name] ?? false; try{ if ( $property ) { foreach($property->getAttributes() as $tag) { if ( $tag->object instanceof Relation ) { return $property; } } } return []; } catch(\Throwable $e) { throw new \InvalidArgumentException("Can't find entity relation's column named `$name` from entity {$this->entityClass}"); } } public function getPropertyHavingAttribute(array|object|string $type) : array { return array_filter(array_map( fn($e) => $e->getAttributes(is_object($type) ? $type::class : $type), $this->reflectedClass->getProperties(true) )); } public function getPropertyEntityType(string $name) : false|string { return $this->reflectedClass->getProperties(true)[$name]->getTypes()[0]->type ?? false; } public function searchFieldAnnotation(string $field, array|object|string $annotationType, bool $caseSensitive = true) : ? object { return $this->searchFieldAnnotationList($field, $annotationType, $caseSensitive)[0] ?? null; } public function searchFieldAnnotationList(string $field, array|object|string $attributeType, bool $caseSensitive = true) : false|array { $list = []; $properties = $this->reflectedClass->getProperties(true); $search = $caseSensitive ? $properties : array_change_key_case($properties, \CASE_LOWER); if ( null !== ( $search[$field] ?? null ) ) { return array_map(fn(ReflectedAttribute $e) => $e->object, $search[$field]->getAttributes((array) $attributeType)); } return false; } public function tableName($required = false) : string { $table = $this->tableAnnotation($required); if ( ( $table->name ?? "" ) === "") { if ($required) { throw new \ArgumentCountError("Your entity {$this->entityClass} seems to be missing a `name` argument for your @Table() annotation"); } } return $table->name ?? ""; } public function tableAnnotation($required = false) : null|Table { if ( null === $table = $this->getTableAttribute() ) { if ($required) { throw new \LogicException("Your entity {$this->entityClass} seems to be missing a @Table() annotation"); } } return $table; } public function databaseName() : null|string { return $this->tableAnnotation(false)->database ?? $this->databaseAdapter()->adapter()->databaseName() ?? null; } public function sqlAdapter() : \Ulmus\ConnectionAdapter { if ( $adapterObj = $this->getAdapterInterfaceAttribute()) { if ( false !== $adapterName = $adapterObj->adapter() ) { if ( null === ( $adapter = \Ulmus\Ulmus::$registeredAdapters[$adapterName] ?? null ) ) { throw new \Exception("Requested database adapter `$adapterName` is not registered."); } else { return $adapter; } } } return Ulmus::$defaultAdapter; } /** * Alias of sqlAdapter */ public function databaseAdapter() : \Ulmus\ConnectionAdapter { return $this->sqlAdapter(); } public function schemaName(bool $required = false) : null|string { if ( null === $table = $this->getTableAttribute() ) { throw new \LogicException("Your entity {$this->entityClass} seems to be missing a @Table() annotation"); } if ( $required && ( ( $table->schema ?? "" ) === "" ) ) { throw new \ArgumentCountError("Your entity {$this->entityClass} seems to be missing a `schema` argument for your @Table() annotation"); } return $table->schema ?? null; } public function getPrimaryKeyField() : null|array { foreach($this->fieldList() as $key => $value) { $field = $this->searchFieldAnnotation($key, [ Field::class ]); if ( null !== $field ) { if ( false !== ( $field->attributes['primary_key'] ?? false ) ) { return [ $key => $field ]; } } } return null; } public function getCompoundKeyFields() : ? Index { return $this->getAttributeImplementing(Index::class); } public function getUniqueFields() : ? array { return null; } protected function getAdapterInterfaceAttribute() : null|object { return $this->getAttributeImplementing(AdapterAttributeInterface::class); } protected function getTableAttribute() { return $this->getAttributeImplementing(Table::class); } public function getAttributeImplementing(string $interface) : null|object { foreach ($this->reflectedClass->getAttributes(true) as $item) { if ($item->object instanceof $interface) { return $item->object; } } return null; } }