Помогите с сервисным слоем

grigori

( ͡° ͜ʖ ͡°)
Команда форума
>Если трудновато придумать адекватное название
трудности ты придумал, для меня это просто сценарий: один параметр модели, один опциональный параметр правила валидации

>мы должны будем менять что-то в модели, которая универсальна
Мне кажется, это достоинство сферической модели в вакууме.
Модель создается под данные, структура данных и контроллер - под задачу.
Меняется логика - меняется и модель, и контроллер. Изменений логики без изменения модели я и не помню.
Не вижу проблем при добавлении контроллера добавить пару строк в список правил в модели, минута дела.
Слишком редко возникают задачи подобные "добавить еще один способ регистрации пользователя".

А вот скорость написания и доработки сложных правил валидации данных, в которых нужна модель - это очень важно.
В модели можно создать простые стандартные правила вроде checkUnique с проверкой уникальности значения в таблице базы, checkIn для проверки вхождения в значения внешнего ключа или enum-поля.
Можно использовать генераторы кода правил валидации по полям таблицы в базе, что сокращает объем ручной работы.
Общие затраты времени на разработку при инкапсуляции данных и проверки в одной модели получаются намного меньше, так как убирают необходимость создания объектов, не возникают проблемы взаимодействия и передачи данных, сильно сокращается объем кода.

Я в этом вопросе смотрю на деньги, а не идеологию. может, дело в этом?
 

korchasa

LIMB infected
Общие затраты времени на разработку при инкапсуляции данных и проверки в одной модели получаются намного меньше, так как убирают необходимость создания объектов, не возникают проблемы взаимодействия и передачи данных, сильно сокращается объем кода.
Можно поподробнее?
 

igortik

Новичок
если сложно определиться, то стоит вспомнить про ТТУК.

модель должна отвечать за работу с данными, а логика "думать, к кому обратиться".
Здесь, скорее, просто имеет место заблуждение на счет специфики данных, ведь капча - это просто строка, а не какая-то "абстрактная единица".
Эту строку необходимо проверить с каким-то значением, не более ни менее.

А если речь идет о сохранности модели, то вопрос - зачем?
Вед в контексте текущей задачи нужно конкретное решение, требующее изменений!
 

varan

Б̈́̈̽ͮͣ̈Л̩̲̮̻̤̹͓ДͦЖ̯̙̭̥̑͆А͇̠̱͓͇̾ͨД͙͈̰̳͈͛ͅ
Мне кажется, это достоинство сферической модели в вакууме.
Вообще, я согласен, что проблема не очень существенна. Просто немного неприятно загаживать объект модели знанием о капчах и проч. Кстати, чтобы проверить капчу, модель еще должна знать о сессии и т.д.

korchasa, о чем именно? фраза длинная
Мне тоже не очень понятно, в чем выигрыш по затратам времени разработки. Можешь псевдокод какой-нибудь привести? Все равно ведь есть какое-то место, где все правила валидации собираются в одну кучу (объект или массив), а только потом валидируются. Или не так? Так какая разница, для чего создавать этот объект, для немедленной валидации или для return $validator?
 

Krishna

Продался Java
я наверно не так выразился. Я имел в виду, что это не задача сущности (легковесный класс с геттерами/сеттерами). Модель: сущность + набор правил для ее валидации + источник данных.
FAIL. Модель - это логика и данные домена. Контроллер - не более чем обработка запросов пользователя - первичная валидация _запроса_ и решение какие методы модели и view нужно дёрнуть для конкретного запроса пользователя.
 

Koc

