@@ -94,6 +94,16 @@ class Builder
94
94
*/
95
95
protected array $ with = [];
96
96
97
+ /**
98
+ * The result type for the query.
99
+ */
100
+ protected ?string $ resultType = null ;
101
+
102
+ /**
103
+ * The document class for custom document DTOs.
104
+ */
105
+ protected ?string $ documentClass = null ;
106
+
97
107
/**
98
108
* Create a new Elasticsearch query builder instance.
99
109
*/
@@ -117,6 +127,25 @@ public function setModel(string $model): self
117
127
return $ this ;
118
128
}
119
129
130
+ /**
131
+ * Set the result type to document.
132
+ */
133
+ public function asDocument (): self
134
+ {
135
+ $ this ->resultType = 'document ' ;
136
+ return $ this ;
137
+ }
138
+
139
+ /**
140
+ * Set the result type to use a custom document DTO class.
141
+ */
142
+ public function asData (string $ documentClass ): self
143
+ {
144
+ $ this ->resultType = 'document ' ;
145
+ $ this ->documentClass = $ documentClass ;
146
+ return $ this ;
147
+ }
148
+
120
149
/**
121
150
* Add a basic where clause to the query.
122
151
*/
@@ -555,42 +584,14 @@ public function first()
555
584
*/
556
585
public function get (): Collection
557
586
{
558
- $ params = $ this ->buildParams ();
559
- $ result = [];
560
-
561
- // Use ES|QL endpoint if esqlQuery is set
562
- if ($ this ->esqlQuery !== null ) {
563
- $ result = $ this ->elasticManager ->esql (
564
- $ params ['esql ' ],
565
- [
566
- 'from ' => $ this ->from ,
567
- 'size ' => $ this ->size ,
568
- ]
569
- );
570
- } else {
571
- $ result = $ this ->elasticManager ->search (
572
- $ this ->model ::getIndexName (),
573
- $ params ,
574
- [
575
- 'from ' => $ this ->from ,
576
- 'size ' => $ this ->size ,
577
- 'sort ' => $ this ->sort ,
578
- ]
579
- );
580
- }
581
-
582
- $ collection = new Collection ();
583
-
584
- foreach ($ result ['hits ' ] as $ hit ) {
585
- $ data = $ hit ['_source ' ] ?? [];
586
- $ data ['_id ' ] = $ hit ['_id ' ];
587
- $ data ['_score ' ] = $ hit ['_score ' ] ?? null ;
587
+ $ params = $ this ->buildQuery ();
588
+ $ response = $ this ->elasticManager ->getClient ()->search ($ params );
588
589
589
- $ model = $ this ->model :: newFromElasticData ( $ data );
590
- $ collection -> push ( $ model );
590
+ if ( $ this ->resultType === ' document ' ) {
591
+ return new Collection ( $ response [ ' hits ' ][ ' hits ' ] );
591
592
}
592
593
593
- return $ collection ;
594
+ return $ this -> hydrate ( $ response -> asArray ()) ;
594
595
}
595
596
596
597
/**
@@ -1717,4 +1718,55 @@ public function whereDoesntHave(string $relation): self
1717
1718
1718
1719
return $ this ;
1719
1720
}
1721
+
1722
+ /**
1723
+ * Build the Elasticsearch query parameters.
1724
+ */
1725
+ protected function buildQuery (): array
1726
+ {
1727
+ $ params = [
1728
+ 'index ' => $ this ->model ::getIndexName (),
1729
+ 'body ' => [
1730
+ 'query ' => $ this ->query ,
1731
+ ],
1732
+ ];
1733
+
1734
+ if ($ this ->from !== null ) {
1735
+ $ params ['from ' ] = $ this ->from ;
1736
+ }
1737
+
1738
+ if ($ this ->size !== null ) {
1739
+ $ params ['size ' ] = $ this ->size ;
1740
+ }
1741
+
1742
+ if (!empty ($ this ->sort )) {
1743
+ $ params ['sort ' ] = $ this ->sort ;
1744
+ }
1745
+
1746
+ return $ params ;
1747
+ }
1748
+
1749
+ /**
1750
+ * Hydrate the search results into model instances.
1751
+ */
1752
+ protected function hydrate (array $ response ): Collection
1753
+ {
1754
+ $ collection = new Collection ();
1755
+
1756
+ foreach ($ response ['hits ' ]['hits ' ] as $ hit ) {
1757
+ $ data = $ hit ['_source ' ] ?? [];
1758
+ $ data ['_id ' ] = $ hit ['_id ' ];
1759
+ $ data ['_score ' ] = $ hit ['_score ' ] ?? null ;
1760
+
1761
+ if ($ this ->documentClass ) {
1762
+ $ model = new $ this ->documentClass ($ data );
1763
+ } else {
1764
+ $ model = $ this ->model ::newFromElasticData ($ data );
1765
+ }
1766
+
1767
+ $ collection ->push ($ model );
1768
+ }
1769
+
1770
+ return $ collection ;
1771
+ }
1720
1772
}
0 commit comments