@@ -39,7 +39,7 @@ trait Custom_Table_Query_Methods {
3939 *
4040 * @return Generator<array<string, mixed>> The rows from the table.
4141 */
42- public static function fetch_all ( int $ batch_size = 50 , string $ output = OBJECT , string $ where_clause = '' , string $ order_by = '' ): Generator {
42+ protected static function fetch_all ( int $ batch_size = 50 , string $ output = OBJECT , string $ where_clause = '' , string $ order_by = '' ): Generator {
4343 $ fetched = 0 ;
4444 $ total = null ;
4545 $ offset = 0 ;
@@ -50,18 +50,20 @@ public static function fetch_all( int $batch_size = 50, string $output = OBJECT,
5050
5151 $ order_by = $ order_by ?: implode ( ', ' , array_map ( fn ( $ column ) => "{$ column } ASC " , $ primary_columns ) );
5252
53+ $ query = $ database ::prepare (
54+ "SELECT * FROM %i {$ where_clause } ORDER BY {$ order_by } LIMIT %d, %d " ,
55+ static ::table_name ( true ),
56+ $ offset ,
57+ $ batch_size
58+ );
59+
5360 $ batch = $ database ::get_results (
54- $ database ::prepare (
55- "SELECT * FROM %i {$ where_clause } ORDER BY {$ order_by } LIMIT %d, %d " ,
56- static ::table_name ( true ),
57- $ offset ,
58- $ batch_size
59- ),
61+ $ query ,
6062 $ output
6163 );
6264
6365 // We need to get the total number of rows, only after the first batch.
64- $ total ??= $ database ::get_var ( "SELECT COUNT(*) FROM %i {$ where_clause }" , static ::table_name ( true ) );
66+ $ total ??= $ database ::get_var ( $ database :: prepare ( "SELECT COUNT(*) FROM %i {$ where_clause }" , static ::table_name ( true ) ) );
6567 $ fetched += count ( $ batch );
6668
6769 $ offset += $ batch_size ;
@@ -70,6 +72,25 @@ public static function fetch_all( int $batch_size = 50, string $output = OBJECT,
7072 } while ( $ fetched < $ total );
7173 }
7274
75+ /**
76+ * Fetches all the rows from the table using a batched query.
77+ *
78+ * @since TBD
79+ *
80+ * @param int $batch_size The number of rows to fetch per batch.
81+ * @param string $where_clause The optional WHERE clause to use.
82+ * @param string $order_by The optional ORDER BY clause to use.
83+ *
84+ * @return Generator<array<string, mixed>> The rows from the table.
85+ */
86+ public static function get_all ( int $ batch_size = 50 , string $ where_clause = '' , string $ order_by = '' ): Generator {
87+ $ batch = static ::fetch_all ( $ batch_size , ARRAY_A , $ where_clause , $ order_by );
88+
89+ foreach ( $ batch as $ row ) {
90+ yield static ::transform_from_array ( static ::amend_value_types ( $ row ) );
91+ }
92+ }
93+
7394 /**
7495 * Inserts a single row into the table.
7596 *
@@ -204,6 +225,7 @@ function ( $c ) use ( $prepared_ids ) {
204225 * @return array<string> The prepared statements and values.
205226 */
206227 protected static function prepare_statements_values ( array $ entries ): array {
228+ $ database = Config::get_db ();
207229 $ columns = array_keys ( $ entries [0 ] );
208230 $ prepared_columns = implode (
209231 ', ' ,
@@ -215,7 +237,7 @@ protected static function prepare_statements_values( array $entries ): array {
215237 $ prepared_values = implode (
216238 ', ' ,
217239 array_map (
218- static fn ( array $ entry ) => '( ' . implode ( ', ' , array_map ( static fn ( $ e ) => DB ::prepare ( '%s ' , $ e instanceof DateTimeInterface ? $ e ->format ( 'Y-m-d H:i:s ' ) : $ e ), $ entry ) ) . ') ' ,
240+ static fn ( array $ entry ) => '( ' . implode ( ', ' , array_map ( static fn ( $ e ) => $ database ::prepare ( '%s ' , $ e instanceof DateTimeInterface ? $ e ->format ( 'Y-m-d H:i:s ' ) : $ e ), $ entry ) ) . ') ' ,
219241 $ entries
220242 )
221243 );
@@ -235,7 +257,7 @@ protected static function prepare_statements_values( array $entries ): array {
235257 *
236258 * @return Generator<array<string, mixed>> The rows from the table.
237259 */
238- public static function fetch_all_where ( string $ where_clause , int $ batch_size = 50 , string $ output = OBJECT , string $ order_by = '' ): Generator {
260+ protected static function fetch_all_where ( string $ where_clause , int $ batch_size = 50 , string $ output = OBJECT , string $ order_by = '' ): Generator {
239261 return static ::fetch_all ( $ batch_size , $ output , $ where_clause , $ order_by );
240262 }
241263
@@ -249,7 +271,7 @@ public static function fetch_all_where( string $where_clause, int $batch_size =
249271 *
250272 * @return array|object|null The row from the table, or `null` if no row was found.
251273 */
252- public static function fetch_first_where ( string $ where_clause , string $ output = OBJECT ) {
274+ protected static function fetch_first_where ( string $ where_clause , string $ output = OBJECT ) {
253275 $ database = Config::get_db ();
254276
255277 return $ database ::get_row (
@@ -297,7 +319,7 @@ public static function update_many( array $entries ): bool {
297319 $ database = Config::get_db ();
298320
299321 $ queries = [];
300- $ columns = array_keys ( static ::get_columns () );
322+ $ columns = static ::get_columns ()-> get_names ( );
301323 foreach ( $ entries as $ entry ) {
302324 $ uid = $ entry [ $ uid_column ] ?? '' ;
303325
@@ -373,7 +395,7 @@ public static function paginate( array $args, int $per_page = 20, int $page = 1,
373395 $ orderby = $ args ['orderby ' ] ?? static ::uid_column ();
374396 $ order = strtoupper ( $ args ['order ' ] ?? 'ASC ' );
375397
376- if ( ! in_array ( $ orderby , array_keys ( static ::get_columns () ), true ) ) {
398+ if ( ! in_array ( $ orderby , static ::get_columns ()-> get_names ( ), true ) ) {
377399 $ orderby = static ::uid_column ();
378400 }
379401
@@ -409,7 +431,7 @@ public static function paginate( array $args, int $per_page = 20, int $page = 1,
409431 $ output
410432 );
411433
412- $ results = array_map ( fn ( $ result ) => self ::amend_value_types ( $ result ), $ results );
434+ $ results = array_map ( fn ( $ result ) => static :: transform_from_array ( self ::amend_value_types ( $ result ) ), $ results );
413435
414436 /**
415437 * Fires after the results of the query are fetched.
@@ -461,18 +483,18 @@ protected static function build_where_from_args( array $args = [] ): string {
461483 if ( $ search ) {
462484 $ searchable_columns = static ::get_searchable_columns ();
463485
464- if ( ! empty ( $ searchable_columns ) ) {
486+ if ( $ searchable_columns ) {
465487 $ search_where = [];
466488
467489 foreach ( $ searchable_columns as $ column ) {
468- $ search_where [] = $ database ::prepare ( "{$ joined_prefix }{$ column } LIKE %s " , '% ' . $ database ::esc_like ( $ search ) . '% ' );
490+ $ search_where [] = $ database ::prepare ( "{$ joined_prefix }{$ column-> get_name () } LIKE %s " , '% ' . $ database ::esc_like ( $ search ) . '% ' );
469491 }
470492
471493 $ where [] = '( ' . implode ( ' OR ' , $ search_where ) . ') ' ;
472494 }
473495 }
474496
475- $ columns = array_keys ( static ::get_columns () );
497+ $ columns = static ::get_columns ()-> get_names ( );
476498
477499 foreach ( $ args as $ arg ) {
478500 if ( ! is_array ( $ arg ) ) {
@@ -556,9 +578,9 @@ protected static function get_join_parts( string $join_table, string $join_condi
556578
557579 $ join_condition = array_map ( 'trim ' , explode ( '= ' , $ join_condition , 2 ) );
558580
559- $ secondary_table_columns = array_keys ( $ join_table ::get_columns () );
581+ $ secondary_table_columns = $ join_table ::get_columns ()-> get_names ( );
560582
561- $ both_table_columns = array_merge ( array_keys ( static ::get_columns () ), $ secondary_table_columns );
583+ $ both_table_columns = array_merge ( static ::get_columns ()-> get_names ( ), $ secondary_table_columns );
562584
563585 if ( ! in_array ( $ join_condition [0 ], $ both_table_columns , true ) || ! in_array ( $ join_condition [1 ], $ both_table_columns , true ) ) {
564586 throw new InvalidArgumentException ( 'The join condition must contain valid columns. ' );
@@ -590,20 +612,23 @@ protected static function get_join_parts( string $join_table, string $join_condi
590612 *
591613 * @since TBD
592614 *
593- * @param string $column The column to get the models by.
594- * @param mixed $value The value to get the models by.
595- * @param int $limit The limit of models to return.
615+ * @param string $column The column to get the models by.
616+ * @param mixed $value The value to get the models by.
617+ * @param string $operator The operator to use.
618+ * @param int $limit The limit of models to return.
596619 *
597620 * @return mixed[] The models, or an empty array if no models are found.
598621 *
599622 * @throws InvalidArgumentException If the column does not exist.
600623 */
601- public static function get_all_by ( string $ column , $ value , int $ limit = 50 ): ?array {
624+ public static function get_all_by ( string $ column , $ value , string $ operator = ' = ' , int $ limit = 50 ): ?array {
602625 [ $ value , $ placeholder ] = self ::prepare_value_for_query ( $ column , $ value );
603626
627+ $ operator = strtoupper ( $ operator );
628+
604629 $ database = Config::get_db ();
605630 $ results = [];
606- foreach ( static ::fetch_all_where ( $ database ::prepare ( "WHERE {$ column } = {$ placeholder }" , $ value ), $ limit , ARRAY_A ) as $ task_array ) {
631+ foreach ( static ::fetch_all_where ( $ database ::prepare ( "WHERE {$ column } { $ operator } {$ placeholder }" , $ value ), $ limit , ARRAY_A ) as $ task_array ) {
607632 if ( empty ( $ task_array [ static ::uid_column () ] ) ) {
608633 continue ;
609634 }
@@ -654,13 +679,16 @@ public static function get_first_by( string $column, $value ) {
654679 private static function prepare_value_for_query ( string $ column , $ value ): array {
655680 $ columns = static ::get_columns ();
656681
657- if ( ! isset ( $ columns [ $ column ] ) ) {
682+ /** @var ?Column $column */
683+ $ column = $ columns ->get ( $ column );
684+
685+ if ( ! $ column ) {
658686 throw new InvalidArgumentException ( "Column $ column does not exist. " );
659687 }
660688
661- $ column_type = $ columns [ $ column ][ ' php_type ' ] ;
689+ $ column_type = $ column-> get_php_type () ;
662690
663- switch ( $ column_type ) {
691+ switch ( $ column -> get_php_type () ) {
664692 case Column::PHP_TYPE_INT :
665693 case Column::PHP_TYPE_BOOL :
666694 $ value = is_array ( $ value ) ? array_map ( fn ( $ v ) => (int ) $ v , $ value ) : (int ) $ value ;
@@ -727,21 +755,25 @@ public static function operators(): array {
727755 * @return array<string, mixed> The amended data.
728756 *
729757 * @throws InvalidArgumentException If the column type is unsupported.
758+ * @throws InvalidArgumentException If the datetime value format is invalid.
730759 */
731760 private static function amend_value_types ( array $ data ): array {
732761 $ columns = static ::get_columns ();
762+ $ column_names = $ columns ->get_names ();
733763 foreach ( $ data as $ column => $ value ) {
734- if ( ! isset ( $ columns [ $ column ] ) ) {
764+ if ( ! in_array ( $ column , $ column_names , true ) ) {
735765 continue ;
736766 }
737767
738- $ column_data = $ columns[ $ column ] ;
768+ $ column_object = $ columns-> get ( $ column ) ;
739769
740- if ( ! empty ( $ column_data [ ' nullable ' ] ) && null === $ value ) {
770+ if ( $ column_object -> get_nullable ( ) && null === $ value ) {
741771 continue ;
742772 }
743773
744- switch ( $ column_data ['php_type ' ] ) {
774+ $ column_php_type = $ column_object ->get_php_type ();
775+
776+ switch ( $ column_php_type ) {
745777 case Column::PHP_TYPE_INT :
746778 $ data [ $ column ] = (int ) $ value ;
747779 break ;
@@ -765,9 +797,18 @@ private static function amend_value_types( array $data ): array {
765797 }
766798
767799 $ data [ $ column ] = $ instance ::createFromFormat ( 'Y-m-d H:i:s ' , $ value );
800+
801+ if ( ! $ data [ $ column ] instanceof DateTimeInterface ) {
802+ $ data [ $ column ] = $ instance ::createFromFormat ( 'Y-m-d ' , $ value );
803+ }
804+
805+ if ( ! $ data [ $ column ] instanceof DateTimeInterface ) {
806+ throw new InvalidArgumentException ( "Invalid datetime value format: {$ value }. " );
807+ }
808+
768809 break ;
769810 default :
770- throw new InvalidArgumentException ( "Unsupported column type: {$ column_data [ ' php_type ' ] }. " );
811+ throw new InvalidArgumentException ( "Unsupported column type: {$ column_php_type }. " );
771812 }
772813 }
773814
0 commit comments