Чем больше пишу про cogear², тем больше хочется про него рассказывать и творить дальше. Вошел во вкус. Итак, мы подобрались к заветному моменту любого движка — работе с формами. Ведь достаточно большую часть времени мы проводим именно вводя информацию на сайте. Чаще всего набирая коммент, конечно. И тем ценнее они для нас.
Мы помним, что первый cogear явил миру достаточно интересный метод работы с формами. Как и везде, здесь в ход идет системный анализ, обобщение, стандартизация. Во второй версии мы добились желаемых целей. Равно как и другие жизненно важные ключевые звенья cogear² шестеренка Form блещет своей ООП-реализацией. Теперь классами описывается все — форма, ее элементы, валидаторы и фильтры.
Устроим экскурс во внутренне устройство нашего Form API.
Как же создать форму? Для удобства хранения информации здесь мы отошли от явного наращивания дерева объектов. Как и конфиги формы хранятся в массивах.
Вы можете сохранить массив с формой в файл или же скормить его напрямую в виде параметра в конструктор объекта формы.
Случай первый. Форма из файла.
Рассмотрим шестеренку User.В корне шестеренки мы найдем папку forms, а в ней файл profile.php со следующим содержимым:
<?php
return array(
'name' => 'user-profile',
// другие параметры формы типа action, enctype
// если не укажете — будут использованы значения класса Form_Object по-умолчанию
…
'elements' => array(
'personal' => array(
'label' => t('Personal','User'),
'type' => 'tab',
),
'avatar' => array(
'label' => t('Avatar', 'User'),
'type' => 'image',
'preset' => 'avatar.photo',
'path' => UPLOADS . DS . 'avatars' . DS . cogear()->user->id,
//'rename' => cogear()->user->id,
),
'realname' => array(
'label' => t('Real name','User'),
'type' => 'text',
'access' => access('user_edit_realname'),
'validators' => array(array('Length',5),'Name'),
),
'login' => array(
'label' => t('Login', 'User'),
'type' => 'text',
'access' => access('user edit_login'),
'validators' => array(array('Length', 3), 'AlphaNum', 'Required', array('User_Validate_Login', User_Validate_Login::EXCLUDE_SELF)),
),
'email' => array(
'label' => t('E-Mail', 'User'),
'type' => 'text',
'validators' => array('Email', 'Required', array('User_Validate_Email', User_Validate_Email::EXCLUDE_SELF)),
),
'password' => array(
'label' => t('Password', 'User'),
'type' => 'password',
'validators' => array(array('Length', 3), 'AlphaNum')
),
// 'role' => array(
// 'label' => t('Role','User'),
// 'type' => 'select',
// 'validators' => array('Required'),
// 'callback' => 'User_Gear->getRoles',
// ),
// 'options' => array(
// 'label' => t('Test','User'),
// 'type' => 'checkbox',
// ),
'submit' => array(
'type' => 'submit',
'label' => t('Update'),
),
'delete' => array(
'type' => 'submit',
'label' => t('Delete'),
'access' => access('users delete_all'),
)
)
);
Кажется, что код настолько простой, что и пояснять нечего. Если вопросы есть, пишите в комменты.
И такую форму мы вызываем следующим образом:
$form = new Form('User.profile');
Случай второй. Форма из массива.
Обратим внимание на шестеренку Comments, которую я начал писать сегодня.$form = new Form(array(
'name' => 'addComment',
'elements' => array(
'info' => array(
'type' => 'div',
'value' => t('Leave comment ').' '.$this->user->getAvatarLinked().' '.$this->user->getLink().' ↓ ',
),
'body' => array(
'type' => 'textarea',
'validators' => array('Required', array('Length', 5)),
'filters' => array(array('strip_tags', '<b><i><u>')),
),
'submit' => array(
'type' => 'submit',
'label' => t('Post'),
),
)
));
Собственно, разницы никакой, кроме того, что форму из файла можно использовать в разных местах, в то время, как форма из массива используется только в конкретный момент.Обработка данных
Надеюсь, что еще с первым cogear вы забыли о той рутине, которая обычно связана с обработкой результатов отправки формы. Если еще не до конца, то с cogear² точно забудете.Проще не придумаешь. Смотрите сами.
if ($result = $form->result()) {
$comment = new Comments_Object();
$comment->pid = $Page->id;
$comment->aid = $this->user->id;
$comment->created_date = time();
$comment->body = $result->body;
$comment->ip = $this->session->ip;
if ($comment->save()) {
$Page->comments = $this->db->where('pid',$Page->id)->count('comments');
$Page->save();
flash_success(t('Your comment has been successfully posted!'));
redirect($Page->getUrl());
}
}
$form->show(); Опять-таки, если вопросы есть — комментируйте.
Вернемся же в шестеренку User и поглядим на более сложный процесс обработки данных.
$user = new User_Object();
$user->where('id', $id);
$user->find();
$form = new Form('User.profile');
$user->password = '';
$form->object($user->object());
if ($form->elements->avatar->is_ajaxed && Ajax::get('action') == 'replace') {
$user->avatar = '';
$user->update();
}
if ($result = $form->result()) {
if ($user->login != $result['login']) {
$redirect = Url::gear('user') . $result['login'];
}
if ($result->delete && access('users delete_all')) {
$user->delete();
flash_success(t('User <b>%s</b> was deleted!'));
redirect(Url::link('/users'));
}
$user->merge($result);
if ($result->password) {
$user->hashPassword();
} else {
unset($user->password);
}
if ($user->update()) {
d('User edit');
flash_success(t('User data saved!'), t('Success'));
d();
if ($user->id == $this->id) {
$this->store($user->object()->toArray());
}
redirect(Url::gear('user') . $user->login);
}
}
append('content', $form->render());
Обратим свое внимание на полезный метод:
$form->object($user->object());
Он не просто выставляет данные элементам формы, но еще и хранит ссылку на объект. Очень удобно для хуков.Также при помощи джедайского аякса мы можем творить чудеса:
if ($form->elements->avatar->is_ajaxed && Ajax::get('action') == 'replace') {
$user->avatar = '';
$user->update();
}
О таких тонкостях будет отдельный материал.Если мы, как админ, редактируем чужой профиль:
if ($user->login != $result['login']) {
$redirect = Url::gear('user') . $result['login'];
}
Если была нажата кнопка «Удалить»:
if ($result->delete && access('users delete_all')) {
$user->delete();
flash_success(t('User <b>%s</b> was deleted!'));
redirect(Url::link('/users'));
}
Объединяем полученные из формы данные с уже существующим объектом пользователя:
$user->merge($result);
if ($result->password) {
$user->hashPassword();
} else {
unset($user->password);
}
Сохраняем результат:
if ($user->update()) {
d('User edit');
flash_success(t('User data saved!'), t('Success'));
d();
if ($user->id == $this->id) {
$this->save($user->object()->toArray());
}
redirect(Url::gear('user') . $user->login);
}
И в конце, если не ушли по редиректу, показываем форму.append('content', $form->render());
Последняя запись эквивалентна$form->show();
Просто данный конкретный кусок кода был создан еще до столь удобных наработок.Все остальные тонкости вы сможете изучить сами в процессе работы. Настоятельно рекомендую вам просто погулять по репозиторию, читая код.
P.S. Завтра презентую бета-версию. Скорее всего сделаю видео-ролик, где расскажу обо всех тонкостях.


