Поддержать Проект

USDT TRC20

TBGKTYDs4yzU17vQbobbUB8epFFtFb6PKh

Обратная связь

[MODX] Guru
  • Информация
  • Разработчикам
  • Дополнения
    • DocLister
    • DLMenu
    • DLCrumbs
    • DLBuildMenu
    • DLLastViews
    • DLSiblings
    • DLRequest
    • DLglossary
    • DLSitemap
    • DocInfo
    • FormLister
      • Контроллеры
      • Параметры
      • Валидация данных
      • Использование капчи
      • Вывод данных
      • Отправка писем
      • Авторизация пользователей
      • Регистрация пользователей
      • Активация учетных записей
      • Редактирование профиля пользователя
      • Удаление профиля пользователя
      • Восстановление паролей пользователями
      • Создание и редактирование документов пользователями
      • Удаление документов пользователями
      • Лексиконы
      • Примеры
      • Использование prepare
      • Сохраняем UTM в сессию
    • Wayfinder
    • phpthumb
    • LikeDislike
    • eForm
    • Ditto
    • multiTV
    • AjaxMegaSearch
    • AjaxSearch
    • WebLoginPE
    • Breadcrumbs
    • CodeMirror
    • AnythingRating
    • Easy Newsletter
    • FirstChildRedirect
    • OpenGraphTags
    • ddTypograph
    • TagSaver
    • BlackList
    • CfgTv
    • ModxAccount
    • Forgot Manager Login
    • GetField
    • if
    • Jot
    • ListChild
    • ListIndexer
    • ManagerManager
    • ddMMEditor
    • MaxiGallery
    • MemberCheck
    • ddGetMultipleField
    • MetaX
    • MODxBB и phpBB
    • Yams
    • Personalize
    • PHx
    • Reflect
    • tagLinks
    • TransAlias
    • TvTagCloud
    • UltimateParent
    • WebSignup
    • WebLogin
    • countViews
    • thumb
    • imageCaptor
    • optimizeJPG
    • Preview Next
    • Shopkeeper
    • SiteMap
    • Sass
    • Selector
    • SimpleGallery
    • SimpleTube
    • SimpleFiles
    • Star Rating
    • MinifyX
    • adminNav
    • SimplePolls
    • CResource
    • MODxAPI
    • customTables
    • HtmlInLine
    • HtmlMinModxEvo
    • SHKUserProfile
    • PickDocsInTree
    • evoSearch
    • editDocs
    • PageBuilder
    • HybridAuth
    • Compare
    • alterTitle
  • Виджеты
  • Уроки
  • Разработчики
  • Готовые примеры
  • Блог
  • Конфиги
  • HTML коды
© [MODX] Guru
  • FormLister

Использование prepare-сниппетов в FormLister

  • Дополнения
  • FormLister
  • Использование prepare
Поддержать: USDT TRC20: TBGKTYDs4yzU17vQbobbUB8epFFtFb6PKh
2781

Использование prepare-сниппетов в FormLister

Рассматривать буду на примере формы для регистрации пользователей.

  • загрузка фото при регистрации;
  • выбор страны из списка;
  • задание даты рождения пользователя.

Сразу привожу итоговый вызов сниппета:

