@@ -693,9 +693,8 @@ protected function whereHaving(string $qbKey, $key, $value = null, string $type
693693 $ op = ' = ' ;
694694 }
695695
696- if ($ v instanceof Closure) {
697- $ builder = $ this ->cleanClone ();
698- $ v = ' ( ' . strtr ($ v ($ builder )->getCompiledSelect (), "\n" , ' ' ) . ') ' ;
696+ if ($ this ->isSubquery ($ v )) {
697+ $ v = $ this ->buildSubquery ($ v , true );
699698 } else {
700699 $ bind = $ this ->setBind ($ k , $ v , $ escape );
701700 $ v = " : {$ bind }: " ;
@@ -723,7 +722,7 @@ protected function whereHaving(string $qbKey, $key, $value = null, string $type
723722 * Generates a WHERE field IN('item', 'item') SQL query,
724723 * joined with 'AND' if appropriate.
725724 *
726- * @param array|Closure|string $values The values searched on, or anonymous function with subquery
725+ * @param array|BaseBuilder| Closure|string $values The values searched on, or anonymous function with subquery
727726 *
728727 * @return $this
729728 */
@@ -736,7 +735,7 @@ public function whereIn(?string $key = null, $values = null, ?bool $escape = nul
736735 * Generates a WHERE field IN('item', 'item') SQL query,
737736 * joined with 'OR' if appropriate.
738737 *
739- * @param array|Closure|string $values The values searched on, or anonymous function with subquery
738+ * @param array|BaseBuilder| Closure|string $values The values searched on, or anonymous function with subquery
740739 *
741740 * @return $this
742741 */
@@ -749,7 +748,7 @@ public function orWhereIn(?string $key = null, $values = null, ?bool $escape = n
749748 * Generates a WHERE field NOT IN('item', 'item') SQL query,
750749 * joined with 'AND' if appropriate.
751750 *
752- * @param array|Closure|string $values The values searched on, or anonymous function with subquery
751+ * @param array|BaseBuilder| Closure|string $values The values searched on, or anonymous function with subquery
753752 *
754753 * @return $this
755754 */
@@ -762,7 +761,7 @@ public function whereNotIn(?string $key = null, $values = null, ?bool $escape =
762761 * Generates a WHERE field NOT IN('item', 'item') SQL query,
763762 * joined with 'OR' if appropriate.
764763 *
765- * @param array|Closure|string $values The values searched on, or anonymous function with subquery
764+ * @param array|BaseBuilder| Closure|string $values The values searched on, or anonymous function with subquery
766765 *
767766 * @return $this
768767 */
@@ -775,7 +774,7 @@ public function orWhereNotIn(?string $key = null, $values = null, ?bool $escape
775774 * Generates a HAVING field IN('item', 'item') SQL query,
776775 * joined with 'AND' if appropriate.
777776 *
778- * @param array|Closure|string $values The values searched on, or anonymous function with subquery
777+ * @param array|BaseBuilder| Closure|string $values The values searched on, or anonymous function with subquery
779778 *
780779 * @return $this
781780 */
@@ -788,7 +787,7 @@ public function havingIn(?string $key = null, $values = null, ?bool $escape = nu
788787 * Generates a HAVING field IN('item', 'item') SQL query,
789788 * joined with 'OR' if appropriate.
790789 *
791- * @param array|Closure|string $values The values searched on, or anonymous function with subquery
790+ * @param array|BaseBuilder| Closure|string $values The values searched on, or anonymous function with subquery
792791 *
793792 * @return $this
794793 */
@@ -801,7 +800,7 @@ public function orHavingIn(?string $key = null, $values = null, ?bool $escape =
801800 * Generates a HAVING field NOT IN('item', 'item') SQL query,
802801 * joined with 'AND' if appropriate.
803802 *
804- * @param array|Closure|string $values The values searched on, or anonymous function with subquery
803+ * @param array|BaseBuilder| Closure|string $values The values searched on, or anonymous function with subquery
805804 *
806805 * @return $this
807806 */
@@ -814,7 +813,7 @@ public function havingNotIn(?string $key = null, $values = null, ?bool $escape =
814813 * Generates a HAVING field NOT IN('item', 'item') SQL query,
815814 * joined with 'OR' if appropriate.
816815 *
817- * @param array|Closure|string $values The values searched on, or anonymous function with subquery
816+ * @param array|BaseBuilder| Closure|string $values The values searched on, or anonymous function with subquery
818817 *
819818 * @return $this
820819 */
@@ -829,7 +828,7 @@ public function orHavingNotIn(?string $key = null, $values = null, ?bool $escape
829828 * @used-by whereNotIn()
830829 * @used-by orWhereNotIn()
831830 *
832- * @param array|Closure|null $values The values searched on, or anonymous function with subquery
831+ * @param array|BaseBuilder| Closure|null $values The values searched on, or anonymous function with subquery
833832 *
834833 * @throws InvalidArgumentException
835834 *
@@ -845,7 +844,7 @@ protected function _whereIn(?string $key = null, $values = null, bool $not = fal
845844 return $ this ; // @codeCoverageIgnore
846845 }
847846
848- if ($ values === null || (! is_array ($ values ) && ! ($ values instanceof Closure ))) {
847+ if ($ values === null || (! is_array ($ values ) && ! $ this -> isSubquery ($ values ))) {
849848 if (CI_DEBUG ) {
850849 throw new InvalidArgumentException (sprintf ('%s() expects $values to be of type array or closure ' , debug_backtrace (0 , 2 )[1 ]['function ' ]));
851850 }
@@ -865,18 +864,19 @@ protected function _whereIn(?string $key = null, $values = null, bool $not = fal
865864
866865 $ not = ($ not ) ? ' NOT ' : '' ;
867866
868- if ($ values instanceof Closure ) {
869- $ builder = $ this ->cleanClone ( );
870- $ ok = strtr ( $ values ( $ builder )-> getCompiledSelect (), "\n" , ' ' ) ;
867+ if ($ this -> isSubquery ( $ values) ) {
868+ $ whereIn = $ this ->buildSubquery ( $ values , true );
869+ $ escape = false ;
871870 } else {
872871 $ whereIn = array_values ($ values );
873- $ ok = $ this ->setBind ($ ok , $ whereIn , $ escape );
874872 }
875873
874+ $ ok = $ this ->setBind ($ ok , $ whereIn , $ escape );
875+
876876 $ prefix = empty ($ this ->{$ clause }) ? $ this ->groupGetType ('' ) : $ this ->groupGetType ($ type );
877877
878878 $ whereIn = [
879- 'condition ' => $ prefix . $ key . $ not . ( $ values instanceof Closure ? " IN ( { $ ok } ) " : " IN : {$ ok }: ") ,
879+ 'condition ' => "{ $ prefix}{ $ key}{ $ not } IN : {$ ok }: " ,
880880 'escape ' => false ,
881881 ];
882882
@@ -2724,9 +2724,35 @@ protected function setBind(string $key, $value = null, bool $escape = true): str
27242724 * Returns a clone of a Base Builder with reset query builder values.
27252725 *
27262726 * @return $this
2727+ *
2728+ * @deprecated
27272729 */
27282730 protected function cleanClone ()
27292731 {
27302732 return (clone $ this )->from ([], true )->resetQuery ();
27312733 }
2734+
2735+ /**
2736+ * @param mixed $value
2737+ */
2738+ protected function isSubquery ($ value ): bool
2739+ {
2740+ return $ value instanceof BaseBuilder || $ value instanceof Closure;
2741+ }
2742+
2743+ /**
2744+ * @param BaseBuilder|Closure $builder
2745+ * @param bool $wrapped Wrap the subquery in brackets
2746+ */
2747+ protected function buildSubquery ($ builder , bool $ wrapped = false ): string
2748+ {
2749+ if ($ builder instanceof Closure) {
2750+ $ instance = (clone $ this )->from ([], true )->resetQuery ();
2751+ $ builder = $ builder ($ instance );
2752+ }
2753+
2754+ $ subquery = strtr ($ builder ->getCompiledSelect (), "\n" , ' ' );
2755+
2756+ return $ wrapped ? '( ' . $ subquery . ') ' : $ subquery ;
2757+ }
27322758}
0 commit comments