MVC и валидация

WMix

герр M:)ller
Партнер клуба
Если getById делает return $this, то ога. :)
если вдуматься, то нет никакой разницы, или это нужно регулировать приватными сетерами, или твоя модель также поддается манипулированию, и с таким же успехом ктонить напишет foreach прям в контроллере
 

fixxxer

К.О.
Партнер клуба
сдуру можно и *** сломать =)

можно вообще в контроллере mysql_connect('localhost', 'username', '8oihlkjh') написать, что ж поделать =)
 

WMix

герр M:)ller
Партнер клуба
поэтому то что было предложенно ничем не отличается
но очень хорошую идею получил, на счет валидаторов, спасибо, я обязательно попробую, а там отпишусь!
 

fixxxer

К.О.
Партнер клуба
Отличие исключительно в навязываемом стиле. Я считаю, что фреймворк должен быть устроен так, чтобы неправильный подход автоматически вызывал затруднения и было проще сделать правильно, чем думать, как обойти и воткнуть хак. :)

Понятно, что всегда найдется тот, кто сделает через задницу - но тут какбэ код, на фоне остального, оформленного совсем иначе, будет сразу заметен.

UPD: Но еще я тут не упомянул другой важный момент - то, как модель рендерится, может отличаться от того, что она о себе рассказывает наружу:) В принципе она может наружу и вообще ничего не рассказывать, кроме как "загрузилась да-нет" ;)
 

WMix

герр M:)ller
Партнер клуба
я понимаю о чем ты говоришь, смысл идеи я понял, я просто также понимаю как думают люди, все ищут входную точку, был проект, где ни представление ни контроллер программистом не затрагивался, хмлка генерила view и базовый класс модели, остальное было либо автоматизировано либо дописывалось на уровне модели (при хорошем ТЗ просто рай, работа переводчика), казалось бы,. еслиб ты видел как начинают писать такие методы не просвещенные, какие извраты кода они пишут, я пойму раньше уровень, поглядев на говнокодистый action и либо подскажу правильное решение либо....
 

vanicon

Новичок
В завершении данной темы, хочу поблагодарить всех участвовавших в ней, и привести пример кода метода регистрации:
PHP:
$form = new FormUser;
$form->setGroup('login','password','email','NameFamily','captcha');
$form->setData(Request::getPost());
if (!$form->isValid()) {
	return $form->getErrors();
}
$user = new User($form->getData());
if (!$user->save()) {
	return $user->getErrors();
}
return true;
Пока не найду варианта сделать это лучше оставлю так, есть какие-либо замечания или предложения по коду?
 

hell0w0rd

Продвинутый новичок
Очень похоже на нелогичный велосипед:)
Посмотрите как этот код выглядел бы в симфони, примерно также, но лучше)
То есть не ясно где тут рендрится форма на пример.
А самое главное - валидацию у вас проходит форма, а потом юзер может не сохраниться. Как так?
Должно быть как-то так:
$user = new User($form->getData());
if (!$user->isValid()) {}
А также у вас этот кусок кода возвращает массив/bool. Все и всегда матерятся на подобные функции в ядре php и сами также пишут:)
Если уж сами пишете фреймворк - придумайте объект, которым контроллеры будут отвечать:)
 

vanicon

Новичок
То есть не ясно где тут рендрится форма на пример.
В представление данные я пока не кидаю, но там все стандартно как у всех, поэтому просто ретурном вывел...
А самое главное - валидацию у вас проходит форма, а потом юзер может не сохраниться. Как так?
Хороший вопрос, дело все в том, что пользователь может и не записаться по причине обрыва соединения с бд и т.п
Ясное дело что в этом случае надо кидать исключение, но один фиг это исключение надо обработать в этом месте, что бы вывести сообщению пользователю рядом с формой, что типа извините что-то пошло не так попробуйте повторить операцию позже...
А также у вас этот кусок кода возвращает массив/bool. Все и всегда матерятся на подобные функции в ядре php и сами также пишут
Пока ничего не выводится в представление, поэтому сделал просто через ретурн...
 

fixxxer

К.О.
Партнер клуба
по причине обрыва соединения с бд и т.п
Да пусть себе летит наверх и рисуется заглушка на 500-ю. Если соединение с базой рвется каждый день, то вы решаете не ту проблему.

Я из контроллеров возвращаю специальный объект типа Result (а Result возвращает много кто - например, рендерер; и Result умеет displayTo(Response)).

Но есть шорткат return int (404 etc). Это то место, где я готов терпеть instanceof в родительском методе ради удобства.
 

vanicon