Новичок
не понял, и что не так в моей цитате? И как это противоречит с тем, что ты написал?
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
varan, вот простейший пример: модель Post форума или блога, реальный код.
Правила собираются в массиве.
PHP:
class Posts extends CActiveRecord{
	public function rules(){
		return array(
			array('id', 'required','on'=>'update'), //applied only for "update" scenario
			array('title,category_id,status,description', 'required'), // for all scenarios
			array('title', 'length', 'max'=>255),
			array('category_id', 'numerical', 'integerOnly'=>true, 'min'=>0),
			array('category_id', 'exist', 'attributeName' => 'id','className' => 'Categories','skipOnError'=>true),
			array('status', 'in', 'range'=>array('Draft','Published','Hidden')),
			array('description', 'length', 'max'=>2048),
		);
	}
	public function relations(){
		return array(
			'categories'=>array(
				self::BELONGS_TO,'Categories','category_id'
			),
status - поле enum, category_id - внешний ключ.
В рамках модели, связанной с базой, эти проверки вполне логичны.
Если мы выносим эти проверки в контроллер - мы создаем зависимость контроллера от структуры таблицы, пишем код, который вызывает модель Categories и реализует проверку с учетом связи таблиц posts и categories.
Для сравнения: мне хватает 2х строк в списке правил валидации.
Изменения списка enum и внешних связей возникают достаточно часто, и мне достаточно подправить только модель.

Пример посложнее: платеж, нужна проверка остатка на счете в транзакции.
Я напишу
PHP:
class Order extends CActiveRecord{
    private $transaction;
	protected function onBeforeValidate{
		$this->transaction = $this->dbConnection->beginTransaction();
	}
	public function rules(){
		return array(
			...
			array('amount', 'checkBalance'),
		);
	}
	public function checkBalance($attr){
		return $this->Users->balance >= $this->amount;
	}
	protected function onAfterValidate(){if (this->error) $this->transaction->rollBack();}

	public function relations(){
		return array(
	        'user'=>array(
		        self::BELONGS_TO,'Users','user_id'
		        ),
		);
	}
...
	protected function onAfterSave{
		$this->transaction->commit();
	}
}
сделать такую проверку в контроллере заметно сложнее - начинать и коммитить транзакцию придется напрямую из контроллера, а перед этим - проверить, открыта ли она, т.е. нарушений инкапсуляции и хрупкости гораздо больше, чем от добавления пары строк в модель
 

Krishna

Продался Java
Я имел в виду, что это не задача сущности (легковесный класс с геттерами/сеттерами). Модель: сущность + набор правил для ее валидации + источник данных.
не понял, и что не так в моей цитате? И как это противоречит с тем, что ты написал?
1) Выделение "легковесной сущности с сеттерами и геттерами", так называемая "анемичная модель" - ущербная практика, противоречащая основам ООП - инкапсуляции данных и логики работающих с этими данными в едином объекте. Подробнее тут: http://martinfowler.com/bliki/AnemicDomainModel.html
Могу сказать, что вижу уже второй проект реализованный с подобным подходом (хвалёный J2EE) и это полный П...
Процедурный код спагетти во всей красе. Впрочем, это несколько оффтопик и об этом можно долго дискутировать. В любом случае есть следующие пункты:

2) Независимо от того в отдельных ли классах ты реализуешь логику или в классах сущности - логика модели принадлежит к модели.

3) Исходя из твоего определения модели получается, что валидация в модели представлена только собственно валидацией строго в рамках сущности. В то время, как валидация модели гораздо интереснее на уровни комплексных сценариев, где участвуют несколько сущностей. Например, что статус заказа не может перейти в Оплачен, если сумма поступившего от клиента платежа меньше суммарной стоимости товаров в корзине, а количество некоторых позиций заказа превышает доступное количество соответствующих товаров на складе. Такая валидация не принадлежит отдельной сущности, но тем не менее является валидацией на уровне модели.
 

Koc

Новичок
Что если, сделать

PHP:
ValidatableInterface
{
  function getValidator();
}
и перегрузить Doctrine\Orm\EntityManager

PHP:
class Foo\Em extends \Doctrine\Orm\EntityManager
{
  public function presist($entity)
  {
    if ($entity instanceof ValidatableInterface) {
      // validate object, throw specific exception if smth bad ($e->getAllErrors(), $e->getErrors($field))
    }

    return parent::presist($entity);
  }
}
getValidator() возвращает минимальный набор правил, которые обязательны при любых случаях, дабы не покорежить логику в базе. Кроме того, валидатор может запоминать состояние объекта:

PHP:
// controller
ValidatorFactory::get($entity, 'admin')->validate($entity); // получили набор специфичных для админа прав, провели валидацию. Когда будем делать presist($entity) - валидация не будет вызвана повторно, так как состояние объекта не изменилось
грубо? И тут как-то я упустил момент разных валидаций для insert/update/delete
 
Сверху