[!FormLister?
&formid=`register`
&controller=`Register`
&defaults=`{"photo":""}`
&keepDefaults=`photo`
&rules=`{
	"fullname":{
		"required":"Обязательно введите имя"
	},
	"email":{
		"required":"Обязательно введите email",
		"email":"Введите email правильно",
		"custom":{
			"function":"\\FormLister\\Register::uniqueEmail",
			"message":"Этот email уже использует другой пользователь"
		}
	},
	"password":{
		"required":"Обязательно введите пароль",
		"minLength":{
			"params":6,
			"message":"В пароле должно быть больше 6 символов"
		}
	},
	"repeatPassword":{
		"required":"Повторите пароль",
		"equals":{
			"message":"Пароли не совпадают"
		}
	},
	"birthday":{
		"date":{
			"params":"d.m.Y",
			"message":"Введите дату правильно"
		}
	},
	"agree":{
		"required":"Для регистрации вы должны принять правила"
	}
}`
&attachments=`userpic`
&fileRules=`{
	"userpic":{
		"optional":"Не удалось загрузить файл",
		"maxSize" : {
			"params": 1024,
			"message": "Размер файла не должен превышать 1 мб"
		},
		"images": "Разрешены только картинки"
	}
}`
&allowedFields=`email,password,username,fullname,country,photo,dob`
&formControls=`agree`
&prepare=`countryList`
&prepareProcess=`userPhoto,userDob`
&formTpl=`@CODE:
<div class="row">
    <div class="col-md-6 col-md-offset-3">
        <div class="well">
            <form method="post" enctype="multipart/form-data">
                <input type="hidden" name="formid" value="register">
                <div class="form-group[<!---->+fullname.errorClass+][<!---->+fullname.requiredClass+]">
                    <label for="fullname">* Имя</label>
                    <input type="text" class="form-control" id="fullname" placeholder="Имя" name="fullname" value="[<!---->+fullname.value+]">
                    [<!---->+fullname.error+]
                </div>
                <div class="form-group[<!---->+email.errorClass+][<!---->+email.requiredClass+]">
                    <label for="email">* Email</label>
                    <input type="text" class="form-control" id="email" placeholder="Email" name="email" value="[<!---->+email.value+]">
                    [<!---->+email.error+]
                </div>
                <div class="form-group[<!---->+birthday.errorClass+]">
                    <label for="birthday">Дата рождения (дд.мм.гггг)</label>
                    <input type="text" class="form-control" id="birthday" placeholder="Дата рождения" name="birthday" value="[<!---->+birthday.value+]">
                    [<!---->+birthday.error+]
                </div>
                <div class="form-group">
                    <label for="country">* Cтрана</label>
                    <select name="country" class="form-control">[<!---->+countryList+]</select>
                </div>
                <div class="form-group[<!---->+userpic.errorClass+]">
                    <label for="userphoto">Картинка</label>
                    <input class="form-control" type="file" name="userpic">
                    [<!---->+userpic.error+]
                </div>
                <div class="row">
                    <div class="col-md-6">
                        <div class="form-group[<!---->+password.errorClass+][<!---->+password.requiredClass+]">
                            <label for="password">* Пароль</label>
                            <input type="password" class="form-control" id="password" placeholder="Пароль" name="password" value="">
                            [<!---->+password.error+]
                        </div>
                    </div>
                    <div class="col-md-6">
                        <div class="form-group[<!---->+repeatPassword.errorClass+][<!---->+repeatPassword.requiredClass+]">
                            <label for="repeatPassword">* Повторите пароль</label>
                            <input type="password" class="form-control" id="repeatPassword" placeholder="Повторите пароль" name="repeatPassword" value="">
                            [<!---->+repeatPassword.error+]
                        </div>
                    </div>
                </div>
                <div class="checkbox[<!---->+agree.requiredClass+]">
                    <label>
                        <input type="checkbox" name="agree" value="Да" [<!---->+c.agree.Да+]>Я согласен с правилами
                    </label>
                    [<!---->+agree.error+]
                </div>
                [<!---->+form.messages+]
                <div class="form-group">
                    <button type="submit" class="btn btn-primary btn-block text-center"><i class="glyphicon glyphicon-user"></i> Зарегистрироваться</button>
                </div>
            </form>
        </div>
    </div>
</div>`
&messagesOuterTpl=`@CODE:<div class="alert alert-danger" role="alert">[+messages+]</div>`
&successTpl=`@CODE:<div>Поздравляем с успешной регистрацией, [+fullname.value+]! Теперь вы можете <a href="[~11~]">авторизоваться</a> на сайте.</div>`
&errorTpl=`@CODE:<span class="help-block">[+message+]</span>`
&errorClass=` has-error`
&requiredClass=` has-warning`
!]

возникло затруднение с параметром . В параметре allowedFields указаны поля, которые в данном случае разрешены к использованию для регистрации пользователя. Если параметр не задавать, то все поля отправятся в модель modUsers как есть. Мне кажется, что правильнее ограничивать набор полей, но тут уже вам решать.

По этой же причине заданы параметры defaults и keepDefaults, чтобы пользователь не мог самостоятельно подставить в форму поле photo. В defaults задается пустое значение этого поля, а keepDefaults не даст перезаписать это поле значением из GET или POST.



Теперь по порядку.

Загрузка фото

Сама по себе задача, как мне кажется, не требует решения вообще, потому что зачем заставлять пользователя загружать фото при регистрации? Я бы делал такое в редактировании профиля, это было бы удобнее и мне, как разработчику, и пользователю. Но пусть будет фото при регистрации.

