@@ -829,6 +829,82 @@ public function orWhereNotIn(string $key = null, $values = null, bool $escape =
829829
830830 //--------------------------------------------------------------------
831831
832+ /**
833+ * HAVING IN
834+ *
835+ * Generates a HAVING field IN('item', 'item') SQL query,
836+ * joined with 'AND' if appropriate.
837+ *
838+ * @param string $key The field to search
839+ * @param array|string|Closure $values The values searched on, or anonymous function with subquery
840+ * @param boolean $escape
841+ *
842+ * @return BaseBuilder
843+ */
844+ public function havingIn (string $ key = null , $ values = null , bool $ escape = null )
845+ {
846+ return $ this ->_whereIn ($ key , $ values , false , 'AND ' , $ escape , 'QBHaving ' );
847+ }
848+
849+ //--------------------------------------------------------------------
850+
851+ /**
852+ * OR HAVING IN
853+ *
854+ * Generates a HAVING field IN('item', 'item') SQL query,
855+ * joined with 'OR' if appropriate.
856+ *
857+ * @param string $key The field to search
858+ * @param array|string|Closure $values The values searched on, or anonymous function with subquery
859+ * @param boolean $escape
860+ *
861+ * @return BaseBuilder
862+ */
863+ public function orHavingIn (string $ key = null , $ values = null , bool $ escape = null )
864+ {
865+ return $ this ->_whereIn ($ key , $ values , false , 'OR ' , $ escape , 'QBHaving ' );
866+ }
867+
868+ //--------------------------------------------------------------------
869+
870+ /**
871+ * HAVING NOT IN
872+ *
873+ * Generates a HAVING field NOT IN('item', 'item') SQL query,
874+ * joined with 'AND' if appropriate.
875+ *
876+ * @param string $key The field to search
877+ * @param array|string|Closure $values The values searched on, or anonymous function with subquery
878+ * @param boolean $escape
879+ *
880+ * @return BaseBuilder
881+ */
882+ public function havingNotIn (string $ key = null , $ values = null , bool $ escape = null )
883+ {
884+ return $ this ->_whereIn ($ key , $ values , true , 'AND ' , $ escape , 'QBHaving ' );
885+ }
886+
887+ //--------------------------------------------------------------------
888+
889+ /**
890+ * OR HAVING NOT IN
891+ *
892+ * Generates a HAVING field NOT IN('item', 'item') SQL query,
893+ * joined with 'OR' if appropriate.
894+ *
895+ * @param string $key The field to search
896+ * @param array|string|Closure $values The values searched on, or anonymous function with subquery
897+ * @param boolean $escape
898+ *
899+ * @return BaseBuilder
900+ */
901+ public function orHavingNotIn (string $ key = null , $ values = null , bool $ escape = null )
902+ {
903+ return $ this ->_whereIn ($ key , $ values , true , 'OR ' , $ escape , 'QBHaving ' );
904+ }
905+
906+ //--------------------------------------------------------------------
907+
832908 /**
833909 * Internal WHERE IN
834910 *
@@ -842,10 +918,11 @@ public function orWhereNotIn(string $key = null, $values = null, bool $escape =
842918 * @param boolean $not If the statement would be IN or NOT IN
843919 * @param string $type
844920 * @param boolean $escape
921+ * @param string $clause (Internal use only)
845922 *
846923 * @return BaseBuilder
847924 */
848- protected function _whereIn (string $ key = null , $ values = null , bool $ not = false , string $ type = 'AND ' , bool $ escape = null )
925+ protected function _whereIn (string $ key = null , $ values = null , bool $ not = false , string $ type = 'AND ' , bool $ escape = null , string $ clause = ' QBWhere ' )
849926 {
850927 if ($ key === null || $ values === null || (! is_array ($ values ) && ! ($ values instanceof Closure)))
851928 {
@@ -874,14 +951,14 @@ protected function _whereIn(string $key = null, $values = null, bool $not = fals
874951 $ ok = $ this ->setBind ($ ok , $ whereIn , $ escape );
875952 }
876953
877- $ prefix = empty ($ this ->QBWhere ) ? $ this ->groupGetType ('' ) : $ this ->groupGetType ($ type );
954+ $ prefix = empty ($ this ->$ clause ) ? $ this ->groupGetType ('' ) : $ this ->groupGetType ($ type );
878955
879956 $ whereIn = [
880957 'condition ' => $ prefix . $ key . $ not . ($ values instanceof Closure ? " IN ( $ ok) " : " IN : {$ ok }: " ),
881958 'escape ' => false ,
882959 ];
883960
884- $ this ->QBWhere [] = $ whereIn ;
961+ $ this ->{ $ clause } [] = $ whereIn ;
885962
886963 return $ this ;
887964 }
@@ -970,6 +1047,86 @@ public function orNotLike($field, string $match = '', string $side = 'both', boo
9701047 return $ this ->_like ($ field , $ match , 'OR ' , $ side , 'NOT ' , $ escape , $ insensitiveSearch );
9711048 }
9721049
1050+ // --------------------------------------------------------------------
1051+
1052+ /**
1053+ * LIKE with HAVING clause
1054+ *
1055+ * Generates a %LIKE% portion of the query.
1056+ * Separates multiple calls with 'AND'.
1057+ *
1058+ * @param mixed $field
1059+ * @param string $match
1060+ * @param string $side
1061+ * @param boolean $escape
1062+ *
1063+ * @return BaseBuilder
1064+ */
1065+ public function havingLike ($ field , string $ match = '' , string $ side = 'both ' , bool $ escape = null , bool $ insensitiveSearch = false )
1066+ {
1067+ return $ this ->_like ($ field , $ match , 'AND ' , $ side , '' , $ escape , $ insensitiveSearch , 'QBHaving ' );
1068+ }
1069+
1070+ // --------------------------------------------------------------------
1071+
1072+ /**
1073+ * NOT LIKE with HAVING clause
1074+ *
1075+ * Generates a NOT LIKE portion of the query.
1076+ * Separates multiple calls with 'AND'.
1077+ *
1078+ * @param mixed $field
1079+ * @param string $match
1080+ * @param string $side
1081+ * @param boolean $escape
1082+ *
1083+ * @return BaseBuilder
1084+ */
1085+ public function notHavingLike ($ field , string $ match = '' , string $ side = 'both ' , bool $ escape = null , bool $ insensitiveSearch = false )
1086+ {
1087+ return $ this ->_like ($ field , $ match , 'AND ' , $ side , 'NOT ' , $ escape , $ insensitiveSearch , 'QBHaving ' );
1088+ }
1089+
1090+ // --------------------------------------------------------------------
1091+
1092+ /**
1093+ * OR LIKE with HAVING clause
1094+ *
1095+ * Generates a %LIKE% portion of the query.
1096+ * Separates multiple calls with 'OR'.
1097+ *
1098+ * @param mixed $field
1099+ * @param string $match
1100+ * @param string $side
1101+ * @param boolean $escape
1102+ *
1103+ * @return BaseBuilder
1104+ */
1105+ public function orHavingLike ($ field , string $ match = '' , string $ side = 'both ' , bool $ escape = null , bool $ insensitiveSearch = false )
1106+ {
1107+ return $ this ->_like ($ field , $ match , 'OR ' , $ side , '' , $ escape , $ insensitiveSearch , 'QBHaving ' );
1108+ }
1109+
1110+ // --------------------------------------------------------------------
1111+
1112+ /**
1113+ * OR NOT LIKE with HAVING clause
1114+ *
1115+ * Generates a NOT LIKE portion of the query.
1116+ * Separates multiple calls with 'OR'.
1117+ *
1118+ * @param mixed $field
1119+ * @param string $match
1120+ * @param string $side
1121+ * @param boolean $escape
1122+ *
1123+ * @return BaseBuilder
1124+ */
1125+ public function orNotHavingLike ($ field , string $ match = '' , string $ side = 'both ' , bool $ escape = null , bool $ insensitiveSearch = false )
1126+ {
1127+ return $ this ->_like ($ field , $ match , 'OR ' , $ side , 'NOT ' , $ escape , $ insensitiveSearch , 'QBHaving ' );
1128+ }
1129+
9731130 //--------------------------------------------------------------------
9741131
9751132 /**
@@ -979,6 +1136,10 @@ public function orNotLike($field, string $match = '', string $side = 'both', boo
9791136 * @used-by orLike()
9801137 * @used-by notLike()
9811138 * @used-by orNotLike()
1139+ * @used-by havingLike()
1140+ * @used-by orHavingLike()
1141+ * @used-by notHavingLike()
1142+ * @used-by orNotHavingLike()
9821143 *
9831144 * @param mixed $field
9841145 * @param string $match
@@ -987,10 +1148,11 @@ public function orNotLike($field, string $match = '', string $side = 'both', boo
9871148 * @param string $not
9881149 * @param boolean $escape
9891150 * @param boolean $insensitiveSearch IF true, will force a case-insensitive search
1151+ * @param string $clause (Internal use only)
9901152 *
9911153 * @return BaseBuilder
9921154 */
993- protected function _like ($ field , string $ match = '' , string $ type = 'AND ' , string $ side = 'both ' , string $ not = '' , bool $ escape = null , bool $ insensitiveSearch = false )
1155+ protected function _like ($ field , string $ match = '' , string $ type = 'AND ' , string $ side = 'both ' , string $ not = '' , bool $ escape = null , bool $ insensitiveSearch = false , string $ clause = ' QBWhere ' )
9941156 {
9951157 if (! is_array ($ field ))
9961158 {
@@ -1004,13 +1166,13 @@ protected function _like($field, string $match = '', string $type = 'AND ', stri
10041166
10051167 foreach ($ field as $ k => $ v )
10061168 {
1007- $ prefix = empty ($ this ->QBWhere ) ? $ this ->groupGetType ('' ) : $ this ->groupGetType ($ type );
1008-
10091169 if ($ insensitiveSearch === true )
10101170 {
10111171 $ v = strtolower ($ v );
10121172 }
10131173
1174+ $ prefix = empty ($ this ->$ clause ) ? $ this ->groupGetType ('' ) : $ this ->groupGetType ($ type );
1175+
10141176 if ($ side === 'none ' )
10151177 {
10161178 $ bind = $ this ->setBind ($ k , $ v , $ escape );
@@ -1036,7 +1198,7 @@ protected function _like($field, string $match = '', string $type = 'AND ', stri
10361198 $ like_statement .= sprintf ($ this ->db ->likeEscapeStr , $ this ->db ->likeEscapeChar );
10371199 }
10381200
1039- $ this ->QBWhere [] = [
1201+ $ this ->{ $ clause } [] = [
10401202 'condition ' => $ like_statement ,
10411203 'escape ' => $ escape ,
10421204 ];
@@ -1152,6 +1314,90 @@ public function groupEnd()
11521314 return $ this ;
11531315 }
11541316
1317+ // --------------------------------------------------------------------
1318+
1319+ /**
1320+ * Starts a query group for HAVING clause.
1321+ *
1322+ * @param string $not (Internal use only)
1323+ * @param string $type (Internal use only)
1324+ *
1325+ * @return BaseBuilder
1326+ */
1327+ public function havingGroupStart (string $ not = '' , string $ type = 'AND ' )
1328+ {
1329+ $ type = $ this ->groupGetType ($ type );
1330+
1331+ $ this ->QBWhereGroupStarted = true ;
1332+ $ prefix = empty ($ this ->QBHaving ) ? '' : $ type ;
1333+ $ having = [
1334+ 'condition ' => $ prefix . $ not . str_repeat (' ' , ++$ this ->QBWhereGroupCount ) . ' ( ' ,
1335+ 'value ' => null ,
1336+ 'escape ' => false ,
1337+ ];
1338+
1339+ $ this ->QBHaving [] = $ having ;
1340+
1341+ return $ this ;
1342+ }
1343+
1344+ // --------------------------------------------------------------------
1345+
1346+ /**
1347+ * Starts a query group for HAVING clause, but ORs the group.
1348+ *
1349+ * @return BaseBuilder
1350+ */
1351+ public function orHavingGroupStart ()
1352+ {
1353+ return $ this ->havingGroupStart ('' , 'OR ' );
1354+ }
1355+
1356+ // --------------------------------------------------------------------
1357+
1358+ /**
1359+ * Starts a query group for HAVING clause, but NOTs the group.
1360+ *
1361+ * @return BaseBuilder
1362+ */
1363+ public function notHavingGroupStart ()
1364+ {
1365+ return $ this ->havingGroupStart ('NOT ' , 'AND ' );
1366+ }
1367+
1368+ // --------------------------------------------------------------------
1369+
1370+ /**
1371+ * Starts a query group for HAVING clause, but OR NOTs the group.
1372+ *
1373+ * @return BaseBuilder
1374+ */
1375+ public function orNotHavingGroupStart ()
1376+ {
1377+ return $ this ->havingGroupStart ('NOT ' , 'OR ' );
1378+ }
1379+
1380+ // --------------------------------------------------------------------
1381+
1382+ /**
1383+ * Ends a query group for HAVING clause.
1384+ *
1385+ * @return BaseBuilder
1386+ */
1387+ public function havingGroupEnd ()
1388+ {
1389+ $ this ->QBWhereGroupStarted = false ;
1390+ $ having = [
1391+ 'condition ' => str_repeat (' ' , $ this ->QBWhereGroupCount -- ) . ') ' ,
1392+ 'value ' => null ,
1393+ 'escape ' => false ,
1394+ ];
1395+
1396+ $ this ->QBHaving [] = $ having ;
1397+
1398+ return $ this ;
1399+ }
1400+
11551401 //--------------------------------------------------------------------
11561402
11571403 /**
@@ -1161,6 +1407,7 @@ public function groupEnd()
11611407 * @used-by _like()
11621408 * @used-by whereHaving()
11631409 * @used-by _whereIn()
1410+ * @used-by havingGroupStart()
11641411 *
11651412 * @param string $type
11661413 *
0 commit comments