Новичок
А вот так если:
PHP:
$view = new View('register/form');
$form = new FormUser;
$form->setGroup('login','password','email','NameFamily','captcha');
$form->setData(Request::getPost());
if (!$form->isValid()) {
	$view->errors = $form->getErrors();
	return $view->show();
}
try {
	$user = new User($form->getData());
	$user->save();
}
catch (Exception $e){
	$view->errors[] = 'Что-то пошло не так, попробуйте зарегистрироваться позднее...';
}
if (!isset($view->errors)) {
	$view->message = 'Вы успешно зарегистрировалиь в системе...';
}
$view->show();
 

AmdY

Пью пиво
Команда форума
vanicon
setGroup должен устанавливать НАБОР правил, чтобы не перечислять каждое ручками.
$form->setGroup('user/register'); // здесь поля для регистрации и капча
или $form->setGroup('user/edit'); // здесь нету капчи, т.к. поля для зарегеного пользователя и поле email только для чтения.
 

hell0w0rd

Продвинутый новичок
Хватит писать велосипеды:) Посмотри как это красиво в симфони:
PHP:
public function addUser(HttpFoundation\Request $request)
{
    $form = $this->createForm(new Form\UserType(), new Entity\User());
    if( $request->isMethod('POST') && $form->bind($request)->isValid() ) {
        $user = $form->getData()->setAddDate();
        $em = $this->getDoctrine()->getManager();
        $em->persist($user);
        $em->flush();
        return $this->redirect($this->generateUrl('homepage'));
    }
    return $this->render('SiteUsersBundle:User:add.html.twig', array('form' => $form->createView()));
}
Еще бы портянку с $em сократили и было-бы вообще сказачно:)
 

vanicon

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

Может и действительно попробовать симфони или взять у нее пару идей, вообщем посмотрим как выше написанное будет "красиво"...
 

hell0w0rd

Продвинутый новичок
GusakovNick
Смотрю вы у нас любитель симфони, что же, может там действительно все красиво и супер будет, но я с ней незнаком, так что не сочтите за наглость, не могли бы вы дописать суда немного функционала, а именно:
Что если соединение с бд оборвется, или по каким то причинам пользователь не сможет записаться в бд, то наверное будет брошено исключение там где - то внутри доктрины, если такое вот произошло надо рядом с формой вывести сообщение, типа "Извините что- то пошло не так, попробуйте зарегаться позже.."
И еще один вопрос, где тут проходит валидация таких правил как "повтор пароля" (у меня ее нет, но все же хочется посмотреть) и капча.
И последние, что нужно будет писать заново в моменте изменения пользовательских данных (какой класс там еще прописывать и т.д)

Может и действительно попробовать симфони или взять у нее пару идей, вообщем посмотрим как выше написанное будет "красиво"...
Я бы не сказал что я прям любитель) Я месяц ее изучаю - и мне очень нравится. Для меня это сложно, но то что на выходе получается - стоит сложностей)
Если происходит обрыв соединения с БД - я честно сказать не знаю что произойдет, скорее всего какое-то исключение, по идее будет 500 ошибка. Если вы считаете что надо выдать пользователю сообщение "что-то пошло не так" - надо узнать что за исключение и поймать его) тут все примерно как у вас. Только что за фигня, когда коннект с бд обрывается? Также я не уверен, но предполагаю, что если он все таки оборвется - доктрина пару раз попробует его возобновить. Они везде пишут что доктрина достаточно умна чтобы делать некоторые вещи.
Вся валидация тут - $form->isValid(), при создании формы задаете ей валидатор.
http://symfony.com/doc/2.1/reference/forms/types/repeated.html - вот тип для повтора пароля.
Если нужно будет изменить модель пользователя - идете в описание вашей entity для него - это может быть в аннотациях, yml и xml. Там изменяете, обновляете класс юзера, форму, если это нужно, валидацию. А контроллер как был - так и остался.
Из плюшек твига стоит добавить, что форму можно отрисовать одной строчкой. А второй строчкой задать как отрисовывать. Вроде доступно два варианта - в дивах и таблицах.
PS чтобы понять подходит вам симфони или нет - просто прочитайте book по ней. Если английский напряжно - http://symfony-gu.ru/documentation/ru/html/index.html
 

WMix

герр M:)ller
Партнер клуба
vanicon
ты все правильно думаешь, твой код совсем не плох! я перекрутил слегка как я написал бы
PHP:
$view = new View('register/form');
$form = new FormUser;
$form->setGroup('login','password','email','NameFamily','captcha');
// if is post ??
$form->setData(Request::getPost()); 
if ($form->isValid()) {
  try {
      $user = new User($form->getData());
      $user->save();
  }
  catch (Exception $e){
    $view->errors[] = 'Что-то пошло не так, попробуйте зарегистрироваться позднее...';
  }
}
else{
    $view->errors = $form->getErrors();
}
$view->show();
 

