|null $shape Inline GeoJSON shape; null when $indexedShape is used. */ public function __construct( private string $field, private array|null $shape = null, private string $relation = 'intersects', private bool|null $ignoreUnmapped = null, private \Spameri\ElasticQuery\Query\IndexedShape|null $indexedShape = null, private float $boost = 1.0, ) { if ( ! \in_array($relation, ['intersects', 'disjoint', 'within', 'contains'], true)) { throw new \Spameri\ElasticQuery\Exception\InvalidArgumentException( 'GeoShape relation must be one of: intersects, disjoint, within, contains.', ); } if ($shape === null && $indexedShape === null) { throw new \Spameri\ElasticQuery\Exception\InvalidArgumentException( 'GeoShape requires either an inline shape or an indexedShape.', ); } } public function key(): string { return 'geo_shape_' . $this->field; } /** * @return array> */ public function toArray(): array { $inner = [ 'relation' => $this->relation, ]; if ($this->shape !== null) { $inner['shape'] = $this->shape; } if ($this->indexedShape !== null) { $inner['indexed_shape'] = $this->indexedShape->toArray(); } $body = [ $this->field => $inner, 'boost' => $this->boost, ]; if ($this->ignoreUnmapped !== null) { $body['ignore_unmapped'] = $this->ignoreUnmapped; } return [ 'geo_shape' => $body, ]; } }