0

I am using CakePHP2.8 and I would like to share multiple custom validation methods between models.

I have created a helper CustomValidators.php class using custom validation methods known to work within models. Logic here is not problem, here only for illustration.

<?php
App::uses('CakeLog', 'Utility');

class CustomValidators {

  public function checkDateNotFuturePast($checks, $params)
  {
    $params += array(
      'type' => 'past', //Date cannot be in the past
      'current_date' => 'now', //Todays date
      'include_current_date' => false //Allow current date to pass validation
    );
    CakeLog::write('error', print_r(json_encode([
      'checks' => $checks,
      'params' => $params,
    ]), true));

    $date = array_values($checks)[0];

    try {
      $timezone = new DateTimeZone("UTC");
      $input_date = new DateTime($date, $timezone);
      $current_date = new DateTime($params['current_date'], $timezone);
    } catch(Exception $e) {
      return false;
    }

    switch ($params['type']) {
      case 'future':
        if($params['include_current_date']){
          if($input_date->format('dmY') != $current_date->format('dmY')&&$input_date->format('U') > $current_date->format('U')) return false;
        }else{
          if($input_date->format('U') > $current_date->format('U')) return false;
        }
        break;
      case 'past':
        if($params['include_current_date']){
          if($input_date->format('dmY') != $current_date->format('dmY')&&$input_date->format('U') <= $current_date->format('U')) return false;
        }else{
          if($input_date->format('U') < $current_date->format('U')) return false;
        }
        break;
    }

    return true;
  }

  public function checkNotOlderThan($check, $params)
  {
    CakeLog::write('error', 'CustomValidators::checkNotOlderThan');
    $params += [
      'current_date' => date('Y-m-d'),
    ];
     CakeLog::write('error', print_r(json_encode([
      'checks' => $checks,
      'params' => $params,
    ]), true));

    if (!isset($params['range'])) {
      return false;
    }

    $date = array_values($check)[0];

    try {
      $current_date = new DateTime($params['current_date']);
      $current_date->modify('-' . $params['range']);
      $input_date = new DateTime($date);
    } catch(Exception $e) {
      return false;
    }

    if ($input_date >= $current_date) {
      return true;
    }

    return false;
  }

}

I am including this file in the model JobCustomA and instantiating it in beforeValidate.

  public function beforeValidate($options = [])
  {
    $CustomValidators = new CustomValidators();

I'm trying to have all validation for JobCustomA in its model which will validate data from Job.

In my JobCustomA model I want to add validation on Job, I'm doing like so:

public function beforeValidate($options = [])
{
  $CustomValidators = new CustomValidators();

  $this->Job->validator()->add('deposit_paid', [
    'not_future' => [
      'rule' => [
        'userDefined', $CustomValidators, 'checkDateNotFuturePast', [
          'type' => 'future',
        ]
      ],
      'message' => 'Deposit date can\'t be in the future',
    ],
    'nottooold' => [
      'rule' => [
        'userDefined', $CustomValidators, 'checkNotOlderThan', [
          'current_date' => date('Y-m-d'),
          'range' => '120 days',
        ],
      ],
      'message' => 'Deposit date can\'t have been paid more than 120 days ago',
    ],
  ]);

  // ...
}

However it doesn't seem to be going to these custom validation methods, I'm not sure how to fix this. I need to be able to reuse custom validation methods between many classes without duplicating them in each model.

TL;DR: Using userDefined role in validator add is not working, need to reuse many custom validation methods between multiple models.

Thanks

5
  • Are you sure that it's the rule that doesn't work? Have you tested that the beforeValidate() method is being invoked at all, and especially that it is being invoked before validation is applied on the Job model data? Commented Aug 24, 2017 at 20:41
  • Yes, I put some logging in, logging works in the beforeValidate the rules in helper didn't write anything so didn't hit the rule. Commented Aug 25, 2017 at 8:11
  • Did you take a look at this book.cakephp.org/2.0/en/models/… It explains how you can properly define a custom validation methods Commented Aug 25, 2017 at 8:55
  • Yes, I have read it and it works if the custom validation method is in the model, I have the issue where the custom validation rule I want to use is not in that model. Commented Aug 25, 2017 at 11:17
  • Hence the question whether the rules are being defined early enough. I could imagine that the associated models beforeValidate() callback is being invoked after the validation on the parent model has already been applied. Commented Aug 25, 2017 at 13:19

1 Answer 1

0

You could have couple options here:

  • Define the custom validation rules in the AppModel, this way you can use them in any model without copying
  • Create an abstract model, for example Job, and then extend this model to create CustomJobA, CustomJobB etc, and define the custom validations there. All the models which extends the Job model could use your validation rules
  • Create a behavior, and define the validation rules there, and use this behavior on any model.
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.