Using ->set(false)->get(false) for field validation on non-database fields

Using ->set(false)->get(false) for field validation on non-database fields

Loren MaxwellLoren Maxwell Posts: 490Questions: 120Answers: 10

Just a quick note for anyone that might find it helpful (plus a small suggestion for @allan at the end!):

Out of the box, Editor has very useful server-side field validation:
https://editor.datatables.net/manual/php/validation

(Lately I've especially taken advantage of the relatively new dependsOn() method!)

But occasionally data is submitted from the client-facing fields that don't match the fields in my table.

These non-database fields are used to do other things on the backend, but my point here is that I've previously done validation on those non-database fields in a global validator, which doesn't allow me to use the built-in field validation tools from Editor and also returns a global error instead of a field-specific one, so the UI isn't as helpful.

MY OLD WAY

// Requires: id, player_code, and school_code (all database fields)
// And either school_code or school_name_manual (not database fields) for other processing

Editor::inst( $db, 'players_seasons' )
    ->fields(
         
        Field::inst( 'id' ),
        Field::inst( 'player_code' )
            ->validator( 'Validate::notEmpty' ),
        Field::inst( 'season_code' )
            ->validator( 'Validate::notEmpty' )
    )

    // Non-database fields checked in a global validator
    ->validator( function ( $editor, $action, $data ) {
        if ( $action === Editor::ACTION_CREATE ) {   
            foreach ( $data['data'] as $pkey => $values ) {
                if (
                    empty($values['school_code'])
                    && empty($values['school_name_manual'])
                ) {
                    return "School cannot be blank";
                }
                return true;
            }
        }
        return true;
    });

However I've recently realized that by using both set(false) and get(false), the server-side Editor will accept those non-database fields without fussing they don't match the fields in the table and I can use field validation:

MY NEW WAY

// Requires: id, player_code, and school_code (all database fields)
// And either school_code or school_name_manual (not database fields) for other processing

Editor::inst( $db, 'players_seasons' )
    ->fields(
        Field::inst( 'id' ),
        Field::inst( 'player_code' )
            ->validator( 'Validate::notEmpty' ),
        Field::inst( 'season_code' )
            ->validator( 'Validate::notEmpty' ),
        
        // Non-database fields checked in a field validator
        // with ->set(false)->get(false)
        
        Field::inst( 'school_name_manual' )->set(false)->get(false),
        
        Field::inst( 'school_code' )->set(false)->get(false),
            ->validator( Validate::notEmpty( ValidateOptions::inst()
                ->message( 'School cannot be blank' )
                ->dependsOn(function ($val, $row, $host) {
                    return empty($row['school_name_manual']);
                })
            ))
    );

This does the same thing except it's cleaner coding and the error for a missing school_code and school_name_manual shows on the client side under the specific field the client sees.


Suggestion for @allan would be to include an ignore() method (or submit(false) or something similar) that would do the same as the ->set(false)->get(false), such as:

SUGGESTION

// Requires: id, player_code, and school_code (all database fields)
// And either school_code or school_name_manual (not database fields) for other processing

Editor::inst( $db, 'players_seasons' )
    ->fields(
        Field::inst( 'id' ),
        Field::inst( 'player_code' )
            ->validator( 'Validate::notEmpty' ),
        Field::inst( 'season_code' )
            ->validator( 'Validate::notEmpty' ),
        
        // Non-database fields
        // with ->ignore() (or submit(false) or something similar)
        
        Field::inst( 'school_name_manual' )->ignore(),
        
        Field::inst( 'school_code' )->ignore(),
            ->validator( Validate::notEmpty( ValidateOptions::inst()
                ->message( 'School cannot be blank' )
                ->dependsOn(function ($val, $row, $host) {
                    return empty($row['school_name_manual']);
                })
            ))
    );

Replies

  • allanallan Posts: 65,655Questions: 1Answers: 10,919 Site admin

    Many thanks for the suggestion! I'll certainly consider it. I'm a little worried about making the API surface bigger than it needs to be, but I can see the utility here.

    Thanks for posting this so others can see your solution as well.

    Allan

Sign In or Register to comment.