Чтобы добавить доп.поле, надо просто хукнуть форму.
Вот как это сделано в шестеренке Loginza:
hook('form.user-profile.init', array($this, 'hookUserProfile')); … /** * Hooking user profile form * * @param object $Form */ public function hookUserProfile($Form) { $data['social'] = array( 'type' => 'tab', 'label' => t('Social') ); $data['social_info'] = array( 'type' => 'div', 'value' => t('<p>There you can attach social accounts to integrate with your profile. It will help you for quick login.</p>'), ); if ($connected_accounts = $this->db->where('uid', $Form->object->id)->get('users_loginza')->result()) { $tpl = new Template('Loginza.accounts'); $tpl->accounts = $connected_accounts; $data['loginza_accounts'] = array( 'type' => 'div', 'value' => $tpl->render(), ); } js('http://loginza.ru/js/widget.js'); $data['loginza'] = array( 'type' => 'div', 'value' => HTML::a($this->api->getWidgetUrl(Url::link() . 'loginza'), HTML::img($this->folder . '/img/sign_in_button_gray.gif', t('Log in via social services', 'Loginza')), array('class' => 'loginza')), ); $Form->elements->place($data, 'submit', Form::BEFORE); }ЗЫ
С нетерпением жду статью про джедайский аякс
Чем больше читаю то, что пишет Дима, тем больше хочется взять Cogear2 и начать с ним работать.
встречатьсязаглядывать на сайт бета-версии ;-)Если пользователь не захочет например создавать подпапки и лить всё в 1 и зальет тысяч 10 тормозить не будет?
Извиняюсь если достал со всем этим, просто хочется что бы были продуманы все моменты.
А во сколько?
Сейчас, еще пару штук допилю, и иду делать видео.
Пойду помоюсь и подстригу ногти, сегодня будет ночь танцующих кинжалов — сегодня буду пробовать Cogear2.
Так что, о великий одминэ, поспать тебе не получится ;)