Большинство операций вам уже должны быть знакомы, поэтому здесь будет минимальное количество комментарий.
Создадим класс ProfileController и добавим в него действие register.
Файл shop/src/controller/ProfileController.class.php:
<?php lmb_require('src/model/User.class.php'); class ProfileController extends lmbController { function doRegister() { $this->useForm('register_form'); $this->setFormDatasource($this->request); if($this->request->hasPost()) { $this->_validatePasswordField(); $user = new User(); $user->setLogin($login = $this->request->get('login')); $user->setEmail($this->request->get('email')); $user->setName($this->request->get('name')); $user->setPassword($password = $this->request->get('password')); $user->setAddress($this->request->get('address')); $user->setIsAdmin(false); if($user->trySave($this->error_list) && $this->error_list->isValid()) { $this->toolkit->getUser()->login($login, $password); $this->toolkit->getSession()->set('user_id', $user->getId()); $this->flashMessage('Thank you for your registration!'); $this->toolkit->redirect('/'); } } } function _validatePasswordField() { $this->validator->addRequiredRule('password'); $this->validator->addRequiredRule('repeat_password'); lmb_require('limb/validation/src/rule/lmbMatchRule.class.php'); $this->validator->addRule(new lmbMatchRule('password', 'repeat_password')); $this->validator->validate($this->request); } } ?>
После регистрации пользователь уже считается прошедшим процедуру аутентификации, и мы перебрасываем его на главную страницу при помощи метода redirect(), а также выводим ему сообщение об успешной регистрации при помощи метода flashMessage().
Код должен быть вам знаком по контроллерам LoginController и AdminUserController.
Обратите внимание на проверку
if($user->trySave($this->error_list) && $this->error_list->isValid()) { [...] }
Мы должны обязательно проверить, нет ли ошибок в списке ошибок, так как процесс валидации данных разбит на 2 составляющие - одна из которых производится в контроллере в методе _validatePasswordField(), а вторая - в классе User.
Аналогом метода $error_list→isValid() может выступат просто $error_list→isEmpty().
Теперь можно будет создать шаблон для действия register.
Файл shop/template/profile/register.html:
<core:set title='Registration'/> <core:wrap file="page.html" in="content"> <form id='register_form' name='register_form' method='post' runat='server'> <core:include file='form_errors.html'/> <div class="field"> <label for="login" errorclass='error'>Login<span class='req'>*</span>:</label> <input name="login" id='login' type="text" title="Login" class='input'/> </div> <div class="field"> <label for="name" errorclass='error'>Name<span class='req'>*</span>:</label> <input name="name" id='name' type="text" title="Name" class='input'/> </div> <div class="field"> <label for="email" errorclass='error'>Email<span class='req'>*</span>:</label> <input name="email" id='email' type="text" title="Email" class='input'/> </div> <div class="field"> <label for="password" errorclass='error'>Password<span class='req'>*</span>:</label> <input name="password" id='password' type="password" title="Password" class='input'/> </div> <div class="field"> <label for="repeat_password" errorclass='error'>Repeat password<span class='req'>*</span>:</label> <input name="repeat_password" id="repeat_password" type="password" title="Repeat password" class='input'/> </div> <div class="field"> <label for="address" errorclass='error'>Delivery address:</label> <textarea name="address" id='address' type="text" title="Delivery address" size='40' class='textarea'></textarea> </div> <div class="hr"></div> <input id='register' type='submit' value='Register' runat='client'/> </form> </core:wrap>
Здесь мы использовали одну интересную особенность WACT-тегов для форм. Они позволяют указать атрибутом errorclass название CSS-класса, который будет применен к ним, если поля содержат ошибки валидации. Мы решили назвать этот класс error.
Попробуйте зайти на страницу /profile/register. Наша форма регистрации c ошибками валидации будет выглядеть следующим образом:
Теперь можно внести в paget.html изменения, связанные с отображением данных текущего пользователя. Данные пользователя нам уже доступны в шаблоне в виде переменной user корневого контейнера данных (мы это реализовали в AccessFilter).
Изменения в файле shop/template/page.html:
[..] <div id="sidebar"> <div id="navigation"> <ul> <li><a href="/product">Products</a></li> <li><a href="/cart">Your Cart</a></li> <core:optional for='#user.is_logged_in'> <li><route_url params='controller:profile,action:orders'>Your Orders</route_url></li> </core:optional> </ul> </div> <core:datasource from='#user'> <dl id="profile"> <dt>Profile</dt> <core:optional for='is_logged_in'> <dd> User: {$name}<br/> Login: {$login}<br/> Email: {$email}<br/> <route_url params='controller:profile'>edit</route_url> <route_url params='controller:login,action:logout'>logout</route_url> </dd> </core:optional> <core:default for='is_logged_in'> <dd> <form method="POST" id='login_form' runat='server' action='/login'> <label for='login'>Login:</label><br/> <input type="text" name="login" id="login" title="Login" class='input'/><br/> <label for='passwd'>Password:</label><br/> <input type="text" name="password" id="password" type="password" title="Password" class='input'/><br/> <input type='submit' name='submitted' value="Submit"/><br/> </form> <route_url params='controller:profile,action:register'>Register</route_url> </dd> </core:default> </dl> </core:datasource> </div> [...]
Мы решили отображать форму для аутентификации в левой части страницы, если пользователь не залогинен. Плюс добавился пункт навигации Your Orders, к реализации которого мы скоро также приступим.
Пользователь должен иметь возможность сменить свой пароль, а также поменять свои контактные данные (например, email) при необходимости. Для этого мы реализуем действие display, которое будет в себя включать весь нужный функционал.
Начнем, пожалуй, с шаблона:
Файл shop/template/profile/display.html:
<core:set title='Your profile'/> <core:wrap file="page.html" in="content"> This is your profile page. You can change some of your profile fields as well as your password<br/> <h2>Profile</h2> <form id='profile_form' name='profile_form' method='post' runat='server'> <core:include file='form_errors.html'/> <label for="name" errorclass='error'>Name:</label><br/> <input name="name" id='name' type="text" title="Name" class='input'/><br/> <label for="email" errorclass='error'>Email:</label><br/> <input name="email" id='email' type="text" title="Email" class='input'/> <br/> <label for="address" errorclass='error'>Delivery address:</label><br/> <textarea name="address" id='address' type="text" title="Delivery address" cols='40' rows='5' class='input'></textarea> <br/> <input id='edit' name='edit' type='submit' value='Update profile' runat='client'/> </form> <h2>Password change form</h2> <form id='change_password_form' name='change_password_form' method='post' runat='server'> <core:include file='form_errors.html'/> <label for="old_password" errorclass='error'>Old Password:</label><br/> <input name="old_password" id='old_password' type="password" title="Old Password" class='input'/><br/> <label for="password" errorclass='error'>Password:</label><br/> <input name="password" id='password' type="password" title="Password" class='input'/><br/> <label for="repeat_password" errorclass='error'>Repeat password:</label><br/> <input name="repeat_password" id="repeat_password" type="password" title="Repeat password" class='input'/><br/> <input id='change_password' name='change_password' type='submit' value='Change password' runat='client'/> </form> </core:wrap>
Шаблон содержит 2 формы:
Теперь мы покажем, как можно обрабатывать 2 формы при помощи одного действия в контроллере.
<?php lmb_require('src/model/User.class.php'); class ProfileController extends lmbController { function doDisplay() { $this->setFormDatasource($this->toolkit->getUser(), 'profile_form'); if($this->request->hasAttribute('change_password')) $this->_changeUserPassword(); if($this->request->hasAttribute('edit')) $this->_updateUserProfile(); } protected function _changeUserPassword() { $this->useForm('change_password_form'); $this->_validateChangePasswordForm(); if($this->error_list->isValid()) { $user = $this->toolkit->getUser(); $user->setPassword($this->request->get('password')); $user->save(); $this->flashMessage('Your password was changed'); $this->toolkit->redirect(); } } protected function _updateUserProfile() { $this->useForm('profile_form'); $this->setFormDatasource($this->toolkit->getUser()); $user = $this->toolkit->getUser(); $user->setEmail($this->request->get('email')); $user->setName($this->request->get('name')); $user->setAddress($this->request->get('address')); if($user->trySave($this->error_list)) { $this->flashMessage('Your profile was changed'); $this->toolkit->redirect(); } } protected function _validateChangePasswordForm() { $this->validator->addRequiredRule('old_password'); $this->_validatePasswordField(); $user = $this->toolkit->getUser(); if($old_password = $this->request->get('old_password')) { $hashed_password = User :: cryptPassword($old_password); if($user->getHashedPassword() != $hashed_password) $this->error_list->addError('Wrong old password', array('old_password')); } } } ?>
Выбор той или иной функции по обработке формы по смене пароля или же по обновлению данных пользователя осуществляется очень просто - исходя из того, какая переменная пришла в request-е.
Мы также сразу передаем текущего пользователя в форму в шаблоне, так как желаем, чтобы эти данные всегда отображались в полях формы все зависимости от того, какая форма была до этого отправлена. Примем мы использовали только метод lmbController :: setFormDatasource($datasource, $form_id):
$this->setFormDatasource($this->toolkit->getUser(), 'profile_form');
Это позволит не выводить ошибки валидации сразу рядом с двумя формами, если пользователь неправильно ввел информацию в форму по смене пароля.
Теперь можно приступать к интересной части: оформлению заказа и сохранению его в базе данных. Этот функционал позволит нам познакомиться к тем, как в пакете ACTIVE_RECORD реализована поддержка отношений между объктами, таких как один-ко-многим, много-ко-многим и один-к-одному.
Итак, следующий шаг: Шаг8. Отправка заказа.
Обсуждение