Потерял доступ к тому же свойству, пытаясь использовать лучшие практики / шаблон проектирования - PullRequest
0 голосов
/ 21 января 2010

у меня было:

  • в классе, реализующем Validator:
    • свойство $ errormessages
    • метод isCorrect ()

В методе isCorrect у меня было:

switch ($type): 
    case 'email':
        isEmailCorrect();
    case 'password':
        isPasswordCorrect();
    case 'x':
        isXCorrect();

isEmailCorrect (), isPasswordCorrect () и isXCorrect () имели доступ к одному и тому же свойству со всеми сообщениями об ошибках

Теперь у меня есть:

  • в валидаторе:
    • свойство $ errormessages
  • в классе EmailValidator, расширяющем Validator:
    • метод isCorrect ()
  • в классе PasswordValidator, расширяющем Validator:
    • метод isCorrect ()
  • в классе расширения XValidator:
    • метод isCorrect ()

Теперь в файле, вызывающем методы isCorrect (), у меня есть:

$EmailValidator = new EmailValidator();
$PasswordValidator = new PasswordValidator();
$XValidator = new XValidator();

$EmailValidator->isCorrect(), $PasswordValidator->isCorrect() и $XValidator->isCorrect() не имеют доступа к одному и тому же свойству со всеми сообщениями об ошибках

$ errormessages в разных экземплярах разных классов. Они должны быть один, но три.

Что теперь?

Ответы [ 5 ]

2 голосов
/ 21 января 2010

Я думаю, вам следует разработать другой класс: ValidatorChain, который принимает произвольное количество валидаторов и объединяет сообщения об ошибках всех валидаторов, которые он тестировал

Для справки см. документы по цепочке валидаторов Zend Framework

EDIT

Теперь, когда я переоцениваю ваш вопрос (благодаря комментарию Брайана М); Почему вы хотите, чтобы каждый отдельный Валидатор имел доступ к сообщениям об ошибках других Валидаторов? Я бы сказал, что сбор сообщений об ошибках каждого отдельного Валидатора является обязанностью объекта выше в иерархии.

Если, однако, вы хотите, чтобы отдельные валидаторы могли действовать в зависимости от контекста, другими словами, в зависимости от результатов других валидаторов, то я полагаю, вы можете добавить параметр $ context в метод isCorrect , Это может, например, принять произвольное количество валидаторов или что-то подобное.

Что-то вроде:

interface ValidatorInterface
{
    public function isCorrect( array $context );
    public function getMessages();
}

abstract class ValidatorContextOptions
{
    const SHOULD_BE_PRESENT = 'shouldBePresent';
    const SHOULD_NOT_BE_PRESENT = 'shouldNotBePresent';
    const SHOULD_BE_VALID = 'shouldBeValid';
}

class EmailValidator implements ValidatorInterface
{
    protected $_field;

    protected $_contextOptions = array();

    protected $_messages = array();

    public function __construct( $field, array $contextOptions )
    {
        $this->_field = $field;
        $this->_contextOptions = $contextOptions;
    }

    public function isCorrect( array $context = null )
    {
        foreach( $this->_contextOptions as $field => $options )
        {
            foreach( $options as $option )
            {
               switch( $option )
               {
                   case ValidatorContextOptions::SHOULD_NOT_BE_PRESENT:
                       if( isset( $context[ $field ] )
                           && $context[ $field ] instanceof ValidatorInterface )
                       {
                           $this->_messages[] = $field . ' should not be present';
                           return false;
                       }
                       break;
                   case ValidatorContextOptions::SHOULD_BE_PRESENT:
                       if( !isset( $context[ $field ] )
                           || !$context[ $field ] instanceof ValidatorInterface )
                       {
                           $this->_messages[] = $field . ' should be present';
                           return false;
                       }
                       break;
                   case ValidatorContextOptions::SHOULD_BE_VALID:
                       if( !isset( $context[ $field ] )
                           || !$context[ $field ] instanceof ValidatorInterface
                           || !$context[ $field ]->isCorrect() )
                       {
                           $this->_messages[] = $field . ' should be valid';
                           return false;
                       }
                       break;
               }
            }
        }

        // some dummy function which you should replace with real validation
        return isAnEmailAddress( $this->_field );
    }

    public function getMessages()
    {
        return $this->_messages;
    }
}

Использование:

$emailValidatorContextOptions = array
(
    'phone' => array( 
                   ValidatorContextOptions::SHOULD_BE_PRESENT,
                   ValidatorContextOptions::SHOULD_BE_VALID
               )
);

