<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom">
<channel><generator>http://textpattern.com/?v=4.5.7</generator>
<title>IHHI-Blog</title>
<link>http://ihhi.ru/</link>
<atom:link href="http://ihhi.ru/rss/" rel="self" type="application/rss+xml" />
<description>Блоги - верная тема.</description>
<pubDate>Tue, 27 Dec 2016 00:39:14 GMT</pubDate>

<item><title>Оповещения Bootstrap в Laravel</title>
<content:encoded>
<![CDATA[<p>Если долго смотреть в админку сайта, то можно превратиться в блогера. Потекут из-под пальцев тексты глубокого смысла, слетятся на них почитатели таланта писательского и жизнь  станет совсем исключительной. Правда админку сначала нужно написать. А состоит она, как оказалось, из кучи второстепенных фишек, натыканных вокруг формы публикации. Лично я решил начать собирать эти фишки с алертов: сообщений, предупреждений и прочего интерактива. В используемом мной Bootstrap есть готовые их версии на <a href="http://getbootstrap.com/components/#alerts">чистом <span class="caps">CSS</span></a> и <a href="http://getbootstrap.com/javascript/#alerts">проскриптованные</a>. Совершил действие &#8211; получил реакцию. И главное &#8211; просто и без всякий выпрыгивающих модальных окон. Хотя и с ними тоже можно.</p>

	<p>Алерты и прочие оповещения совсем не рокет сайенс, но без них теряется связь с приложением и приходится только догадываться, что там произошло, записался ли файл, нет ли проблем с загрузкой фото и т.п. Вроде работает, но как-то некомфортно. Поэтому все фреймворки по фронтенду предлагают соответствующие сниппеты. И для получения полноценных оповещений остаётся лишь формировать информативные сообщения в контроллере и отображать их в представлении. А чтобы не париться по поводу программирования этой функциональности в каждом новом проекте, нужно подключать готовые пакеты и добавлять несколько строк в blade-шаблоны. А так же взять за правило формировать сами сообщения по факту производства активностей.</p>

	<p>С пакетами всё просто: можно написать свой или использовать чужой. Готовых пакетов для алертов много. Мне за последнее время попалась пара: <a href="https://github.com/vinkla/alert">vinkla/alert</a> и <a href="https://github.com/laracasts/flash">laracasts/flash</a>. Я начну свои эксперименты со второго пакета. Если не пойдёт или что-то не понравится, попробую первый. Если и с первым ничего не выйдет, то напишу свой. А скорее всего, я всё перепробую и напишу свой, но начну таки с laracasts/flash. И начало это, как принято в Laravel, состоит из команды</p>

	<p><pre class='brush: plain'>
composer require laracasts/flash
</pre></p>

	<p>которая пакет установит. После установки, по традиции, редактирую файл <strong>config/app.php</strong> и делаю две вставки</p>

	<p><pre class='brush: php'>
'providers' => [
     ...
    Laracasts\Flash\FlashServiceProvider::class,
];
'aliases' => [
    ...
    'Flash' => Laracasts\Flash\Flash::class,
];
</pre></p>

	<p>Практически всё. Теперь в шаблонах blade необходимо в нужном месте вставить одну строчку.</p>

	<p><pre class='brush: xml'>
@include('flash::message')
</pre></p>

	<p>Всё, можно применять. Для этого можно использовать фасад, алиас которого я прописал в файле конфигурации, либо функцию-хэлпер:</p>

	<p><pre class='brush: php'>
     // Хотим сообщить об ошибке с помощью фасада
     Flash::error('Что-то пошло не так!');
    // Используем хэлпер для сообщение об успехе
     flash()->success('Всё отлично получилось.');
</pre></p>

	<p>Доступно 5 видов сообщений:</p>

	<ul>
		<li>Flash::info(&#8216;Сообщение для вывода информации&#8217;)</li>
		<li>Flash::success(&#8216;Сообщение об успешном производстве действия&#8217;)</li>
		<li>Flash::error(&#8216;Сообщение об ошибке&#8217;)</li>
		<li>Flash::warning(&#8216;Предупреждение&#8217;)</li>
		<li>Flash::overlay(&#8216;Сообщение для вывода в модальном окне&#8217;, &#8216;Заголовок окна&#8217;)</li>
	</ul>

	<p>Текст сообщения и его тип в виде значений ключей <strong>flash_notification.message</strong> и <strong>flash_notification.level</strong> сохранятся в сессии и будут извлечены при создании страницы. Если вставка в шаблоне для этого пакета есть, то всё должно произойти само собой. Ручная обработка сообщений, что может потребоваться при использовании не Bootstrap, а чего-нибудь другого, производится довольно просто:</p>

	<p><pre class='brush: xml'>
@if (Session::has('flash_notification.message'))
    <div class="alert alert-{{ Session::get('flash_notification.level') }}">
        <button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>
         {{ Session::get('flash_notification.message') }}
    </div>
@endif
</pre></p>

	<p>Что на русский можно перевести как &#8220;Если есть сообщение в сессии, то будем его транслировать в соответствии с заданным уровнем тревожности&#8221;. Скобочки и буковки в этом коде расставить по вкусу в соответствии с используемыми инструментами. И лучше сохранить код в виде всё того же blade шаблона и вставлять его куда надо.</p>

	<p>Если для алертов используются модальные окна, то нужно после подключения библиотек jQuery.js и Bootstrap.js добавить такой скрипт:</p>

	<p><pre class='brush: js'>
<script>
    $('#flash-overlay-modal').modal();
</script>
</pre></p>

	<p>Вот кажется и всё. </p>]]>
</content:encoded>
<link>http://ihhi.ru/articles/220/opoveshcheniya-bootstrap-v-laravel</link>
<pubDate>Mon, 11 Apr 2016 00:56:13 GMT</pubDate>
<dc:creator>IHHI</dc:creator>
<guid isPermaLink="false">tag:ihhi.ru,2016-04-11:40e1955cceef8b96b347e053376f8ee2/7181bce18a1f1376270d340be6aeb210</guid>

<category>bootstrap</category>
<category>laravel</category>
</item>
<item><title>Аутентификация в Laravel</title>
<content:encoded>
<![CDATA[<p>Второй раз зайду в тему. Для меня действительно <a href="http://ihhi.ru/articles/218/sindrom-vakhtera-adminka">было шоком</a> осознание того, что админка и пароль на вход в закрытые зоны могут создаваться отдельно. Такой вот шаблон, отпечатавшийся в мозгах до уровня принятия формы извилины. Плохо, что тупил. Хорошо, что перестал. К паролям.</p>

	<p>У прекрасной тулзы &#8220;artisan&#8221; есть опция показа всех маршрутов роутера. Отличная штука. Я уже <a href="http://ihhi.ru/articles/217/poslat-po-adresu">писал</a>, что у меня в роутере всё очень скромно, ничего лишнего. И писал, что после выполнения </p>

	<p><pre class='brush: plain'>
./artisan make:auth
</pre></p>

	<p>происходит несколько трансформаций, после которых меняется и роутер.</p>

	<p><pre class='brush: php'>
&lt;?php
Route::group(['middleware' => ['web']], function () {
	Route::get('/{id?}', 'PagesController@show')->where('id', '\d+');
	Route::get('contacts', 'ContactsController@getContacts');
	Route::post('contacts', 'ContactsController@postContacts');
});
Route::group(['middleware' => 'web'], function () {
    Route::auth();
    Route::get('/home', 'HomeController@index');
});
</pre></p>

	<p>А теперь о магии: на рисунке ниже отчётливо видно две таблицы. Первая &#8211; это маршруты до изменения роутера, а вторая, соответственно &#8211; после. Состав не так важен. Важен размер. </p>

	<p><img src="http://ihhi.ru/images/122.jpg" alt="" width="650" height="250" /></p>

	<p>Добавилось 9 маршрутов, по названиям которых становится понятно, что помимо аутентификации и логаута у меня появились регистрация и сброс пароля. К сожалению эта конфигурация подходит только для демонстрации на лабораторной работе. Магия &#8211; это вообще опасная штука, а в случае с сайтом ещё и очень дорогая. Поэтому сейчас я буду приводить эту эльфийскую поделку в соответствие с реалиями окружающего мира.</p>

	<p>Самый лучший способ избежать взлома &#8211; сделать вид, что ломать нечего. На следующий день после установки своего одностраничинка я обнаружил попытку регистрации и аутентификации по адресам, которые обычно используются для этого в Laravel. Разумеется взломщики обломались. А произошло это потому, что я <del>гений</del> закомментировал добавленные в роутер строчки и главное &#8211; <strong>Route::auth()</strong>. Этот метод аналогичен добавлению таких строк:</p>

	<p><pre class='brush: php'>
&nbsp;
// Authentication Routes...
$this->get('login', 'Auth\AuthController@showLoginForm');
$this->post('login', 'Auth\AuthController@login');
$this->get('logout', 'Auth\AuthController@logout');
// Registration Routes...
$this->get('register', 'Auth\AuthController@showRegistrationForm');
$this->post('register', 'Auth\AuthController@register');
// Password Reset Routes...
$this->get('password/reset/{token?}', 'Auth\PasswordController@showResetForm');
$this->post('password/email', 'Auth\PasswordController@sendResetLinkEmail');
$this->post('password/reset', 'Auth\PasswordController@reset');
</pre></p>

	<p>Приятно, что маршруты не уводят в даль светлую, а заканчиваются готовыми для ввода данных шаблонами, со встроенными сообщения ошибок ввода. Реализация похожа на ту, что я показывал в публикации по <a href="http://ihhi.ru/articles/217/poslat-po-adresu">отправке email</a>. Точнее, у меня она сделана так же.</p>

	<p>Регистрация пользователя</p>

	<p><img src="http://ihhi.ru/images/123.jpg" alt="" width="650" height="415" /></p>

	<p>Аутентификации пользователя</p>

	<p><img src="http://ihhi.ru/images/124.jpg" alt="" width="650" height="344" /></p>

	<p>Сброс пароля</p>

	<p><img src="http://ihhi.ru/images/125.jpg" alt="" width="650" height="244" /></p>

	<p>Перед началом использования этих форм необходимо настроить базу данных и накатить стандартные миграции:</p>

	<p><pre class='brush: plain'>
./artisan migrate
</pre></p>

	<p>О миграциях и операциях с ними я <a href="http://ihhi.ru/articles/209/organizatsiya-bazy-dannykh-migratsii">уже писал</a>. Для начала работы с аутентификацией доработок не требуется и формы как раз рассчитаны на стандартные таблицы.</p>

	<p>Огромное спасибо за такой подгон, но лучше всё сделать самому, чтобы управлять ситуацией. Регистрацию, к примеру, в некоторые проекты не стоит добавлять. В свой проект с одним автором можно не добавлять маршруты сброса пароля и удовлетвориться простым выводом формы аутентификации и обеспечить процесс входа/выхода. Причём, изменив сам маршрут, заменив ключевое слово <strong>login</strong> на имя любимой кошки, добавив перед ним фамилию любимого актёра. Пусть перед подбором пароля адрес подберут, собаки.</p>

	<p>А быстрый тюнинг стандартной аутентификации я бы делал так:</p>

	<ol>
		<li>Установить чистый Laravel</li>
		<li>Установить скелет аутентификации ./artisan make:auth</li>
		<li>Настроить подключение к базе данных</li>
		<li>Накатить миграции ./artisan migrate</li>
		<li>Зайти по адресу http://yuoir.site/register и создать минимум одного пользователя</li>
	</ol>

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

	<p><pre class='brush: php'>
Route::group(['prefix' => 'myauth', 'middleware' => ['web'], 'namespace' => 'Auth'], function() {
    Route::get('login', 'AuthController@showLoginForm');
    Route::post('login', 'AuthController@login');
    Route::get('logout', 'AuthController@logout');
});
Route::group(['prefix' => 'figwamadminka', 'middleware' => ['web','auth'], 'namespace' => 'Admin'], function() {
    Route::get('/', 'AdminController@getDashboard');
});
</pre></p>

	<p>В первой строке сразу два интересных момента:</p>

	<ul>
		<li><strong>&#8216;prefix&#8217; =&gt; &#8216;myauth&#8217;</strong> &#8211; маршруты начинающиеся с <strong>myauth</strong></li>
		<li><strong>&#8216;namespace&#8217; =&gt; &#8216;Admin&#8217;</strong> &#8211; по умолчанию используют контроллеры из директории app/Http/Controllers/Auth</li>
	</ul>

	<p>Шестая строка добавляет интереса</p>

	<ul>
		<li><strong>&#8216;middleware&#8217; =&gt; [&#8216;auth&#8217;]</strong> &#8211; доступ только через аутентификацию</li>
	</ul>

	<p>И теперь для прохождения процесса аутентификации я должен идти по адресу http://mysite/myauth/login. Так же будет работать адрес /myauth/logout и всё. Регистрацию и сброс пароля я не заказывал. Нужно не забыть внести соответствующие правки в код blade шаблона. Разумеется префикс можно брать любой. Перед тестированием, чтобы не испытать чувство глубокого разочарование, нужно внести изменения в файлы <strong>app/Http/Controllers/Auth/AuthController.php</strong>,  и  <strong>app/Http/Middleware/Authenticate.php</strong>. В противном случае не будет находиться форма ввода логина/пароля при попытке неавторизованного доступа в закрытые обаласти, а после успешной аутентификации будет производиться переадресация в корень сайта.</p>

	<p><pre class='brush: php'>
&lt;?php namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Auth;
class Authenticate
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @param  string|null  $guard
     * @return mixed
     */
    public function handle($request, Closure $next, $guard = null)
    {
        if (Auth::guard($guard)->guest()) {
            if ($request->ajax() || $request->wantsJson()) {
                return response('Unauthorized.', 401);
            } else {
                return redirect()->guest('myauth/login');
            }
        }
        return $next($request);
    }
}
</pre></p>

	<p>и фрагмент AuthController.php</p>

	<p><pre class='brush: php'>
    /**
     * Where to redirect users after login / registration.
     *
     * @var string
     */
    protected $redirectTo = '/figwamadminka/dashboard';
</pre></p>

	<p>Теперь при попытке входа по адресу /figwamadminka/dashboard и при прямом вызове /myauth/login будет вызываться форма аутентификации. После ввода логина и пароля пользователь перенаправляется на /figwamadminka/dashboard, где его &#8220;должна ждать&#8221; заранее подготовленная главная страница админки. На время отладки можно задействовать полученный вместе с каркасом аутентификации HomeController, из которого следует удалить конструктор, т.к. он повторяет действия, &#8220;заказанные&#8221; в роутере. Всё. Пилите админку, малята. </p>]]>
</content:encoded>
<link>http://ihhi.ru/articles/219/autentifikatsiya-v-laravel</link>
<pubDate>Wed, 06 Apr 2016 01:15:50 GMT</pubDate>
<dc:creator>IHHI</dc:creator>
<guid isPermaLink="false">tag:ihhi.ru,2016-04-04:40e1955cceef8b96b347e053376f8ee2/0086ca7f8ef5397566c07679e375beb3</guid>

<category>laravel</category>
</item>
<item><title>Синдром вахтёра - админка</title>
<content:encoded>
<![CDATA[<p>Как я не оттягивал момент начала работы с админкой, но он таки наступил на меня всей своей неотвратимой массой. Это может показаться странным, но сразу после установки в Laravel админки нет. От слова совсем. Никакой. Это легко можно проверить, запустив <strong>artisan</strong> с параметром <strong>route:list</strong>. Нормально, да? На дворе весна, а ты тут сиди и придумывай админку. Думаю, что разработчики в этом направлении тоже идут, что подтверждают нововведения в версии 5.2, но пока почти всё приходится делать самому. </p>

	<p>Я уже писал, что практически сразу после установки Laravel версии 5.2 рекомендую установить каркас авторизации, для чего нужно выполнить команду</p>

	<p><pre class='brush: plain'>
./artisan make:auth
</pre></p>

	<p>В результате обновится <strong>router.php</strong>, добавится несколько blade шаблонов и добавится HomeController, демонстрирующий как бы авторизацию. Если честно, то все эти действия и даже &#8220;более лучшие&#8221; можно совершить самостоятельно, но для начала сойдёт. Особенно в качестве демонстрации имеющихся в Laravel механизмов авторизации и аутентификации. Однако, как я писал ранее, на улице давно весна и простые вещи типа логин/пароль уже не удовлетворяют нас. Пришло время авторизации с помощью аккаунтов социальных сетей. И опять потребуется минимальное хотя бы планирование приложения.</p>

	<p>Аутентификация пользователя &#8211; это, в терминах Laravel, определение свой-чужой: есть пользователь с введёнными данными в базе или нет. Есть &#8211; аутентификация прошла успешно. При этом данные для аутентификации одного и того же пользователя могут быть разные: логин/пароль, OAuth токен и что-нибудь ещё. Главное, чтобы пользователь мог доказать приложению, что это он. А есть ещё авторизация &#8211; это определение набора прав или операций, доступных конкретному пользователю. Пусть даже не аутентифицированному. И это не обязательно доступ в админку, но и комментарии, доступ к определённым информационным материалам и что там ещё разработчик придумал. </p>

	<p>Получается, что админка может разрабатываться независимо и на первых парах быть доступна и без пароля. Во всяком случае на сервере разработки. Достаточно создать маршруты и связать их с операциями. Аутентификация и авторизация потребуются только при создании ролей. Если честно, то эта мысль раньше мне в голову не приходила. В этом месте я завис. </p>

	<p>Оказывается мне нужна была служебная область, а я собирался реализовывать механизмы ограничения доступа. Неожиданно.  В этом месте я остановлюсь для создания нового плана захвата Парижа. И да, я же писал: без плана &#8211; никуда.</p>]]>
</content:encoded>
<link>http://ihhi.ru/articles/218/sindrom-vakhtera-adminka</link>
<pubDate>Mon, 04 Apr 2016 00:29:09 GMT</pubDate>
<dc:creator>IHHI</dc:creator>
<guid isPermaLink="false">tag:ihhi.ru,2016-04-03:40e1955cceef8b96b347e053376f8ee2/0d4e73d188efaa96ccc11f26bead63cc</guid>

<category>laravel</category>
</item>
<item><title>Послать по адресу</title>
<content:encoded>
<![CDATA[<p>От теории к практике. Быстро! А то стоит одиноко в интернете вся из себя такая продающая страница, клиентов собрала легион, а сообщить мне об этом не может. Пока <a href="http://ihhi.ru/articles/216/formalizatsiya-kontaktov">писал рассуждения о форме почтовой</a> понял, что главное &#8211; не заморачиваться. Рассуждать можно долго, а связь должна быть прямо вот сразу. Путь в <a href="https://laravel.com/docs/5.2/mail">документацию Laravel</a> &#8211; это практически тупик. Если знаешь как делать, то и по документации поймешь. А не знаешь&#8230; Ну и вот.</p>

	<p>Начнём с настройки. Laravel, если верить файлу конфигурации поддерживает доставку почты &#8220;smtp&#8221;, &#8220;mail&#8221;, &#8220;sendmail&#8221;, &#8220;mailgun&#8221;, &#8220;mandrill&#8221;, &#8220;ses&#8221;, &#8220;log&#8221;. В соответствии с выбором, который лучше произвести в файле <strong>.env</strong>, нужно указать и другие параметры, обеспечивающие работу email на конкретном сервере. Для хостинга одно, для домашнего сервера другое, а для выделенного или виртуального сервера и вовсе третье.</p>

	<p><pre class='brush: plain'>
MAIL_DRIVER=smtp
MAIL_HOST=mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
</pre></p>

	<p>Самое главное в почтовых формах &#8211; это обеспечение доставки электропочты. Как бы ни был хорош дизайн, он не имеет смысла, если почта не доходит до адресата. Поэтому рекомендую озаботиться этим моментом очень серьёзно и тестировать настройки не отходя от кассы. Сразу хочу предостеречь от использования для доставки своего аккаунта Gmail, если сервер находится вдали от рабочего компьютера. Google просто заблокирует отправку и будет слать предупреждения, что паролем завладели злоумышленники и корпорация добра вот только что спасла тебя от страшного.</p>

	<p>Настроили? Проверяем. Для этого проще всего использовать <strong>tinker</strong>, известный ранее как <strong>Boris</strong> и являющийся <strong><span class="caps">REPL</span></strong>. Всё ясно? Тогда запускаем его и проверяем реальную работу доставки почты. Там ниже <strong>real@email</strong> &#8211; это реальный адрес, на который нужно доставить email. Желательно его указывать без ошибок.</p>

	<p><pre class='brush: plain'>
[polygon@ihhi.dev]$ ./artisan tinker
Psy Shell v0.7.2 (PHP 5.5.25 — cli) by Justin Hileman
>>> Mail::send('email.test',
['data' => 'Test, test, test!'],
function($message) {$message->to('real@email')
->subject('Просто тест');
});
InvalidArgumentException with message 'View [email.test-blade] not found.'
>>>
</pre></p>

	<p>Оп-с, неправильно записал имя blade шаблона. Хотел сделать <strong>test.blade.php</strong> в <strong>resources/views/email</strong>, но рука дрогнула. Запускаю с правильным именем шаблона.</p>

	<p><pre class='brush: plain'>
>>> Mail::send('email.test-blade',
['data' => 'Test, test, test!'],
function($message) {$message->to('real@email')
->subject('Просто тест');
});
ErrorException with message 'PHP error:  Undefined variable: mydata in /www/dev/ihhindex/cv.ihhindex.dev/storage/framework/views/53c4829e48b94a5f7e7c823bc8903fc74064aa9f.php on line 8 (View: /www/dev/ihhindex/cv.ihhindex.dev/resources/views/email/test-blade.blade.php)'
>>>
</pre></p>

	<p>Ну здесь обычная история: в шаблоне описанная переменная не получает данных, т.к. в него передаётся другая и он грустит. Ещё одна правка и запуск</p>

	<p><pre class='brush: plain'>
>>> Mail::send('email.test-blade',
['data' => 'Test, test, test!'],
function($message) {$message->to('real@email')
->subject('Просто тест');
});
=> 1
>>> exit
Exit:  Goodbye.
[polygon@ihhi.dev]$
</pre></p>

	<p>Всё получилось, почта ушла. И даже пришла. Сразу скажу, что команда, начиная с <strong>Mail::</strong> и до <strong>});</strong> может быть одной строкой. Здесь она отформатирована исключительно для удобства восприятия. Если будут найдены ошибки, то курсором придётся &#8220;гулять&#8221; по всей длине записи.</p>

	<p>Теперь потребуется совершить три подвига:</p>

	<ul>
		<li>Добавить маршруты в <strong>router.php</strong>;</li>
		<li>Создать и заполнить кодом контроллер;</li>
		<li>Сделать вьюшки.</li>
	</ul>

	<p>Да, чуть не забыл: перед стартом производства подвигов требуется план. Даже если подвигов всего три. И далее, в соответствии с планом, вычёркиваем сделанное.</p>

	<h3>Маршруты</h3>

	<p><pre class='brush: php'>
Route::group(['middleware' => ['web']], function () {
	Route::get('/{id?}', 'PagesController@show')->where('id', '\d+');
	Route::get('contacts', 'ContactsController@getContacts');
	Route::post('contacts', 'ContactsController@postContacts');
});
</pre></p>

	<p>Сейчас роутер у меня выглядит предельно просто: все запросы идут через middlware <strong>web</strong> и далее разруливаются. Вторая строка про вызов одностраничика и про то, что если в адресе обнаруживается число, то генерируется соответствующая версия страницы. Это фишка не для электропочты и на &#8220;боевом&#8221; сервере отключается.</p>

	<p>А следующие две строки с маршрутом <strong>contacts</strong> про неё родимую. Метод <strong>get</strong> &#8211; вызвать функцию <strong>getContacts</strong>, которая отображает отдельно стоящую форму отправки. Это вспомогательная функция, т.к. я надеюсь, что вменяемый посетитель сразу правильно заполнит форму и отправит её с одностраничника. Но в случае непосредственного перехода по адресу <strong>/contacts</strong> будет отображаться эта форма. Она же отображается и при ошибке ввода, так что лишней работы здесь почти нет. Но прямой ссылки на эту страницу я давать не планирую. Метод <strong>post</strong> вызывает функцию <strong>postContacts</strong>, которая должна выполнить всю работу. Обе функции в контроллере <strong>ContactsController</strong>. На этом с маршрутами можно закончить.</p>

	<h3>Контроллер</h3>

	<p>Для начала неплохо бы его сделать. И лучше пустым, чтобы не убирать лишнее.</p>

	<p><pre class='brush: plain'>
 ./artisan make:controller ContactsController
</pre></p>

	<p>И теперь про план в отношении этого контроллера: в последнее время из контроллеров стараются убрать всё лишнее. Не должно быть в них обработки, валидации и вообще ничего сложного и повторяющегося. И я с этим согласен. Но не сейчас. Решение рассматриваю как временное и не хочу потом выкорчёвывать следы этой деятельности в нескольких местах. Поэтому всё будет в одном контроллере. После небольшой доработки вот что получилось.</p>

	<p><pre class='brush: php'>
&lt;?php namespace App\Http\Controllers;
use Mail;
use Validator;
use Illuminate\Http\Request;
use App\Http\Requests;
class ContactsController extends Controller
{
    //
}
</pre></p>

	<p>Я добавил в контроллер почту и валидатор. Теперь быстренько организую функции. Сначала отображение формы</p>

	<p><pre class='brush: php'>
	/**
	 * Show contact form
	 * 
	 * @return view
	 */
    public function getContacts(){
        return view('frontend.pages.contact');
    }
</pre></p>

	<p>Теперь обработку</p>

	<p><pre class='brush: php'>
/**
 * Post data from contact form
 * 
 * @param Request $request 
 * @return view
 */
public function postContacts(Request $request){
	$data = $request->all();
    $messages = [
        'required'  => 'Это поле обязательно для заполнения.',
        'string'    => 'Введены недопустимые символы.',
        'min' 		=> 'Маловато знаков. Минимум - :min',
        'max' 		=> 'Многовато знаков. Максимум - :max',
        'email'     => 'Это  не похоже на адрес email',
        'url'      	=> 'Это  не похоже на адрес сайта',
    ];
	$validator = Validator::make($data, [
        'contactname' 	=> 'required|min:3|max:255',
        'email' 		=> 'email|required',
        'website' 		=> 'url',
        'message' 		=> 'required|min:10|max:255',
    ], $messages);
	if ($validator->fails()) {
        return redirect('contacts')
                    ->withErrors($validator)
                    ->withInput();
    }
    Mail::send('email.form', ['data' => $data], function($message) use ($data)
    {
     	$message->from($data['email'] , $data['contactname']);
    	$message->to('real@email', 'CV Form')->subject('CV mail form');
    });
    return view('frontend.pages.form-ok', ['name' => $data['contactname']]);
}
</pre></p>

	<p>Надеюсь всё понятно:</p>

	<ul>
		<li>Строки 9-16 &#8211; я создал свои версии сообщений об ошибках ввода. Делать перевод в файлах локализации не хотелось по описанным выше причинам. И ещё один нюанс: использовать сообщение &#8220;Поле contactname обязательно для заполнения&#8221; мне не хочется, а стандартные сообщения показывают не названия, которые видит посетитель, а имена, используемые при генерации полей и они часто сильно отличаются.</li>
		<li>Строки 17-22 &#8211; правила проверки пользовательского ввода. Обращаю внимание на поле website &#8211; оно не обязательно для заполнения, но если уж посетитель решил в него что-нибудь написать, то потребуется сделать это правильно. И ввести http:// перед адресом, или создать правило самому.</li>
		<li>Строки 23-27 &#8211; в случае ошибки сообщаем об этом пользователю и используем вспомогательный шаблон, а не весь одностраничник. И передаём в него как сообщения об ошибках, так и данные, введённые пользователем. Многие не вводят повторно данные в форму, если они исчезли при ошибке.</li>
		<li>Строки 28-32 &#8211; формирование и отправка почты. Так же я передаю в шаблон <strong>form.blade.php</strong> весь массив данных из формы. С названием вьюхи я ошибся и оно выглядит провокационно, но пока менять не буду.</li>
		<li>Строка 33 &#8211; вызов страницы с сообщением об успешной отправке. Успех, кстати, не гарантирован, но проверки я не делаю. Потом нужно будет добавить. При формировании сообщения я использую имя автора, для чего передаю его в шаблон. Мне не трудно, а человеку приятно. Да, ещё, я вместо редиректа использую вью. Мне так больше нравится.</li>
	</ul>

	<h3>Шаблоны</h3>

	<p>И третья часть марлезонского балета: шаблоны blade. Вспомогательная почтовая форма. Она используется при прямом вызове или при наличии ошибок ввода. Ошибки можно выводить скопом в специально отведённом для этого месте, или под соответствующим полем ввода. Я выбрал второй вариант. При наличии ошибки поле ввода обводится красным бордюром и под ним выводится первое сообщение об ошибке. Одно.</p>

	<p><pre class='brush: php'>
@extends('frontend.layouts.default')
@section('content')
<section id="contact" class="section section-contact">
<!--Contact -->
  <div class="container">
  <h2 class="section-title"><span>Контакты</span></h2>
    <div class="row">
      <div class="col-xs-12 col-md-6 col-sm-12">
        <h3>Контактная форма</h3>
          <div class="contact_wrap" >
          <form method="post" action=""{{ URL::to('contacts') }} id="passion_form">
            <input type="hidden" name="_token" value="{!! csrf_token() !!}">
            <div class="form-group{{ $errors->first('contactname', ' has-error') }}">
              <input type="text" size="50" name="contactname" id="InputName" value="{{ old('contactname') }}" class="form-control required" placeholder="Имя*"/>
              {!! $errors->first('contactname', '<span class="help-block">:message</span>') !!}
            </div>
            <div class="form-group{{ $errors->first('email', ' has-error') }}">
              <input type="text" size="50" name="email" id="email" value="{{ old('email') }}" class="form-control required email" placeholder="Email*"/>
              {!! $errors->first('email', '<span class="help-block">:message</span>') !!}
            </div>
            <div class="form-group{{ $errors->first('website', ' has-error') }}">
              <input type="text" size="50" name="website" id="website" value="{{ old('website') }}" class="form-control" placeholder="Сайт"/>
              {!! $errors->first('website', '<span class="help-block">:message</span>') !!}
            </div>
            <div class="form-group{{ $errors->first('message', ' has-error') }}">
              <textarea class="form-control required" rows="6"  name="message" id="message"  placeholder="Сообщение*">{{ old('message') }}</textarea>
              {!! $errors->first('message', '<span class="help-block">:message</span>') !!}
            </div>
            <button type="submit" class="btn btn-default">Отправить</button>
          </form>
        </div>
      </div>
      <div class="col-xs-12 col-md-6 col-sm-12">
        <h3>Карта. Во-первых - это красиво.</h3>
        <br>
        <div class="google">
          <div id="map"></div>
        </div>
      </div>
    </div>
  </div>
<!-- /contact --> 
</section>
@endsection
</pre></p>

	<p>И в случае успеха выводится сообщение с помощью вот такого шаблона.</p>

	<p><pre class='brush: php'>
@extends('frontend.layouts.default')
@section('content')
<section id="contact" class="section section-contact">
<!--Contact -->
  <div class="container">
  <h2 class="section-title"><span>Контакты</span></h2>
    <div class="row">
      <div class="col-xs-12 col-md-6 col-sm-12">
        <h3>Контактная форма обработана</h3>
          <div class="contact_wrap" >
            <p>{{$name}}, всё отлично, письмо отправлено. Теперь попробуйте послать мне бандероль или денежный перевод. </p>
            <p>Перейти на единственную страницу сайта</p>
            <p><a href="http://ihhi.ru/{{url('/')}}"  class="btn btn-info">прыг</a></p>
        </div>
      </div>
      <div class="col-xs-12 col-md-6 col-sm-12">
        <h3>Карта. Во-первых - это красиво.</h3>
        <br>
        <div class="google">
          <div id="map"></div>
        </div>
      </div>
    </div>
  </div>
<!-- /contact --> 
</section>
@endsection
</pre></p>

	<p>И&#8230; И всё, на этом можно переходить к испытаниям и ждать сообщения от покупателей. А, не, не всё. Я забыл про шаблон для отправки почты. Исправляюсь. Шаблон для тестирования можно сделать на его основе, если что.</p>

	<p><pre class='brush: php'>
&lt;!DOCTYPE HTML>
&lt;html lang="en-US">
&lt;head>
	&lt;meta charset="UTF-8">
	&lt;title>&lt;/title>
&lt;/head>
&lt;body>
	<p>Hello,</p>
	<p>Name: {{ $data['contactname'] }}</p>
	<p>E-mail: {{ $data['email'] }}</p>
	@if ($data['website'])
	<p>Site: {{ $data['website'] }}</p>
	@endif
	<p>Text: {{ $data['message'] }}</p>	
	<p>---<br/>
	Best regards,<br/>
	CV Team</p>
&lt;/body>
&lt;/html>
</pre></p>

	<p>Вот теперь всё. Кажется. На самом деле я уже готов всё переделать, но всплыла более насущная проблема: полное отсутствие присутствия админки. Я как-то забыл про неё, а заглянул в роутер и оба-на, нету. Не то, чтобы я хотел активно что-то редактировать на одностраничнике. Но лендинг должен собирать статистику. Можно подключить GA, LI или ещё что-нибудь. Можно добавить их просмотр в админку. Можно сделать свой сбор данных и их анализировать или смотреть &#8220;сырыми&#8221;. Это детали. И для их реализации админка нужна 100 пудов.</p>]]>
</content:encoded>
<link>http://ihhi.ru/articles/217/poslat-po-adresu</link>
<pubDate>Sun, 03 Apr 2016 17:01:25 GMT</pubDate>
<dc:creator>IHHI</dc:creator>
<guid isPermaLink="false">tag:ihhi.ru,2016-04-03:40e1955cceef8b96b347e053376f8ee2/01e728dc8602cbb046f7dbfa686e0991</guid>

<category>laravel</category>
<category>blade</category>
<category>tinker</category>
<category>email</category>
</item>
<item><title>Формализация контактов</title>
<description>
<![CDATA[Организация контактной формы на одностраничном сайте]]>
</description>
<content:encoded>
<![CDATA[<p><a href="http://ihhi.ru/articles/214/psikhanul-odnostranichnik-na-laravel">Делал я одностраничник, делал</a> и тут выяснилось, что главная его часть &#8211; обратная связь. Если обычный сайт может быть ориентирован на показ рекламы, внедрение в головы посетителей абстрактного благоговения перед каким-нибудь брендом и на прочие диджитальные штучки, то одностраничник должен дать контакт с посетителем. Не какой-нибудь визртуальный, а обычный контакт: письмо, звонок. Любое действие, предшествующее покупке. Кажется это называется &#8220;лид&#8221;. А это возможно только при наличии контактной формы или телефона для звонка. </p>

	<p>Ввиду безграничности интернета в части глупых шуток, размещать личный телефон на сайте не очень хочется. А вот форму обратной связи сделать нужно. И, кажется, таких форм может потребоваться несколько. Самое очевидное &#8211; это размещаемая в самом низу страницы контактная форма. Типа &#8220;напишите мне что-нибудь&#8221; и &#8220;ах, введённый вами email не соответствуют rfc&#8221; через &#8220;докажите, что вы не робот&#8221;. Вот сам видел: лендинг с капчей. Карл, с капчей!</p>

	<p>Ну ладно, форму внизу страницы размещать нужно. Вдруг лендинг настолько бестолковый, что человеку даже хочется купить, но он не получил ответа на какой-нибудь свой вопрос. Тогда он пишет сообщение в духе &#8220;а такое же,  но с перламутровыми пуговицами есть?&#8221; и отправляет его куда-то туда. И&#8230; А что должно произойти после нажатия кнопки &#8220;Послать&#8221;? Как вообще должна работать форма на одностраничнике? Варианты</p>

	<ul>
		<li>Обычная форма
	<ul>
		<li>Страница обновляется, сообщение об отправке замещает форму</li>
		<li>Страница обновляется, сообщение об отправке дополняет форму</li>
		<li>Страница на время заменяется страницей с сообщением &#8220;ОК&#8221; с последующим возвратом;</li>
		<li>Страница заменяется страницей с сообщением &#8220;ОК&#8221;;</li>
	</ul></li>
		<li>Поп-ап форма;</li>
		<li>Форма по типу <span class="caps">SPA</span>;</li>
		<li>&#8220;Приклеенный&#8221; ярлычок &#8220;свяжитесь с нами&#8221;, постоянно присутствующий в окне.</li>
	</ul>

	<p>Обычная форма при использовании которой приходится маслать весь лендинг во время отправки сообщения кажется мне не самым лучшим решением. Вариант с дополнительной страницей и автовозвратом, претендующий на роль приемлемого компромисса, тоже  вызывает ряд вопросов. Например, что делать человеку на одностраничнике после отправки сообщения? Второй раз перечитать? Зачем тогда со страницы его уводить и потом приводить обратно? И как обрабатывать желание посетителя пообщаться раньше, чем он добрался до низа страницы?</p>

	<p>Поп-ап форма кажется отличной штукой: нажал на кнопку, заполнил, отправил. Вызов модального окна можно разместить в нескольких местах, что позволит получить контакт с клиентом в любой момент, а не когда тот домотает страницу до конца. После отправки сообщение об успехе в модальном же окне и выводится, после чего можно закрыть либо окно, либо страницу целиком. Смущает один момент: если закрывать модальное окно при клике за его пределами, то можно потерять контакт с клиентом, а если блокировать эту возможность, то можно &#8220;заклинить&#8221; страницу на каком-нибудь мобильном девайсе и тоже потерять клиента.</p>

	<p>И последний вариант: перегрузка только области страницы с контактной формой. У этого варианта два негативных момента: это сложнее и нужно специально отрабатывать сценарий отправки при отключенном у клиента JS. То есть вариант прекрасен, но сложен. Два раза сложен. И ещё при нём, как и при первом варианте, нужно обеспечивать возможность контакта не только в конце страницы.</p>

	<p>С такой штукой сталкивались многие. Чаще всего ставятся сторонние разработки, обеспечивающие возможность пообщаться с оператором по любому вопросу. Проблема у этого решения одна: выбор между навязчивостью и скромностью приводит к тому, что в первом случае клиент может отказаться от общения из вредности, а во втором &#8211; по невнимательности. Зато плюс огромный: ничего  не надо писать самому, а значит я и рассматривать этот вариант не буду.</p>

	<p>Пока я не решил, какой вариант для связи на одностраничнике лучше, буду реализовывать их по одному. Сначала самый простой вариант: форма внизу, после отправки посетитель попадает на служебную страницу с отчётом. На служебной странице помимо ссылки на главную можно размещать какую-нибудь дополнительную информацию. Потом сделаю поп-ап. А за это время решу на чём делать <span class="caps">SPA</span>. Там вариантом очень много.</p>]]>
</content:encoded>
<link>http://ihhi.ru/articles/216/formalizatsiya-kontaktov</link>
<pubDate>Sat, 02 Apr 2016 21:13:56 GMT</pubDate>
<dc:creator>IHHI</dc:creator>
<guid isPermaLink="false">tag:ihhi.ru,2016-03-26:40e1955cceef8b96b347e053376f8ee2/101563300ff3d22cc4feba63b3ac7614</guid>


</item>
<item><title>Laravel - это про новости?</title>
<content:encoded>
<![CDATA[<p>Я не замечал раньше сайтов на Laravel и жизнь моя была спокойна и безмятежно. С тех пор, как я занялся поисками, я потерял покой, сон и разум. Причиной этого стало то, что почти все найденный сайты на Laravel оказались новостными и мой отказ от чтения газет по утрам был полностью уничтожен этим обстоятельством. </p>

	<p><a href="http://tvernews.ru/">Сетевое издание <span class="caps">ТИА</span></a> &#8211; что-то очень похожее на городской портал Твери. Новости, реклама, блоги, конкурсы и что-то ещё с указанием регистрации в &#8220; Федеральной службе по надзору&#8230;&#8221; от 2014 года. Если копнуть глубже, то найдутся записи пятилетней давности. Значит на Ларавель они не сразу перешли. . На этом сайте я узнал, что в Твери депутаты чего-то не сделали, что Нюша &#8211; это не розовая свинья из мультфильма, а певица и композитор, и что в Твери есть цирк. Как я жил без этого? </p>

	<p>Портал народной аналитики <a href="http://balalaika24.ru/">Balalaika24.ru</a>. Балалайка. Карл, они назвали свой сайт Ба-ла-лай-ка. 24. Я даже не знаю в каких словах описать те слова, которые я знаю и имею сказать. Зачем они так? Они &#8211; это &#8220;платформа для народных новостей и аналитики&#8221;. Платформа. Фреймворк. А ещё они &#8220;место для встреч независимых блоггеров, журналистов и просто неравнодушных людей&#8221;, некоммерческая организация и зарегистрированы как <span class="caps">СМИ</span>. Они собирают по всему и-нету политически озабоченных графоманов и предлагают им писать статьи. Одно может оправдать этот сайт: если собранный ими <span class="caps">УКЖ</span> все буквы будет тратить на Балалайку и больше нигде не будет отсвечивать.</p>

	<p>Новостной портал который&#8230; Опять новости. На этот раз сайт <a href="http://inetia.ru">http://inetia.ru</a>. Если верить интерфейсу, то у них новости на десятке языков, какая-то система их ранжирования и какие-то настройки отображения в духе Медиаметрикса. Даже есть ссылка &#8220;городские порталы&#8221;. Интересно, там тверской сайт есть? Нет, вру, совсем неинтересно. Объём проделанной работы впечатляет, но результат мне не нравится. Может это и прекрасный проект, но я не являюсь его ЦА. Хотя бы в качестве <span class="caps">СМИ</span> не зарегистрирован.</p>

	<p>Ну и, наконец, нормальный сайт по продаже шин. Он даже называется <a href="http://avtoshina74.ru">Автошина74</a> &#8211; суровый челябинский Ларавель: шины, диски, шиномонтаж. Нормальные коммерсанты оказались в абсолютном меньшинстве. Интересно, о чём это говорит?</p>

	<p>Думаю, что рубрику &#8220;а вот ещё я сайт нашёл&#8221; нет смысла делать постоянной. Поиск сайтов на Laravel был интересен в самом начале, когда было не совсем понятно кто и что на нём делает. Теперь, после приватизации Ларавеля <span class="caps">СМИ</span>шными сайтами, я задумался о том, какие бы мне новости на нём организовать. И уже есть пара идей.</p>]]>
</content:encoded>
<link>http://ihhi.ru/articles/215/laravel-eto-pro-novosti</link>
<pubDate>Sat, 02 Apr 2016 21:11:19 GMT</pubDate>
<dc:creator>IHHI</dc:creator>
<guid isPermaLink="false">tag:ihhi.ru,2016-03-26:40e1955cceef8b96b347e053376f8ee2/34ac58944d423806cff94bff4389257c</guid>


</item>
<item><title>Психанул. Одностраничник на Laravel.</title>
<description>
<![CDATA[Создание одностраничкика с на laravel с помощью gulp, bootstrap и jquery]]>
</description>
<content:encoded>
<![CDATA[<p>Ещё раз прошёлся по близлежащим интернетам с целью изучения примеров сайтов на Laravel. Искал варианты с исходниками, разумеется. Всё что нашёл не выдерживает никакой критики. Либо только админка времени выхода первого айфона, либо клиентской части вообще нет, а то и просто набор вьюх без базы данных из серии &#8220;я и моё любимое животное (я справа)&#8221;. И тогда я решил сделать сайт с нуля. С сассами, бутстрепами и ещё какой-нибудь нежностью. Пусть даже всего из одной страницы.</p>

	<p>Да-да, я решил сделать одностраничник. Точнее &#8211; переделать чисто пхп-шный концепт, позволяющий из блоков набрать какое-то подобие одностраничного сайта или лендинга. Никаких затей, чисто <strong>require block.php</strong> и куча стилей со скриптами. И решил я этот сайт оформить как посадочную страницу по продаже разработчика. Типа продаётся программист со всеми вытекающими последствиями. Разумеется страница будет безо всяких мотивирующих приколов типа &#8220;заказавшему программиста сегодня скидка 25%&#8221;. Хотя&#8230;</p>

	<p>Ладно, о способах продажи людей в другой раз. Сейчас об инструментах: Laravel, Gulp, Bootstrap и всём том, о чём я писал <a href="http://ihhi.ru/articles/212/evroremont-po-laravelski">ранее</a>. Сделать несколько blade шаблонов и собрать из них страницу не является целью данной лабораторной работы. Хочется выяснить размер экономии в байтах при использовании Gulp и Sass. Суммарный размер файлов Bootsrap, jQuery и используемых модулей в моём случае составлял почти 700 килобайт. За красоту приходится платить, но такая цена мне кажется избыточной. Буду резать.</p>

	<p>Понимаю, что за один раз всё лишнее я не уберу. Работа эта требует внимания и усидчивости. Для первого раза я хочу убрать самые очевидные излишки жира. Мне тут подсказали, что в быту это называется &#8220;липосакция&#8221;. Ну пусть так и будет. Sass файл Bootstrap выглядит вот так:</p>

	<p><pre class='brush: css'>
/*!
 * Bootstrap v3.3.6 (http://getbootstrap.com)
 * Copyright 2011-2015 Twitter, Inc.
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 */
// Core variables and mixins
@import "bootstrap/variables";
@import "bootstrap/mixins";
// Reset and dependencies
@import "bootstrap/normalize";
@import "bootstrap/print";
@import "bootstrap/glyphicons";
// Core CSS
@import "bootstrap/scaffolding";
@import "bootstrap/type";
@import "bootstrap/code";
@import "bootstrap/grid";
@import "bootstrap/tables";
@import "bootstrap/forms";
@import "bootstrap/buttons";
// Components
@import "bootstrap/component-animations";
@import "bootstrap/dropdowns";
@import "bootstrap/button-groups";
@import "bootstrap/input-groups";
@import "bootstrap/navs";
@import "bootstrap/navbar";
@import "bootstrap/breadcrumbs";
@import "bootstrap/pagination";
@import "bootstrap/pager";
@import "bootstrap/labels";
@import "bootstrap/badges";
@import "bootstrap/jumbotron";
@import "bootstrap/thumbnails";
@import "bootstrap/alerts";
@import "bootstrap/progress-bars";
@import "bootstrap/media";
@import "bootstrap/list-group";
@import "bootstrap/panels";
@import "bootstrap/responsive-embed";
@import "bootstrap/wells";
@import "bootstrap/close";
// Components w/ JavaScript
@import "bootstrap/modals";
@import "bootstrap/tooltip";
@import "bootstrap/popovers";
@import "bootstrap/carousel";
// Utility classes
@import "bootstrap/utilities";
@import "bootstrap/responsive-utilities";
</pre></p>

	<p>Каждая вставка &#8211; это функциональность и вес. Простой чек-лист позволяет выявить неиспользуемые блоки и просто выключить их. То же самое можно сделать и с остальными Sass файлами. Animation.css, к примеру, с 50 кил сокращается до полутора. Такие вот расклады. В результате  css ужимается до 100 килобайт. И я надеюсь, что есть ещё резервы, но уже первые результаты вдохновляют. </p>

	<p>Подозреваю, что столь же впечатляющие достижения ждут меня при обрезании jQuery и&#8230; отложу это счастье на потом. Просто солью весь скрипт в один файл. Дело в том, что набор скриптов я буду менять и пока не хочу погружаться в это болото. Хватило того, что я полез смотреть, что думает про сайт &#8220;PageSpeed Insights&#8221;: от Google и зарылся с настройку сервера, ревизию модулей Апача и сравнение с результатами Я.Вебмастера и других инструментов. А ведь я совсем не планировал этого. Ну её, преждевременную оптимизацию. Эксперимент признан удачным и пока на этом остановлюсь.</p>]]>
</content:encoded>
<link>http://ihhi.ru/articles/214/psikhanul-odnostranichnik-na-laravel</link>
<pubDate>Sat, 02 Apr 2016 18:06:56 GMT</pubDate>
<dc:creator>IHHI</dc:creator>
<guid isPermaLink="false">tag:ihhi.ru,2016-03-26:40e1955cceef8b96b347e053376f8ee2/3858430bcda7970f969230d856e014e3</guid>

<category>laravel</category>
<category>bootstrap</category>
<category>лендинг</category>
</item>
<item><title>Модельный бизнес</title>
<content:encoded>
<![CDATA[<p>Кажется я сильно погорячился с <a href="http://ihhi.ru/articles/209/organizatsiya-bazy-dannykh-migratsii">заявлением</a>, что мне для начала нужны только миграции, а модели потом. Ну закачал я данные в базу, ну порадовался, что могу ими теперь пользоваться. А ведь и не могу. От слова совсем. Для работы с базами данных в Laravel предназначены модели. В них же рекомендуют выносить из контроллеров и бизнес логику. А раз нужны модели, то таблицы нужно приводить в порядок, описывать связи, устанавливать правила и описывать как оно вообще должно работать.</p>

	<p>Сначала о моделях. В Laravel это расширение базового класса Model используемой <span class="caps">ORM</span> Eloquent. <span class="caps">ORM</span> (англ. Object-Relational Mapping) &#8211; это объектно-реляционное отображение. По-русски это звучит столь же непотребно: реализация <span class="caps">ООП</span> шаблона Active Record по кличке Красноречивый решает. А если на практике, то всё просто отлично. Создаём модель</p>

	<p><pre class='brush: plain'>
php artisan make:model Article
</pre></p>

	<p>или модель с миграцией</p>

	<p><pre class='brush: plain'>
php artisan make:model Article --migration
</pre></p>

	<p>Про <a href="http://ihhi.ru/%2C">миграции</a> надеюсь, всё понятно: сгенерируется отличный каркас миграции по имени <strong>2016_03_23_030541_create_articles_table.php</strong>, в который следует добавить нужное и убрать лишнее для создания таблицы <strong>articles</strong>. А каркас модели для управления этой таблицей по имени <strong>Article</strong> выглядит вот так</p>

	<p><pre class='brush: php'>
&lt;?php  namespace App;
&nbsp;
use Illuminate\Database\Eloquent\Model;
&nbsp;
class Article extends Model
{
    //
}
</pre></p>

	<p>И&#8230; А всё, можно создавать объекты класса <strong>Article</strong> и пользоваться всеми возможностями <strong><span class="caps">ORM</span></strong>. Например, создать новую статью, задать заголовок и содержимое, записать статью в базу:</p>

	<p><pre class='brush: php'>
$article = new Article;
$article->title = 'Крутая статья';
$article->title = 'Улётный текст статьи';
$article->save();
</pre></p>

	<p>Это уже работает. Кроме шуток. Первые тесты я проводил на простых сайтах, имеющих примитивные сценарии работы. Создал модели и даже не заглядывал в них. Просто получал из базы нужные данные и перекидывал их в представления. В моделях Laravel вообще куча вполне разумных умолчаний, позволяющих использовать их без долгих прелюдий, а вся мощь <span class="caps">ORM</span> Eloquent наследуется и доступна без дополнительных телодвижений. Имя таблицы базы данных, к примеру &#8211; это множественное число имени модели в нижнем регистре. Не устраивает? Можно задать своё. </p>

	<p>Но если выходить за пределы тестовых заданий и лабораторных работ, то придётся немного поработать как руками, так и головой. Голова потребуется для понимания связей в базах данных вообще и в Eloquent в частности. А руками связи нужно будет закодировать и заставить работать. И тогда без проблем будут находиться теги, авторы и комментарии статей, а так же статьи авторов и категорий. Связи решают. Такой вывод.</p>]]>
</content:encoded>
<link>http://ihhi.ru/articles/213/modelnyi-biznes</link>
<pubDate>Mon, 28 Mar 2016 05:30:02 GMT</pubDate>
<dc:creator>IHHI</dc:creator>
<guid isPermaLink="false">tag:ihhi.ru,2016-03-23:40e1955cceef8b96b347e053376f8ee2/8ab4a6bc48d6e02ec3c4f2ee52495110</guid>

<category>eloquent</category>
<category>laravel</category>
<category>orm</category>
<category>mvc</category>
<category>migrations</category>
<category>model</category>
</item>
<item><title>Евроремонт по-ларавельски</title>
<content:encoded>
<![CDATA[<p>Каждый фреймворк имеет раздел типа &#8220;Быстрый старт&#8221;. В этом разделе в духе &#8220;3 клика, 2 минуты, готовый результат&#8221; рассказывается о том, как просто и быстро можно начать пользоваться их замечательным продуктом. И это правда. Но только про первую дозу, которая, как все знают, бесплатна. А потом уже  не соскочить и приходится платить. Временем, деньгами, нервами и&#8230; В общем &#8211; платить. В <a href="http://ihhi.ru/articles/211/bootstrap-foundation-i-drugie-mimimishki">публикации</a> по выбору фреймворка для фронтенда набежал нехилый список дополнений, делающих интеграцию, разработку и внешний вид более лучшими. Уточню.</p>

  <p>Для начала работы с Twitter Bootstrap требуется совсем немного. Базовый шаблон выглядит просто и понятно</p>

<pre class='brush: xml'>
&lt;!DOCTYPE html&gt;
&lt;html lang=&#8220;en&#8221;&gt;
&lt;head&gt;
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Bootstrap 101 Template</title>

    <!-- Bootstrap -->
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
<!-- Optional theme -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap-theme.min.css" integrity="sha384-fLW2N01lMqjakBkx3l/M9EahuwpSfeNvV63J5ezn3uZzapT0u7EYsXMjQV+0En5r" crossorigin="anonymous">
    <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
    <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
    <!--[if lt IE 9]>
      <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
      <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
    <![endif]-->
  </head>
  <body>
    <h1>Hello, world!</h1>

    <!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
    <!-- Latest compiled and minified JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js" integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS" crossorigin="anonymous"></script>
&lt;/body&gt;
&lt;/html&gt;
</pre>

  <p>Подключены свежие стили и скрипты, включая jQuery. Можно исполнять весь репертуар. Довольно убогий, если честно. Да, тема тоже подключена, но&#8230; Одним словом, дорабатывать и дорабатывать. И это без учёта &#8220;мобайл фёст&#8221; и интересов мобильных пользователей: &#8220;вес&#8221; минифицированных стилей и скриптов почти 300 килобайт. И вроде грузить их пользователю всего один раз, но это не факт и далеко не у всех топовые девайсы в карманах. И да, это ведь ещё без текстов, картинок и прочего контента, за которым пользователь зашёл. Ведь никто не думает, что он за скриптами и стилями здесь, правда? И ещё есть деталь: чем меньше количество подключаемых файлов при одинаковом их размере, тем лучше. В идеале этих файлов может быть два: в начале со стилями и в конце со скриптами. А можно и вообще в тело документа шить. Короче, с этим нужно что-то делать.</p>

  <p>Самый простой способ &#8211; это зайти на страницу <a href="http://getbootstrap.com/customize/">Customize and download</a> и на ней &#8220;галочками и точечками&#8221; отсечь лишнее, выбрать нужное и результат скачать. Даже можно с цветами, бордюрами и размерами поиграться. Выглядит неплохо. Но это при условии, если уже ничего не нужно менять. А если то одно прибавится, то другое убавится, а то опять всё взад вертать? Не находишься, говорят про такое в народе. И вот для этого придуманы всякие умные штуки из списка на предыдущей странице.</p>

  <p>Сейчас я перечислю действия для создания прокачанного центра разработки фронтенда на базе Laravel. Рекомендую перед исполнением подобного сольного номера определиться с набором установки и дочитать текст до конца. А то вдруг оно и не нужно совсем.</p>

  <p>Во-первых, совсем не обязательно использовать тот же набор, что и я. Самое главное понять: в Laravel легко встраивается механизм сборки css/js файлов из различных полуфабрикатов. Я для себя выбрал Bootstrap и <span class="caps">SASS</span>. Этот выбор позволяет легко подключать и другие популярные штуки типа Font Awesome и им подобные. Но можно использовать <span class="caps">LESS</span>, CoffeeScript, Stylus и что там ещё существует. Кстати, это касается не  только текста. Можно собирать картинки в спрайты и ещё какой-нибудь непотребщиной заниматься. Дело личного выбора.</p>

  <p>Итак, определились и поехали. </p>

  <p>1. Проверяем наличие установленной Node.js</p>

<pre class='brush: plain'>
node -v
</pre>

  <p>Получили версию? Идём дальше. Нет? Устанавливаем. rpm, dpkg, yum, apt-get или иной подходящий менеджер пакетов в руки. И главное не забыть установить <strong>npm</strong>. Без него не получится. С установленным npm ставим глобально <strong>gulp</strong> и <strong>bower</strong>. Можно и в одну строку, если что. Я такие действия от рута провожу. Будет ли это работать от локального пользователя не проверял, но думаю, что нет. </p>

<pre class='brush: plain'>
npm install --global gulp
npm install --global bower
</pre>

  <p>Теперь  в корне проекта необходимо создать файл <strong>.bowerrc</strong> для указания места загрузки всякого-разного.</p>

<pre class='brush: js'>
{
  "directory": "resources/assets/vendor"
}
</pre>

  <p>И запускаем</p>

<pre class='brush: plain'>
npm install bower
</pre>

  <p>Теперь нужно проконтролировать попадание директории <strong>node_modules</strong> в файл <strong>.gitignore</strong>. Создаём <strong>bower.json</strong> примерно такого содержания</p>

<pre class='brush: js'>
{
  "name": "Super Site",
  "version": "0.0.0",
  "description": "My superb site",
  "ignore": [
    "**/.*",
    "node_modules",
    "resources/vendor",
    "test",
    "tests"
  ]
}
</pre>

  <p>Если лень его создавать руками, можно запустить процесс его умной генерации</p>

<pre class='brush: plain'>
bower init
</pre>

  <p>И добавить нужные пакеты, наборы и компоненты в <strong>bower.json</strong></p>

<pre class='brush: plain'>
bower install jquery --save
bower install bootstrap-sass --save
bower install fontawesome --save
bower install bootswatch --save
</pre>

  <p>Это богатство установится по указанному ранее пути. Если <strong>bower.json</strong> заполнялся полностью вручную, то нужно выполнить команду</p>

<pre class='brush: plain'>
bower update
</pre>

  <p>Таким образом собрано всё, что должно быть обработано. По мене необходимости можно добавлять или удалять что-либо. Теперь к настройке собственно <strong>gulp</strong>.</p>

  <p>В свежих установках, говорят, вообще ничего не надо делать. Даже <strong>bower</strong> как бы лишний. Но дело в том, что с его помощью проще управлять зависимостями, а <strong>gulp</strong> пусть используется для обработки. Поэтому я убираю строку</p>

<pre class='brush: js'>
    "bootstrap-sass": "^3.0.0"
</pre>

  <p>из файла <strong>package.json</strong>. Важно не забыть убрать запятую в предшествующей строке. Иначе будут ошибки при чтении <strong>json</strong> файла. И запускаем</p>

<pre class='brush: plain'>
npm install
</pre>

  <p>Этот процесс может занять какое-то время. Пока он идёт, я советую в шаблон страницы сайта, в том месте где должны  находиться стили и скрипты сделать две простых вставки для стилей и скриптов, соответственно:</p>

<pre class='brush: xml'>
<link rel="stylesheet" href="{{ elixir('/assets/css/style.css') }}">
</pre>

<pre class='brush: xml'>
<script src="{{ elixir('/assets/js/script.js') }}"></script>
</pre>

  <p>Это позволит избежать проблем с кэшированием подключаемых файлов при отладке. И последний штрих: донесение до <strong>gulp</strong> своих пожеланий. У всех они разные, но возможно всё. На автомате файлы могут копироваться, сливаться, обрабатываться препроцессорами, минифицироваться и всё это может происходить как по требованию, так и по факту внесения изменения в исходники. </p>

  <p>Их смысл в том, что во время разработки будут показываться свежие версии собранных файлов и не нужно думать об этом самому. Для описания задач я сделал подобие дерева директорий откуда и куда должны двигаться байты в процессе получения, обработки и комбинирования запасных частей</p>

<pre class='brush: plain'>
├── resources
|   └── assets
|       ├── sass
|       |   └── style.sass
|       └── vendor
|           ├── bootstrap-sass
|           ├── font-awesome
|           └── jquery
|
├── public
    └── assets
        ├── css
        ├── fonts
        ├── images
        └── js
</pre>

  <p>Таким образом, мне нужно после каждого обновления <strong>bower</strong> копировать то, что не нуждается в последующей обработке. Обычно это картинки и шрифты. Так же сначала можно копировать минифицированные файлы стилей и скриптов, если они подключаются отдельно и процессе разработки не принимают участия. А устраивать полную сборку непосредственно перед деплоем. А можно отдельно стили и скрипты процессить. Чисто время сэкономить. Короче, сценариев очень много. Нужно научиться выбирать правильные.</p>

  <p>В качестве теста я хочу <strong>jquery.js</strong> и <strong>bootstrap.js</strong> копировать во временную директорию, а шрифты  скопировать в <strong>public/assets/fonts</strong> только когда я явно это укажу. На регулярной основе  компилировать файл <strong>resources/assets/style.sass</strong> с подключенными Bootstrap и Fonf Awesome и получать <strong>style.css</strong> в <strong>public/assets/css</strong>, а  из скопированных ранее во временную директорию скриптов компилировать <strong>style.js</strong> в <strong>public/assets/js</strong>. Для этого нужно отрыть файл <strong>gulpfile.js</strong> и привести его к такому виду:</p>

<pre class='brush: js'>
var gulp = require('gulp');
var elixir = require('laravel-elixir');
gulp.task("copyfiles", function() {
  gulp.src("resources/assets/vendor/jquery/dist/jquery.js")
    .pipe(gulp.dest("resources/assets/js/"));
  gulp.src("resources/assets/vendor/bootstrap-sass/assets/javascripts/bootstrap.js")
    .pipe(gulp.dest("resources/assets/js/"));
  gulp.src("resources/assets/vendor/bootstrap-sass/assets/fonts/**")
    .pipe(gulp.dest("public/assets/fonts"));
  gulp.src("resources/assets/vendor/font-awesome/fonts/**")
    .pipe(gulp.dest("public/assets/fonts"));
});
elixir(function(mix) {
  // Combine scripts
  mix.scripts([
      'js/jquery.js',
      'js/bootstrap.js'
    ],
    'public/assets/js/script.js',
    'resources/assets'
  );
  // Compile Sass
  mix.sass('style.sass', 'public/assets/css/style.css');
  mix.version(['assets/css/style.css', 'assets/js/script.js']);
});
</pre>

  <p>
  Всё готово, кроме одного: не создан файл <strong>style.sass</strong>. По указанному в предудущем параграфе адресу этот файл нужно создать и подключить в него нужные блоки. В моём тестовом примере это выглядит так:</p>

<pre class='brush: css'>
/* Style SASS */
@import url(http://fonts.googleapis.com/css?family=Roboto)
@import url(http://fonts.googleapis.com/css?family=Roboto+Slab&subset=latin,cyrillic-ext)
/* Bootstrap */
@import "../vendor/bootstrap-sass/assets/stylesheets/_bootstrap-compass.scss"
@import "../vendor/bootstrap-sass/assets/stylesheets/_bootstrap.scss"
/* Font Awesome */
@import "../vendor/font-awesome/scss/font-awesome.scss"
</pre>

  </p>
  <p>Теперь при выполнении команды <strong>gulp copyfiles</strong>, будет производиться копирование шрифтов и скриптов. А при запуске <strong>gulp</strong> будет компилироваться файл стилей <strong>style.css</strong> и скрипты будут &#8220;сцепляться&#8221;. Я намеренно прописал пути явно, а не через переменные, чтобы было понятно, откуда, что и куда. Если  хочется при каждом изменении исходников стилей запускать процесс компиляции, запускаем волшебную команду <strong>gulp watch</strong>. Вот вкратце и всё. Далее нужно просто создать свой сценарий, настроить его, добавить нужное, удалить лишнее и разрабатывать, разрабатывать и разрабатывать.</p>

  <p>Маленький фокус: чтобы полученные при компиляции файлы минифицировались, нужно запускать вот такую команду:</p>
<pre class='brush: plain'>
gulp --production
</pre>

  <p>И немного радости в конце статьи. Все эти действия необходимо совершать только на инстансе, настроенном под разработку фронтенда. Другие версии и продакт могут просто своевременно получать готовые минифицированные версии файлов style.css и script.js, которые заранее в нужных местах прописаны. Как это будет происходить, дело исключительно внутреннее. Хоть через git, хоть с помощью флэшек. Главное, чтобы техпроцесс не нарушался. </p>]]>
</content:encoded>
<link>http://ihhi.ru/articles/212/evroremont-po-laravelski</link>
<pubDate>Sat, 26 Mar 2016 05:41:14 GMT</pubDate>
<dc:creator>IHHI</dc:creator>
<guid isPermaLink="false">tag:ihhi.ru,2016-03-22:40e1955cceef8b96b347e053376f8ee2/35face2243fd8fa01f27fd6246b324c0</guid>

<category>bootstrap</category>
<category>laravel</category>
<category>elixir</category>
<category>sass</category>
<category>gulp</category>
<category>node.js</category>
<category>bower</category>
</item>
<item><title>Bootstrap, Foundation и другие мимимишки</title>
<content:encoded>
<![CDATA[<p><a href="http://ihhi.ru/articles/201/pristrelka-lumen">Первые тесты</a> фреймворков семейства Laravel показали, что Google хочет от вебмастера мобильной версии сайта. Бета Я.Вебмастера, несмотря на разницу в цифрах с основной версией сервиса, тоже настаивает на мобилизации. Аргументация бронебойная: в мобильной выдаче поиска нет смысла показывать неадаптированные сайты. Правда, есть один нюанс в этой самой адаптации, заключающийся в том, что вёрстка в деле мобилизации находится на 9-м месте, а то и дальше. Но сейчас не об идеологии, а о технологии мобилизации. Как её добиться?</p>

	<p>Вообще существует два базовых подхода при создании версий сайта для мобильных терминалов:</p>

	<ul>
		<li>Отдавать разным устройствам разные версии сайта</li>
		<li>Заставить один сайт адаптироваться под разные устройства вывода</li>
	</ul>

	<p>Первое исполнять правильнее, второе &#8211; проще. Обоснование очень простое: для большого экрана стационарного устройства требуется больше данных и отправка этих данных в смартфоны избыточна, т.к. нет возможности все их задействовать. И дело не совсем в представлении контента, а в самой его структуре. К этому нужно добавить технологические нюансы, желание побольше букв для поисковых ботов подсунуть и всё такое прочее. Но делать отдельные сайты для смарфонов, для планшетов и для больших экранов слишком затратно. Получается традиционный выбор: хорошо или дёшево.</p>

	<p>Я сейчас не буду обсуждать создание нескольких версий сайта потому, что сейчас не буду этим заниматься. Из этого можно сделать вывод, что буду я заниматься адаптивной вёрсткой. Из заголовка статьи внимательный и дедуктивно  мыслящий читатель поймёт, что буду я использовать готовые решения, а не изобретать что-то своё. Причин у этого несколько. Во-первых, это долго. А во-вторых &#8211; невозможно. В одиночку практически невозможно сделать и длительное время поддерживать в актуальном состоянии что-либо для фронтенда, т.к. постоянно появляются новые технологии, девайсы и прочие факторы, которые не только нужно учитывать при разработке, но ещё и тестировать. </p>

	<p>На роль базового фреймворка для фронтенда я вижу двух кандидатов: <a href="http://foundation.zurb.com">Foundation</a> и <a href="http://getbootstrap.com">Bootstrap</a>, так же известный как Twitter Bootstrap и я его так и буду звать, т.к. бутстрепов развелось много и можно просто запутаться. Такая вот развилка возникает передо мной уже не в первый раз и я каждый раз склоняюсь к Foundation и&#8230; выбираю Twitter Bootstrap. Связано это, как правило, с его поддержкой какой-нибудь соседней технологией. Twitter Bootstrap кажется менее продвинутым и более кондовым. Вот и сейчас я тоже, кажется, выбираю не Foundation. Laravel просто вынуждает пользоваться Twitter Bootstrap на начальном этапе, а потом уже нет смысла переходить на что-нибудь другое. </p>

	<p>Таким образом стек технологий выглядит просто и незатейливо:</p>

	<ul>
		<li>Laravel</li>
		<li>Twitter Bootstrap</li>
		<li>jQuery</li>
		<li>Font Awesome</li>
		<li><span class="caps">SASS</span></li>
		<li>Gulp</li>
		<li>И кажется, Elixir</li>
		<li>Оп-с, Bower</li>
		<li>Модули Node.js?</li>
		<li>Ну что ещё?..</li>
	</ul>

	<p>Кажется здесь совсем не так просто, как я надеялся в самом начале. Проект разрастается до неприличия. Говорят Лужкову принадлежала технология: &#8220;Хочешь похоронить что-либо &#8211; укрупняй&#8221;. Нет ли тут риска закопаться и пропасть?</p>]]>
</content:encoded>
<link>http://ihhi.ru/articles/211/bootstrap-foundation-i-drugie-mimimishki</link>
<pubDate>Tue, 22 Mar 2016 19:42:13 GMT</pubDate>
<dc:creator>IHHI</dc:creator>
<guid isPermaLink="false">tag:ihhi.ru,2016-03-22:40e1955cceef8b96b347e053376f8ee2/f1162c33fda1b5704cc1c34f69481547</guid>

<category>bootstrap</category>
<category>foundation</category>
<category>laravel</category>
</item></channel>
</rss>