В общем случае задача сводится к тому, чтобы загрузить файл, обязательно проверить, загрузил ли пользователь именно то, что надо, затем сохранить файл куда-то и задать в поле photo путь к файлу перед тем как отправить данные в модель modUsers. Сделать в форме поле input type=«file» name=«photo» не прокатит — если не понятно почему, то дальше можно не читать.

Загрузка файлов и валидация в FormLister есть, загружать будем в поле с именем userpic. Остается только решить вопрос с сохранением файла в нужное место и заданием поля photo. Для этого понадобится написать сниппет userPhoto:

<?php
//получаем массив с загруженными файлами
$files = $FormLister->getFormData('files');
//проверяем, есть ли там нужный файл и загружен ли он успешно
if (isset($files['userpic']) && $files['userpic']['error'] === 0) {
//задаем папку для хранения пользовательских фото	
$dir = 'assets/images/userphoto/';
//получаем имя загруженного файла, без расширения
$filename = $FormLister->fs->takeFileName($files['userpic']['name']);
//расширение отдельно
$ext = $FormLister->fs->takeFileExt($files['userpic']['name']);
//делаем транслитерацию имени файла, добавляем к нему расширение
$filename = $modx->stripAlias($filename).'.'.$ext;
//получаем предполагаемый путь к файлу, при необходимости переименовываем, чтобы не затереть файл с таким же именем
$filename = $FormLister->fs->getInexistantFilename($dir.$filename,true);
//пытаемся переместить файл в нужное место
if ($FormLister->fs->makeDir($dir) && move_uploaded_file($files['userpic']['tmp_name'],$filename)) {
    //если получилось, то сохраняем в поле photo относительный путь к файлу
    $FormLister->setField('photo',$FormLister->fs->relativePath($filename));
}
}

Добавляем имя сниппета в параметр prepareProcess. Указанные в этом параметре сниппеты выполнятся после успешной валидации, а до этого момента нет смысла сохранять загруженные файлы.

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

Список стран

Очевидный поклонникам Ditto способ вписать в select все нужные страны вполне себе годный, если нужно иметь дело с двумя-тремя странами. Если стран много, то придется написать еще один сниппет, countryList:

<?php
$file = MODX_MANAGER_PATH."/includes/lang/country/{$FormLister->getCFGDef('countryLang','russian-UTF8')}_country.inc.php";
if (!file_exists($file) || !is_readable($file)) $file = MODX_BASE_PATH.MGR_DIR."/includes/lang/country/russian-UTF8_country.inc.php";
$out = '';
include($file);
foreach ($_country_lang as $key => $value) {
$out .= '<option value="'.$key.'"'.($FormLister->getField('country') == $key ? ' selected' : '').'>'.$value.'</option>';		
};
$FormLister->setPlaceholder('countryList',$out);
?>

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

Может возникнуть вопрос, почему поле задается через $FormLister->setPlaceholder('countryList',$out) вместо $FormLister->setField('countryList',$out). На самом деле можно и так, внешне работать будет одинаково. Разница лишь в том, что заданное через setPlaceholder поле можно использовать только для вывода в шаблоне, передать его в модель уже не получится.

Сниппет указывается в параметре prepare — список стран нам нужен сразу.


Дата рождения

Дата рождения пользователя хранится в таблице в поле dob как timestamp. Вряд ли найдутся пользователи, которые захотят вводить дату в таком виде, поэтому в форме мы используем поле birthday, в которое будем вводить дату в понятном виде, а затем из этой даты создадим значение для поля dob.

Для этого понадобится сниппет userDob:

<?php
$date = $data['birthday'];
$date = $date ? \DateTime::createFromFormat('d.m.Y',$date)->getTimestamp() : 0;
$FormLister->setField('dob',$date);
?>

Добавляем сниппет в параметр prepareProcess и задача решена. Обратите внимание на то, как задано правило для валидации даты: !birthday означает, что пользователь может не указывать дату, тогда и поле dob не будет установлено.

Почему я не стал вводить ограничения, как с полем photo — смысла в этом нет, так как ограничение уже введено правилом валидации, так что в поле dob попадет корректное значение.

Заключение

Таким образом, prepare-сниппеты можно вызывать до валидации данных в форме и после.

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

Так как в качестве prepare-сниппетов можно использовать статические методы класса, то можно написать такой класс для типовых решений и тягать его из проекта в проект.

Для каких-то масштабных задач prepare-сниппеты не годятся и лучше не городить огород, а создать отдельный контроллер.