@@ -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,9 +864,8 @@ 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+ $ ok = $ this ->buildSubQuery ($ values );
871869 } else {
872870 $ whereIn = array_values ($ values );
873871 $ ok = $ this ->setBind ($ ok , $ whereIn , $ escape );
@@ -876,7 +874,7 @@ protected function _whereIn(?string $key = null, $values = null, bool $not = fal
876874 $ prefix = empty ($ this ->{$ clause }) ? $ this ->groupGetType ('' ) : $ this ->groupGetType ($ type );
877875
878876 $ whereIn = [
879- 'condition ' => $ prefix . $ key . $ not . ($ values instanceof Closure ? " IN ( {$ ok }) " : " IN : {$ ok }: " ),
877+ 'condition ' => $ prefix . $ key . $ not . ($ this -> isSubQuery ( $ values) ? " IN ( {$ ok }) " : " IN : {$ ok }: " ),
880878 'escape ' => false ,
881879 ];
882880
@@ -2724,9 +2722,35 @@ protected function setBind(string $key, $value = null, bool $escape = true): str
27242722 * Returns a clone of a Base Builder with reset query builder values.
27252723 *
27262724 * @return $this
2725+ *
2726+ * @deprecated
27272727 */
27282728 protected function cleanClone ()
27292729 {
27302730 return (clone $ this )->from ([], true )->resetQuery ();
27312731 }
2732+
2733+ /**
2734+ * @param mixed $value
2735+ */
2736+ protected function isSubQuery ($ value ): bool
2737+ {
2738+ return $ value instanceof BaseBuilder || $ value instanceof Closure;
2739+ }
2740+
2741+ /**
2742+ * @param BaseBuilder|Closure $builder
2743+ * @param bool $wrapped Wrap the subquery in brackets
2744+ */
2745+ protected function buildSubQuery ($ builder , bool $ wrapped = false ): string
2746+ {
2747+ if ($ builder instanceof Closure) {
2748+ $ instance = (clone $ this )->from ([], true )->resetQuery ();
2749+ $ builder = $ builder ($ instance );
2750+ }
2751+
2752+ $ subQuery = strtr ($ builder ->getCompiledSelect (), "\n" , ' ' );
2753+
2754+ return $ wrapped ? '( ' . $ subQuery . ') ' : $ subQuery ;
2755+ }
27322756}
0 commit comments