$phoneValidator = new PhoneValidator( $phoneString );
$emailValidator = new EmailValidator( $emailString, $emailValidatorContextOptions );

if( !$emailValidator->isCorrect( array( 'phone' => $phoneValidator ) ) )
{
    print_r( $emailValidator->getMessages() );
}

То, что я показал здесь, требует гораздо больше размышлений (и я действительно имею в виду много), чертовски глючит и определенно не пуленепробиваемое. Но я надеюсь, что вы поймете, что я пойду с этим.

Кроме того, куда вы вставляете значения в свой валидатор, которые все равно должны быть проверены?

0 голосов
/ 21 января 2010

Кто-то из упомянутых ниже использует для этого синглтон.

Я не убежден, что этот шаблон проектирования хорошо используется, тем более что принято считать, что синглтоны являются «анти-шаблоном» и часто чрезмерно / неправильно используются.

Тем не менее, имея это в виду, вот пример в этом духе:

<?php

//Error Class implemented as a Singleton
class ErrorClass
{

  static private $instance = false;
  static private $errorMessages;

  function getInstance() {
    if (!self::$instance) {
      self::$instance = new ErrorClass();
      self::$errorMessages = "No errors;";
    }
    return self::$instance;
  }

  public function setError($errorMessage){
    self::$instance->errorMessages .= $errorMessage;
  }

  public function getError(){
    return self::$instance->errorMessages;
  }

}

abstract class AbstractClass
{

  // Force Extending class to define this method
  abstract protected function isCorrect($b);

  // Common Method for setting error
  public function setError($errorMessage) {
    ErrorClass::getInstance()->setError($errorMessage);   
  }

  // Common Method for getting error
  public function getError() {
    return ErrorClass::getInstance()->getError();   
  }
}

class EmailValidator extends AbstractClass
{

  public function isCorrect($b) {
    if(!$b) {
      $this->setError('EmailValidator->isCorrect();');
    }
  }

}

class PasswordValidator extends AbstractClass
{

  public function isCorrect($b) {
    if(!$b) {
      $this->setError('PasswordValidator->isCorrect();');
    }
  }

}

// Then in your code
$errorState = 1; // used for testing purposes

$EmailValidator = new EmailValidator(); 
$EmailValidator->isCorrect($errorState);

$PasswordValidator = new PasswordValidator(); 
$PasswordValidator->isCorrect($errorState);

echo $EmailValidator->getError();
echo $PasswordValidator->getError();
0 голосов
/ 21 января 2010

Если я правильно вас понял, вы хотите, чтобы несколько экземпляров совместно использовали одно и то же свойство сообщений об ошибках, чтобы вы могли создавать экземпляры нескольких валидаторов и делать так, чтобы все они вносили свой вклад в один массив.

Если это так, есть несколько способов сделать это. Можно было бы создать класс менеджера валидаторов, который отвечает за создание и регистрацию валидаторов. Затем, когда проверка завершена, вы можете вызвать $validator_manager->getErrors(), который объединит ошибки, присутствующие во всех зарегистрированных валидаторах.

Другим способом, которым вы могли бы это сделать, было бы использование класса хранения одноэлементных ошибок, который вы получаете в конструкторе каждого валидатора. Каждый метод валидатора addError() затем делегирует задание одиночному.

Есть и другие методы, но в основном вам придется использовать другой объект, либо для управления валидаторами, либо для хранения ошибок.

0 голосов
/ 21 января 2010

Я часто буду использовать Zend_Validate классы для выполнения проверки и агрегирования любого сообщения об ошибке для свойства объекта, который проверяется (а также для флага, управляющего действительным состоянием).

Моя установка будет похожа на эту:

class User {
  public $email;
  protected $_errorMessages = array();

  public function validate()
  {
    $valid = true;

    $emailValidator = new EmailValidator();
    if (!$emailValidator->isCorrect($this->email)) {
      $valid = false;

      // validation message are added to the $errormessages property in
      // the validator class upon failure of isCorrect()
      $this->_errorMessages[] = $emailValidator->getMessages();
    }

    // repeat this for all your validators

    return $valid
  }

  public function getErrorMessages()
  {
     return $this->_errorMessages();
  }
}

// in your page....
if (!$user->validate()) {
  $messages = $user->getErrorMessages();
}
0 голосов
/ 21 января 2010

Что ж, вы могли бы создать фабрику внешних свойств для управления доступом к вашему свойству, если вы говорите о файлах свойств, что я обычно и использую.

Если вы имеете в виду общее поле, вы можете поместить его в базовый класс и получить к нему доступ таким образом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...