vanicon

Новичок
GusakovNick
Вы меня не поняли, вот смотрите задача, которую нужно написать на симвони:
1. Есть некая сущность пользователя с полями, такими как логин, пароль, мыло, имя фамилия.
2. Нужен сценарий регистрации, но там кроме основных полей валидации (логин, мыло и т.п) есть такие поля "повтор пароля" и "капча".
3. Также есть сценарий изменения данных пользователя (изменения мыла, логина и т.п), там тока основные поля, никаких капч и т.п
Как на симфони вы реализуете это, и можно поподробнее какой класс и для чего..
Особенно интересно, где будет происходить валидация данных...
 

hell0w0rd

Продвинутый новичок
vanicon
1) Это вы описываете в моделях
У доктрины есть песочница, вот пример от туда:
PHP:
Entities\User:
  type: entity
  table: users
  id:
    id:
      type: integer
      generator:
        strategy: AUTO
  fields:
    name:
      type: string
      length: 50
  oneToOne:
    address:
      targetEntity: Address
      joinColumn:
        name: address_id
        referencedColumnName: id
Дальше для вас генерируетя класс с геттерами и сеттерами.
На основе этого класса можно сгенерировать класс для формы. Или самому написать, хотя проще уже дописывать.
2) Сценарии - контроллеры. Вы описываете роутинг и к ним прикручиваете контроллеры.
PHP:
register_user:
    pattern: /register
    defaults: { _controller: SiteUserBundle:Edit:register }
updating_user:
    pattern: /user/edit/{id}
    defaults: { _controller: SiteUserBundle:Edit:update }
    requirements:
        page:  \d+
Повтор чего либо - это в symfony forms можно сказать одно поле. На вход проверяется они одинаковы - или нет. Почитайте ссылку про повторение полей.
Капчу - я кидал бандл, который ее реализует, добавляет для нее валидатор, то есть уже все реализовано.

+ помимо всего прочего из любого места вашего приложения вы можете сгенерировать ссылку до каждого из контроллеров по его названию в роутинге (register_user и updating_user)
Это все можно долго рассказывать) Поставьте и попробуйте) Это дело 5 минут)
 

AmdY

Пью пиво
Команда форума
Форма в симфони и есть модель которая валидируется, у неё есть методанные и через них можно добавлять любой валитатор через $metadata->addPropertyConstraint('login', new NotBlank());
К форме можно прибиндить модель и тогда форма может взять часть валитаторов из этой модели плюс то, что ты опишешь ручками.
Поэтому формы симфонии можно юзать без доктрины и её моделей.

Процесс работы с формой примерно такой (это не симфони):
1. Создаём форму.
2. Биндим к ней модель.
3. Форма спрашивает у модели правила для валидации, но берёт лишь те, поля на которые есть в форме.
4. Добавляем правила вручную
5. Мержим правила ручные и правила отданные моделью, ручные правила важнее.
6. Форма проводит валидацию $form->isValid() и чуть что возвращает ошибки
7. Если вс ок, сохраняем модель с данными из формы, если произошла ошибка возвращаем их форме,
8. Если были ошибки форма выводит их.

Как сахар можно создавать кастомные наборы правил, типо для регистраци это поля с паролем и подтверждением плюс капча и тогда форме передаём их как группу $form->addGroup('registration') плюс прибиндженная модель и все привила навесились в две строки.
 

AmdY

Пью пиво
Команда форума
Теперь самое важное, так как для этого нужная умная модель, куча интерфесов и прочего ООП говна, то нафик надо, проще делать нашешивание тупо в контроллере. Люблю толстые контроллеры и делаю так $form->add('title', 'text', ['title' => 'Title'])->addValidator('Empty');
https://github.com/AmdY/phpkiss/blob/master/vendor/Bundle/News/C/Admin.php#L56
 

vanicon

Новичок
Можно в принципе делать как то так:
PHP:
//controller
$form = new FormRegister(Request::getPost());
if ($form->isValid()) {
	$user = new User($form->getData());
	$user->save(array('validate' => false));
}
else {
	$form->getErrors();
}
//form
class FormRegister extends Form {
	
	public $login;
	public $password;
	public $email;
	public $captcha;
	public $password2;
	
	public function rules()
	{
		return array(
			'login' => 'User.login',
			'password' => 'User.password',
			'email' => 'User.email',
			'captcha' => array(
				array('required'),
				array('captcha'),
			),
			'password2' => array(
				array('required'),
				array('repeat', 'password'),
			),
		);
	}
	
}
Но рисовать для этого класс, как то не хочется, поэтому мой вариант выше мне кажется более симпатичным...
 
Сверху