12 мая 2014 в 11:43

25 Laravel Tips and Tricks перевод

Было время, достаточно недавно, когда PHP и его сообщество ненавидели. Главная шутка была про то, насколько ужасен PHP.

Да, к сожалению, сообщество и экосистема просто были ниже сообществ других современных языков по уровню. Казалось, что предназначение PHP было прожить большинство времени в форме беспорядочных тем для WordPress.

Но позже, на удивление, вещи начали меняться — и достаточно быстро. Как будто пока ведьма помешивала горшочек, из ниоткуда начали появляться новаторские проекты. Наверно, самый заметный проект был Composer: наиболее полный менеджер зависимостей для PHP (как Bundler для Ruby или NPM для Node.js). В прошлом PHP разработчики были вынуждены совладать с PEAR (что было страшным сном, на самом деле), сейчас, благодаря Composer, они могут просто обновить JSON файл, и немедленно подтянуть все нужные зависимости. Здесь — профайлер, там — фреймворк для тестирования. Это занимает секунды.

В переполненном мире PHP фреймворков, как раз, когда CodeIgniter начал выдыхаться, фреймворк Laravel Тэйлора Отвелла возник из пепла, чтобы стать любимцем общества. С таким простым и элегантным синтаксисом, создавать приложения с Laravel и PHP было абсолютной забавой! Далее, c четвертой версией фреймворка, полностью использовавшим Composer, наконец-то показалось, что для сообщества все вещи встают на места.

image

Хотите миграций (контроль версий базы данных)? Сделано! Как насчёт мощной реализации Active Record? Конечно, Eloquent сделает всё за вас. Как насчёт возможности тестировать? Безусловно! Маршрутизация (роутинг)? Непременно! Что насчёт хорошо протестированного HTTP слоя? Благодаря Composer, Laravel использует много превосходных Symfony компонентов. Когда доходит до дела, есть все шансы, что Laravel уже это может вам предложить!

image

Раньше PHP был похож на игру Дженга — в одном кубике от того, чтобы развалиться — вдруг, благодаря Laravel и Composer, загорелся свет в конце тоннеля. Так что уберем все намёки, и давайте пороемся во всем, что фреймворк может предложить!

1. Красноречивые запросы*


Laravel предлагает одну из самых мощных реализаций Active Record в мире PHP. Скажем, у вас есть таблица orders вместе с Eloquent моделью Order.
class Order extends Eloquent {}

Мы с легкостью можем выполнить любое количество запросов в базу данных, используя простой и элегантый код PHP. Не надо разбрасываться беспорядочно SQL. Давайте получим все заказы.
Order::all();

Готово! Или, может, эти заказы должны быть отсортированы по дате. Легко:
$orders = Order::orderBy('release_date', 'desc')->get();

А что, если вместо получения записи, нам надо сохранить новый заказ в базу. Мы, конечно, можем это сделать.
$order = new Order;
$order->title = 'Xbox One';
$order->save();

Готово! С Laravel, задачи, которые раньше были громоздкими для выполнения, теперь до смеха просты.

* — Eloquent — название реализации Active Record в Laravel, а также в переводе с английского красноречивый.

2. Гибкая маршрутизация (роутинг)


Laravel уникален тем, что может быть использован разными способами. Предпочитаете более простой и похожий на Sinatra роутинг? Laravel легко может это сделать, используя анонимные функции
Route::get('orders', function()
{
    return View::make('orders.index')
        ->with('orders', Order::all());
});

Это может быть полезным для маленьких проектов и API, но есть большие шансы, что вам понадобятся контроллеры для большинства ваших проектов. Окей, Laravel это тоже умеет.
Route::get('orders', 'OrdersController@index');

Готово! Заметили, как Laravel растет по мере ваших потребностей? Уровень приспособления — вот, что делает фреймворк таким популярным сегодня.

3. Отношения без проблем


Что мы делаем в объектах, когда нужно определить отношения? Например, задача точно принадлежит пользователю. Как это указать в Laravel? Предположив, что нужные таблицы в базе данных созданы, мы только должны обратиться к связанным Eloquent моделям.
class Task extends Eloquent {
    public function user()
    {
        return $this->belongsTo('User');
    }
}

class User extends Eloquent {
    public function tasks()
    {
        return $this->hasMany('Task');
    }
}

Всё готово! Давайте получим все задачи пользователя с id = 1. Для этого нам понадобится всего 2 строчки кода.
$user = User::find(1);
$tasks = $user->tasks;

Впрочем, так как мы указали отношение с обеих сторон, если мы захотим получить пользователя, за которым закреплена данная задача, это также легко сделать.
$task = Task::find(1);
$user = $task->user;


4. Связь формы с моделью


Очень часто, будет полезным связать форму с моделью. Очевидный пример — когда Вы хотите изменить какую-то запись в базе. Связав форму с моделью, мы можем моментально заполнить поля формы данными из базы.
{{ Form::model($order) }}
    <div>
        {{ Form::label('title', 'Title:') }}
        {{ Form::text('title') }}
    </div>
 
    <div>
        {{ Form::label('description', 'Description:') }}
        {{ Form::textarea('description') }}
    </div>
{{ Form::close() }}

Так как форма связана с объектом модели Order, в полях будет отображаться данные из таблицы. Вот так просто!

5. Кеш запросов в базу


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

Давайте получим все вопросы из базы данных, но при этом закешируем запрос, так как вряд ли эта таблица будет часто изменяться.
$questions = Question::remember(60)->get();

Вот и всё! Теперь, в течение следующего часа, этот запрос будет храниться в кеше, и база будет нетронутой.

6. Композиторы шаблонов


Вы столкнётесь с ситуациями, когда несколько шаблонов потребуют некоторую переменную или кусок данных. Хороший пример этого — навигационное меню, которое отображает список тегов.
Чтобы контроллеры были с минимальным кодом, Laravel предлагает композиторы шаблонов (вьюшек), чтобы управлять такими вещами.
View::composer('layouts.nav', function($view)
{
    $view->with('tags', ['tag1', 'tag2']);
});

Использовав этот кусок кода, в любой момент, когда подгружен файл layouts/nav.blade.php, у него (у файла) будет доступ к переменной $tags.

7. Простая авторизация


Laravel использует очень простой подход к авторизации. Просто передайте массив данных, которые Вы, скорее всего, получили из формы логина, в Auth::attempt(). Если предоставленный массив соответствует тому, что сохранено в таблице users, пользователь моментально будет авторизован.
$user = [
    'email' => 'email',
    'password' => 'password'
];
 
if (Auth::attempt($user))
{
    // пользователь авторизован
}

Что если надо произвести выход при переходе, например на /logout URI?
Route::get('logout', function()
{
    Auth::logout();
     
    return Redirect::home();
});


8. Ресурсы


Работать RESTfully в Laravel также очень легко! Чтобы объявить контроллер ресурс, просто вызовите Route::resource() следующим образом.
Route::resource('orders', 'OrdersController');

Этот код зарегистрирует 8 роутов.

  • GET /orders
  • GET /orders/:order
  • GET /orders/create
  • GET /orders/:order/edit
  • POST /orders
  • PUT /orders/:order
  • PATCH /orders/:order
  • DELETE /orders/:order


Далее, OrdersController может быть сгенерирован из командной строки:

php artisan controller:make OrdersController

В этом контроллере, каждый метод будет соответствовать одному из роутов, описанных выше. Например, /orders вызовет метод index, /orders/create — метод create и так далее.

Теперь у нас есть необходимая сила, чтобы с легкостью строить RESTful приложения и API.

9. Шаблонизатор Blade


Да, PHP по натуре язык шаблонов, но он не стал слишком хорошим. Впрочем, ничего страшного. Laravel предлагает свой движок Blade, чтобы восполнить пробел. Просто назовите ваши шаблоны с расширением .blade.php, и они соответствующим образом будут парситься. Теперь мы можем делать следующее:
@if ($orders->count())
    <ul>
        @foreach($orders as $order)
            <li>{{ $order->title }}</li>
        @endforeach
    </ul>
@endif


10. Средства для тестирования


Так как Laravel использует Composer, мы тотчас имеет поддержку PHPUnit “из коробки”. Установите фреймворк и запустите phpunit из командной строки, чтобы протестировать.

В дополнение к этому Laravel предлагает некоторое количество хелперов для некоторых общих типов функциональных тестов

Давайте проверим, что домашняя страница возвращает код ответа 200.
public function test_home_page()
{
    $this->call('GET', '/');
    $this->assertResponseOk();
}

Или, может, мы хотим проверить, что, когда контактная форма отправлена на сервер, пользователь перенаправлен на домашнюю страницу с сообщением.
public function test_contact_page_redirects_user_to_home_page()
{
    $postData = [
        'name' => 'Joe Example',
        'email' => 'email-address',
        'message' => 'I love your website'
    ];
 
    $this->call('POST', '/contact', $postData);
 
    $this->assertRedirectedToRoute('home', null, ['flash_message']);
}


11. Компонент “Дистанционное управление”


Частью Laravel 4.1, который был выпущен в ноябре 2013, стала возможность написать консольную команду для Artisan, чтобы по SSH подключаться к серверу и выполнять любые действия. Просто используйте SSH фасад:
SSH::into('production')->run([
    'cd /var/www',
    'git pull origin master'
]);

В метод run() передайте массив команд, а Laravel займётся всем остальным! Теперь, так как есть смысл выполнять команды в качестве Artisan команд, вам всего лишь нужно выполнить php artisan command:make DeployCommand и в метод fire() написать нужный код для выполнения деплоя.

12. События


Laravel предлагает элегантную реализацию шаблона Observer, которую вы можете использовать где угодно в Вашем приложении. Подписывайтесь на нативные события, такие, как illuminate.query, или запускайте и слушайте свои собственные.

Продуманное использование событий даст вам много возможностей.
Event::listen('user.signUp', function()
{
    // выполните то, что надо,
    // когда пользователь регистрируется
});

Как и большинство вещей в Laravel, если вы предпочитаете указывать название класса, а не анонимную функцию, вы можете спокойно это сделать. Laravel разрулит всё, используя IoC контейнер.
Event::listen('user.signUp', 'UserEventHandler');


13. Покажите маршруты


image

Приложение растёт, и может стать тяжело посмотреть, какие роуты описаны. Особенно, если Вы не уделяли должного внимания файлу routes.php (например, излишния описания роутов).

Laravel предлагает удобную команду routes, которая покажет все зарегистрированные роуты, наряду с методами контроллеров, которые эти роуты вызывают.
php artisan routes


14. Очереди


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

Зачем заставлять пользователей ждать, пока произойдут эти события, если мы можем отправить выполняться эти события в бекграунде?
Queue::push('SignUpService', compact('user'));

Наверно, самое замечательное, это то, что Laravel превосходно работает с Iron.io “push” очередями. Это значит, что даже не имея опыта работы с воркерами или демонами, мы всё равно можем использовать очереди. Просто опишите роут с помощью команды php artisan queue:subscribe, и Iron.io будет отправлять данные на этот урл каждый раз, когда задача отправлена в очередь. А этот роут в свою очередь выполнит нужные действия.
image

15. Простая валидация


Когда нужна валидация, Laravel снова приходит нам на помощь! Используя класс Validator как нельзя просто. Просто передайте объект для валидации вместе с правилами в метод make, а Laravel сделает всё остальное.
$order = [
    'title' => 'Wii U',
    'description' => 'Game console from Nintendo'
];
 
$rules = [
    'title' => 'required',
    'description' => 'required'
];
 
$validator = Validator::make($order, $rules);
 
if ($validator->fails())
{
    var_dump($validator->messages()); // validation errors array
}



16. Tinker


image

Особенно, если вы используете Laravel в первый раз, может быть полезным повозиться с ядром. Команда tinker поможет с этим.

Tinker использует популярный компонент Boris.

$ php artisan tinker

> $order = Order::find(1);
> var_dump($order->toArray());
> array(...)


17. Миграции


Думайте о миграциях, как о контроле версий базы данных. В любой момент, вы можете “откатить” миграции, вернуть их, обновить, и так далее. Наверно, сила миграций таится в том, чтобы запушить приложение в продакшн и просто выполнить команду php artisan migrate, чтобы сконструировать базу данных.

Чтобы приготовить схема для новой таблицы users, мы можем выполнить:
php artisan migrate:make create_users_table

Команда сгененерирует файл миграции, который вы наполните так, как вам нужно. Как будете готовы, команда php artisan migrate создаст таблицу. Вот и всё! Нужно откатить изменения? Легко! php artisan migrate:rollback.

Вот пример таблица для таблицы ЧаВО.
public function up()
{
    Schema::create('faqs', function(Blueprint $table) {
        $table->integer('id', true);
        $table->text('question');
        $table->text('answer');
        $table->timestamps();
    });
}
 
public function down()
{
    Schema::drop('faqs');
}

Обратите внимание, что метод drop() выполняет обратные действия метода up(). Это то, что позволяет “откатить” миграцию. Не правда ли, что это намного легче, чем мучаться с чистым SQL?

18. Генераторы


Laravel предлагает некоторое количество генераторов. Но также есть пакет, который называется “Laravel 4 Generators”, и он зашел еще дальше. Он может генерировать ресурсы, файлы для наполнения базы, pivot таблицы и миграции.

В предыдущем пункте мы вынуждены были сами писать схему. Но используя пакет генераторов, мы можем выполнить команду:

php artisan generate:migration create_users_table --fields="username:string, password:string"


А генератор сделает всё остальное. С этой командой вы сможет подоготовить и создать новую таблицу в базе.
Laravel 4 Generators может быть установлен через Composer.

19. Консольные команды


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

Так как это распространенная задача, Laravel делает процесс создания команд наиболее простым.
php artisan command:make MyCustomCommand

Это команда сгенерирует нужный шаблон для Вашей кастомной команды. Далее, в только что созданном файле app/commands/MyCustomCommand.php, заполните название и описание.
protected $name = 'command:name';
protected $description = 'Command description.';

И, в методе fire() выполните нужные действия. После этого останется только зарегистрировать команду для Artisan, в файле app/start/artisan.php.
Artisan::add(new MyCustomCommand);

Хотите верьте, хотите нет, но это всё! Теперь вы можете вызывать эту команду из терминала.

20. Тестируйте фасады


Laravel много использует шаблон Фасад. Это даёт возможность использовать “статический” синтаксис, который, без сомнений, Вам понравится (Route::get(), Config::get(), и так далее), и при этом позволяет полностью тестировать их.

Так как “лежащий в основе” класс разруливается через IoC контейнер, мы легко можем подменить “нижние” классы с нашими тестовыми. Это позволяет нам делать следующее:
Validator::shouldReceive('make')->once();

Да, мы вызываем shouldReceive прямо из фасада. “За кулисами”, Laravel использует фреймворк Mockery. Это значит, что Вы абсолютно спокойно можете использовать фасады, и при этом тестировать абсолютно все куски кода.

21. Хелперы форм


Так как построение форм часто бывает громоздкой задачей, в дело вступает построитель форм в Laravel, чтобы облегчить этот процесс, а также использовать некоторые “особенности стиля”, связанные с конструированием форм. Вот несколько примеров:
{{ Form::open() }}
    {{ Form::text('name') }}
    {{ Form::textarea('bio') }}
    {{ Form::selectYear('dob', date('Y') - 80, date('Y')) }}
{{ Form::close() }}

Что насчёт задачи запоминания введенных данных при прошлой отправке формы? Laravel это делает автоматически!

22. IoC контейнер (Inverse of control)


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

Просто сделайте typehint ваших зависимостей в конструкторе, и при инициализации Laravel, используя PHP Reflection API, грамотно прочитает ваши подсказки и постарается вставить эти классы за вас.
public function __construct(MyDependency $thing)
{
    $this->thing = $thing;
}

Пока вы запрашиваете класс из IoC контейнера, разрешение зависимости произойдет автоматически.
$myClass = App::make('MyClass');

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

23. Окружения


Одно окружение может подойти для маленьких проектов. Для других проектов, несколько окружений — жизненно важно! Разработка, тестирование, продакшн. Всё это жизненно важно и каждое окружение требует своих настроек.

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

К счастью, Laravel снова облегчает нашу работу. Взгляните на файл bootstrap/start.php.

Там находится простая демонстрация настройки local окружения, которое базируется на hostname компьютера.
$env = $app->detectEnvironment(array(

	'local' => array('your-machine-name'),

));

В общем, это будет работать. Но предпочтительнее использовать переменные окружения для таких вещей. Не беспокойтесь, это легко сделать в Laravel! Просто передайте функцию в метод detectEnvironment.
$env = $app->detectEnvironment(function()
{
    return getenv('ENV_NAME') ?: 'local';
});

Теперь, если переменная окружения не задана (а для продакшна Вы её установите), окружение будет иметь значение local.

24. Простая настройка


Laravel опять таки использует очень простой подход к конфигурированию. Создайте в папке app/config папку с названием окружения, и любые файлы конфигурации в этой папке будут иметь приоритет над другими, при условии, что вы находитесь в этом окружении. Например, можно задать другой API ключ для dev окружения.
<?php // app/config/development/billing.php
 
return [
    'api_key' => 'your-development-mode-api-key'
];

Конфигурация полностью автоматическая. Просто вызовите метод Config::get(‘billing.api_key’) и Laravel сам определит из какого именно файла, считать это значение.

25. Обучаемость


Когда дело доходит до обучения, Laravel сообщество бесконечно хорошее, несмотря на маленький возраст. В течение чуть более года, были опубликованы полдюжины разных книг, связанные с разработкой на Laravel.
Автор оригинала: Jeffrey Way
Алексей Плеханов @alexsoft
карма
7,0
рейтинг 0,0
PHP Developer
Похожие публикации

Комментарии (190)

  • –1
    «Когда дело доходит до обучения, Laravel сообщество, несмотря на маленький возраст, бесконечно хорошее».
    «В течение чуть более года, полдюжины разных книг, связанных с разработкой на Laravel, были опубликованы».

    Издеваетесь?
    • +4
      Перечитал, осознал, что звучит не очень. Переписал. Спасибо!
    • +5
      Пожалуйста, давайте грамматику в личку.
      • +1
        Сложно было им в личку написать, чтобы грамматику в личке обсуждали?
        • +3
          Нет, не сложно.
          Просто ветка обсуждения уже стартовала, это раз. И к сведенью остальных, что бы не спамили ЛС-ками я написал публично, это два.
          • +1
            Скажем прямо, для этого текста никакой лички не хватит.
            «Переписанный» вариант оказался чуть ли не хуже изначального.
            Тут, правда, не в грамматике дело — переводчик попросту не знает языка, на который взялся переводить.
            Это-то и ужасно.
  • +4
    Да, PHP по натуре язык шаблонов, но он не стал слишком хорошим. Впрочем, ничего страшного. Laravel предлагает свой движок Blade, чтобы восполнить пробел. Просто назовите ваши шаблоны с расширением .blade.php, и они соответствующим образом будут парситься. Теперь мы можем делать следующее:
    @if ($orders->count())
        <ul>
            @foreach($orders as $order)
                <li>{{ $order->title }}</li>
            @endforeach
        </ul>
    @endif
    


    Да ладно, не стал хорошим? Чего недостаточно в пхп, что есть в шаблонизаторах? Кроме отсутствия нормальной подсветки синтаксиса, разве? Вот любят же люди все усложнять на пустом месте…
    <?php if ($orders->count()): ?>
        <ul>
            <?php foreach($orders as $order): ?>
                <li><?= $order->title ?></li>
            <?php endforeach; ?>
        </ul>
    <?php endif; ?>
    
    • +2
      Никто вам не запрещает в Laravel писать таким образом. Blade или Native — это дело вкуса!
    • +2
      Возьмем twig, у него приятный синтаксис, куча синтаксического сахара, а код ниже будет эквивалентен:
      <ul>
      {% for order in orders %}
          <li>{{order.title}}</li>
      {% else %}
      <li class="no-records">No records</li>
      {% endfor %}
      <ul>
      


      <ul>
      <?php if ($orders->count()): ?>
              <?php foreach($orders as $order): ?>
                  <li><?= htmlentities($order->title) ?></li>
              <?php endforeach; ?>
      <?php else: ?>
      <li class="no-records">No records</li>
      <?php endif; ?>
      </ul>
      


      А что говорить о том что он очень легко расширяется, добавить свои синтаксические конструкции очень просто, что делает его идеальным для интеграции в различные инструменты. И при том после компиляции шаблонов он все еще сохраняет скорость plain php.
      • +3
        У Twig покамест к тому же еще и поддержка IDE нормальная в отличие от Blade.
        • +1
          Для Sublime Text точно есть плагин. Для PHPStorm, вроде, тоже когда-то видел. Что еще надо?
          • 0
            дайте, пожалуйста, ссылку на PHPStorm плагин, я не нашёл.
            • +2
              Если не ошибаюсь, то вот. Но я лично его не пробовал еще.
              github.com/outofcontrol/Blade.tmbundle
              • 0
                Пробовал его. Возможно, надо его поковырять, но у меня он дает только подсветку. Даже фигурные скобки не дополняет в отличие от того же Twig. Ну, и PHP не распознает.
                • 0
                  Дык, это модуль под textmate, то есть, там реализована только подсветка синтаксиса. Но в шторме с этим бандлом все еще хуже — отваливается нормальная подсветка html и отваливается emmet.
              • 0
                В том смысле, что автодополнения нету.
        • +1
          это дело времени
      • +1
        В Blade тоже можно добавлять свои конструкции. Плюс в {{ }} можно использовать php.
    • +2
      Отсутствие автоэкранирования — уже достаточная причина, чтобы поставить на PHP как на шаблонизаторе крест.
      • +1
        В Laravel можно написать {{{ }}} и данные будут экранироваться.
        • +10
          нужно больше фигурных скобок!
        • +2
          Ну вот кстати это тоже неправильно. Автоэкранирование должно быть в дефолтном операторе, а всё остальное — опция.
          то есть, всё должно быть наоборот — в Laravel пишем {{{ }}} по дефолту, а можно написать {{ }}, если надо вывести данные как есть. А вообще определять вывод количеством скобочек — это мина замедленного действия
          Эта ерунда с подсчетом скобочек еще аукнется многочисленными XSS-ами.
          • 0
            Так в документации и написано:
            Пишем {{{ $name }}}, но если не хотите, чтобы срабатывало экранирование пишите {{ $name }}
            • +2
              мне больше нравится twig в этом плане:
              {{name | raw}}
              • 0
                Вот да — так совершенно отдельное усилие требуется для вывода «как есть». А скобочки считать — это фигня какая-то.
          • 0
            Как в Handlebars, да. У Тейлора была отличная возможность сделать будущие проекты безопаснее (хотя бы по части XSS), но он почему-то решил продолжить эту традицию и сделал все наоборот. Никак для «обратной совместимости» с v3…
            • 0
              Мне кажется как раз с обратной совместимостью Тейлор не заморачивался (и это хорошо).
              v4 во многом отличается от v3 (взять хотя бы полный переход на composer) в лучшею сторону.
              • 0
                Все верно, именно поэтому я взял «обратную совместимость» в кавычки — решение с Blade совершенно не понятно. Можно объяснить только тем, что Тейлор не видит с XSS каких-либо проблем, как до 4.2 не видел проблем с «зашифрованной» кукой laravel_remember.
        • 0
          А где тут автоэкранирование? Автоэкранирование — это когда работает без всяких скобок.
          • 0
            скобки — оператор вывода. А уже при выводе должно быть автоэкранирование. В twig-е есть синтаксическая конструкция для эскейпа блоков.
      • +1
        Может быть экранированные данные требуется выводить чаще, чем неэкранированные. Могу даже предположить, что иногда автоэкранирование это удобно.

        Тем не менее я бы считал автоэкранирование злом, если бы оно было по умолчанию PHP. Не должен шаблонизатор за меня решать надо или не надо экранировать.
        • +1
          Должен-должен.
          Это как в SQL — по умолчанию все передаваемые данные обрабатываются как строки. Любые исключения надо оговаривать специально. Иначе проблем не избежать
          • 0
            Хорошо иметь удобную возможность экранировать. Как это реализовано — дело другое. В классе View фреймворка, через функцию типа _e, как ниже в комментариях или еще как-то.

            Но <?= или echo/print не должны экранировать ничего.
          • +1
            Если должен, то как шаблонизатор узнает, каким именно образом надо экранировать строку? В контексте HTML-текста, HTML-атрибута или, к примеру, значения переменной в Javascript экранирование должно быть разным.
            • 0
              Вот — это очень дельный комментарий.
              В отличие от SQL, в котором неверное форматирование не приведет к проблемам в безопасности, а, в худшем случае — просто к ошибке приложения, в HTML не так всё просто.

              Я так думаю, что для дефолтного искейпинга надо применять более расширенный набор символов, чем тот, который используется в htmlspecialchars().
              • +1
                В таком случае «расширенным» экранированием будет «биться» весь вывод в контексте, отличном от конетекста по умолчанию. Я думаю, это не выход.

                Представьте, что HTML-текст по умолчанию экранируется через mysql_escape_string(). Или наоборот :-).
                • 0
                  Выхд-выход.
                  Это то, о чем я говорил выше. Безопасность важнее функциональности.
                  Всё правильно — выше описана, в сущности, идеальная модель разработки:
                  — по умолчанию всё форматируем наиболее безопасным способом
                  — для отличного контекста специально выставляем соответствующий контексту фильтр
                  — если разработчик зевнул и не выставил, то вывод бьётся
                  — не беда — когда разработчик это замечает, то просто добавляет соответствующий фильтр
                  • 0
                    Да, что-то в этом есть. Интересно было бы посмотреть на фильтр, который бы делал строку безопасной для любого из возможных контекстов, но при этом сохранял вывод максимально близким к оригиналу.
                    • 0
                      Ну вот, к сожалению, в HTML я не очень силён, моя идея происходит от обработки параметров в SQL, где это работает 100%.

                      Но вообще, если говорить о выводе в HTML, то если любые спецсимволы конвертировать в HTML-сущности, то проблемы близости к оригиналу быть не должно, вроде бы.
                      • 0
                        В том-то и беда, что HTML-шаблонах бывает не только HTML, но и Javascript. И к нему никакие HTML-сущности неприменимы. К примеру, для js-строки нужно экранировать символ перевода строки, а для HTML-строки — открывающую угловую скобку. Если по умолчанию мы будем делать и то, и то, то по умолчанию будут «биться» и js-строки (заменой < на "), и многострочные HTML-строки (заменой перевод строки на "\n").

                        В любом случае придётся указывать контекст — сразу же или до первого бага.
                        • 0
                          Парсер сожрал HTML-мнемонику для открывающей угловой скобки. Ну вы поняли.
                        • 0
                          Ну я ж об этом и говорю — надо. Надо указывать контекст.
                          Но нам важно, чтобы даже и без указания контекста, выводимая переменная если уж не принесла пользы — то хотя бы не навредила. Я об этом выше и говорил. С тем, что надо указывать контекст, никто не спорит.
                          • +1
                            Почему бы тогда не сделать указание контекста обязательным, если заведомо известно, что безопасное экранирование побьёт вывод? То есть, ситуация «без указания контекста» не имеет смысла в принципе.
                            • 0
                              Вообще, мысль интересная.
                              Но работать не будет.
                              Разработчики будут по умолчанию лепить контекст «HTML» и пропускать JS-инъекции.
                            • +1
                              если заведомо известно, что безопасное экранирование побьёт вывод?

                              Совсем даже не известно. Единственный случай, когда пострадает вывод — это описанный вами вывод в JS. Часто вы генерите JS в шаблоне? Если да — у вас ошибка в архитектуре. Если нет — автоэкрарование [HTML] для вас логичный выход. Для оного достаточно экранировать всего три символа, если совсем лень
                              < & "
                              • 0
                                Часто вы генерите JS в шаблоне? Если да — у вас ошибка в архитектуре.

                                Многие CMS позволяют вставлять JS в материалы/шаблоны в админке, что вы видите в этом плохого? Это позволяет не обращаться каждый раз к разработчику проекта для элементарных скриптовых вещей, а JS все еще является и скриптовым языком. И любой мало-мальски разбирающийся админ может сделать кнопочку с onclick. Именно поэтому:
                                Для оного достаточно экранировать всего три символа, если совсем лень
                                < & "

                                Не все так однозначно.
                                Во-первых, HTML документация не обязывает нас использовать именно кавычки. Появляются еще и апострофы, которые могут быть и частью аттрибута. Хотя вы наверное опять скажете что-то про архитектуру или code-style.
                                Во-вторых, аттрибуты событий, аттрибут style.
                                В-третьих, экранировать в input value что-то кроме кавычек тоже может быть не нужно.
                                В-четвертых, a href опять же как бы не вышло двойное экранирование амперсанда (urlencode и html).
                                • +1
                                  Многие CMS позволяют вставлять JS в материалы/шаблоны в админке, что вы видите в этом плохого?

                                  В этом — ничего, и это именно тот случай, когда нужно использовать сырой вывод. Но это один из немногих use case в сравнении с другими — вывод отдельный компонентов страницы (заголовок, имя, телефон и т.д и т.п).

                                  Что будет, если вы напишете JS-код в WYSIWYG-редакторе (WordPress например)? Правильно, он будет выведен как текст. Точно так же вы указываете шаблонизатору, что вы знаете что делаете и что это сырой HTML, который вы прямо интерполируете в тело страницы.

                                  Во-первых, HTML документация не обязывает нас использовать именно кавычки.

                                  Не обязывает, зато 100% предотвращает XSS во всякого рода . Экономия — 5 байт на каждую кавычку, что несерьёзно.

                                  Появляются еще и апострофы, которые могут быть и частью аттрибута.

                                  … и они тоже должны быть экранированы.

                                  Во-вторых, аттрибуты событий, аттрибут style.

                                  … в которых они также экранируются, так как являются обычными атрибутами тега.

                                  В-четвертых, a href опять же как бы не вышло двойное экранирование амперсанда (urlencode и html).

                                  URL-encoding и HTML никоим образом не пересекаются. Если амперсанд — часть значения переменной (типа ?field=value) — он будет заменён на %26. Если часть URL (?smth&smth) — будет заменён на & что есть верное поведение:
                                  <a href="?a&amp;b">
                                  


                                  Возьмите W3C validator, вбейте туда:
                                  <!DOCTYPE html>
                                  <html><body>
                                  <a href="a.html?b&c">
                                  </body></html>
                                  


                                  И получите:
                                   & did not start a character reference. (& probably should have been escaped as &.)
                                  
    • 0
      У нейтив ПХП есть один очень серёьзный недостаток — невозможно сделать нормальный авто-искейпинг.
      А это, пожалуй, в шаблонизаторе главное.

      «приятный синтаксис», «экономия целых двух символов на оператор» — это всё ерунда. А вот собственный оператор вывода, которым можно управлять — это очень, очень важно.

      Ведь на самом деле в нейтив должно быть что-то вроде
      <li><?=_e($order->title) ?></li>
      

      — а с таким довеском идея как-то уже меркнет.

      В какой-то мере можно рассматривать {{ $order->title }} как аналог плейсхолдера в SQL. А <?=$order->title ?>, соответственно — как прямую интерполяцию, со всеми вытекающими.
      • 0
        Это очень просто решается:
        function _e($content ='') {
         ... эскейпинг, транслейт и все все все.
        }
        
        • +1
          Ну вот это «очень легко решается» и проблема.
          Кто-то стал решать, но не зная технологии, насовал в _e() кучу бесполензного мусора.
          Кто-то вообще не знал, что что-то решать надо.
          Кто-то знал, да забыл.

          В общем — типичный «пхп-стайл», и типичный же результат, ЕВПОЧЯ.

          Я не зря привел аналогию с SQL — там эти баталии на тему «легко решается» уже (надеюсь) отгремели, и все согласились наконец-то, что ручное экранирование должно быть забыто как страшный сон.
          • +1
            Возможно стоит поднять этот вопрос в core-комьюнити, о возможности дефолтного фильтра в echo|print* функциях.
            • 0
              Это очень скоропалительный комментарий, не проходит проверку практикой.
              Как раз в PHP, как языке общего назначения, так делать ни в коем случае нельзя.
              Ведь проблема касается только одной ипостаси, РНР-как-шаблонизатора.

              правда, для <?=?> оно с одной стороны, идеально подходит, но с другой — настолько ломать обратную совместимость — я думаю, невозможно.
              • +1
                Возможность не подразумевает переопределение поведения по-умолчанию, можно реализовать это так-же как и с ошибками, что нибудь вроде register_output_filter
      • +1
        Не понимаю откуда берется мысль, что в нативном PHP нельзя сделать авто-escape? Я не за этот вид шаблонизации, но ведь способов чуть меньше миллиона?

        function a($vars)
        {
            foreach($vars as $key => &$value)
            {
                $value = ЛЮБОЙ_ЭСКЕЙПИНГ($value);
            }
            extract $vars;
            unset($vars);
            require 'template.phtml';
        }
        


        $vars = get_defined_vars();
        foreach($vars as $key => $value)
        {
             $$key = ЛЮБОЙ_ЭСКЕЙПИНГ($value);
        }
        

        И так далее?
        • 0
          Вот он, самый простой шаблонизатор :D
        • +1
          Беда в том, что как раз в приведённом выше примере мы имеем объект $order, и это очень показательно.
          А объекты — штука тонкая. К моменту попытки автоискейпинга объект может ещё не знать, что у него такое свойство есть.
          Или вообще его не иметь.

          Ну то есть да — если заставить разработчика передавать в шаблон только скаляры и массивы — это работает.
          Но, увы, я еще не встречал ни одного, который бы не хотел передать в шаблон объект $user и уже в шаблоне обращаться к его свойствам/методам. Хотя сам считаю это порочной практикой.
          • +1
            В чем проблема вообще не понимаю)

            	class Templater
            	{
            		public function render($file, $vars)
            		{
            			$vars = $this->evalVars($vars);
            			extract($vars);
            			unset($vars);
            			require $file;			
            		}
            		protected function evalVars($vars)
            		{
            			$export_vars = array();
            			foreach($vars as $key => $var)
            			{
            				switch(gettype($var))
            				{
            					case 'object':
            						$export_vars = array_merge($export_vars, array( $key => $this->evalVars(get_object_vars($var))));
            					break;
            					case 'array':
            						$export_vars = array_merge($export_vars, array( $key => $this->evalVars($var) ));
            					break;
            					default:
            						$export_vars = array_merge($export_vars, array($key => $this->prepareVar($var) ));
            				}
            			}
            			return $export_vars;
            		}
            		protected function prepareVar($var)
            		{
            			return $var . 'ЧТО_УГОДНО';
            		}
            	}
            	$templater = new Templater;
            	$order = (object)(array('id' => 1, 'amount' => 5));
            	$vars = array('order'=>$order);	
            	$templater->render('template.phtml',$vars);
            
            • +1
              А если вам одну переменную НЕ НАДО эскейпить?
              • 0
                Ну это-то как раз просто.
                Переменные в шаблон в любом случае должны передаваться какой-нибудь tmpl::set() — и вот у этой функции должен быть дополнительный параметр, который, скажем, делает переменную свойством специального объекта, или помещает в отдельный список — способов много.
                • 0
                  То есть передаем 2 набора параметров в шаблон: ескейпенные и неэскейпенные?
                  • 0
                    Я думаю, в хорошем приложении наборов должно быть больше.
                    «неэскейпенные» — это, на самом деле, частный случай, один из фильтров.
                    Но фильтров может быть много — urlencode, JSON к примеру.
                    • +2
                      Короче, в погоне за конями в вакууме вы понаделали кучу костылей. Не говоря уже о том, что обрабатывать данные, если мы еще не знаем, понадобятся они или нет, плохая практика. Испульзуйте нормальный шаблонизатор, жить станет намного лучше. Кроме ескейпинга там еще много разных плюшек. Я тоже раньше хейтерил шаблонизаторы, потом попробовал Твиг и теперь не могу соскочить.
                      • 0
                        Не понял, при чем здесь противопоставление «нейтив — шаблонизаторы».
                        Очевидно же, что разговор здесь идет о шаблонизаторах вообще, любых.
                        Все описанные выше принципы относятся к «шаблонизаторам» в той же самой мере. В них точно так же должна быть поддержка фильтров, которая должна иметь ту или иную внутреннюю реализацию. Вот варианты реализации фильтров мы и обсуждаем здесь.

                        На момент вызова tmpl::set() мы вообще не знаем, какой конкретно синтаксис в шаблонизаторе используется — нейтив или самопал. И не должны знать, по-хорошему.
                        • 0
                          Начиналось все с холивара «Нейтив — шаблонизаторы» =) habrahabr.ru/post/222453/#comment_7576125

                          По теме: переменная должна эскейпиться, если не указано иное. Эскейпить (или накладывать какой угодно фильтр) мы должны в момент вывода пременной на экран из соображений быстродействия. Чистый PHP такое, насколько я знаю, не умеет.
                      • 0
                        Я тупанул выше.
                        В «шаблонизаторах» мы как раз имеем inline-форматирование, когда фильтр накладывается уже перед самым выводом, и прописывается прямо в шаблоне. Так что да — в этом смысле шаблонизатор удобнее нейтива — о чем я и говорил, начиная эту ветку.

                        Но проблема с «конями», ей-богу — не самая большая у нейтива. Наложить фильтр эксплицитно — не проблема. Главная проблема — всё-таки, накладывание дефолтного фильтра.
                        • 0
                          Так в чем проблема то? Вы же прочитали это?
                          habrahabr.ru/post/222453/#comment_7576933
                          • 0
                            Прочитать мало, надо руками пощупать.
                            Чем я сейчас и занимаюсь. Это ж ведь не языком чесать — тут время нужно :)
              • 0
                Указать мы это должны где-то в любом случае, скорее всего в шаблоне.
                class TemplateValue
                {
                	private $_value;
                	public function __construct($value)
                	{
                		$this->_value = $value;
                	}
                	public function __toString()
                	{
                		return $this->escapeValue($this->_value);
                	}
                	public function getValue()
                	{
                		return $this->_value;
                	}
                	public function escapeValue($value)
                	{
                		return stripslashes(htmlentities($value));
                	}
                }
                
                function NOTESCAPE($var)
                {
                	return $var->getValue();
                }
                
                $vars =array('a'=> '<div>tratata</div>');
                foreach($vars as &$var)
                {
                	$var = new TemplateValue($var);
                }
                extract($vars);
                var_dump((string)$a);
                var_dump(NOTESCAPE($a));
                
                
            • +1
              Он имел ввиду магические свойства, кажется
            • 0
              Ну, я писал выше — в современных объектах далеко не все свойства доступны через public переменные, которые можно вытянуть через get_object_vars().
              Всякий lazy loading, getters и прочая магия сильно затрудняют такой прямолинейный подход.
              К тому же, возвращать данные может не только свойство, но и метод.

              Но сам по себе подход хорош. Я пытался решить задачу таким же примерно наскоком, но обломался, по причинам, изложенным выше.
              И вообще, очень приятно видеть ответы с кодом. Очень люблю такой подход!
              • +1
                Ну, я писал выше — в современных объектах далеко не все свойства доступны через public переменные, которые можно вытянуть через get_object_vars().
                Всякий lazy loading, getters и прочая магия сильно затрудняют такой прямолинейный подход.
                К тому же, возвращать данные может не только свойство, но и метод.

                	class Order
                	{		
                		private $_fields=array();
                		public function setName($value)
                		{
                			$this->_fields['name'] = $value;
                		}
                		public function __get($name)
                		{
                			if (!isset($this->_fields[$name]))
                			{
                				throw new \Exception('Invalid field ' . $name);
                			}
                			return $this->_fields[$name];
                		}
                	}
                
                	trait TemplateVarPreparing
                	{
                		protected function prepareVar($var)
                		{
                			return $var . 'ЧТО_УГОДНО';
                		}
                	}
                	class TemplateProxyObject
                	{		
                		use TemplateVarPreparing;
                		protected $_object;
                		public function __construct($object)
                		{
                			$this->_object = $object;
                		}
                		public function __call($name, $args)
                		{
                			return $this->prepareVar( call_user_func_array($this->_object->$name,$args) );
                		}
                		public function __get($name)
                		{
                			return $this->prepareVar($this->_object->$name);
                		}
                	}
                	
                	class Templater
                	{
                		use TemplateVarPreparing;		
                		public function render($file, $vars)
                		{
                			$vars = $this->evalVars($vars);
                			extract($vars);
                			unset($vars);
                			
                			var_dump($order->name);
                			
                			//require $file;			
                		}
                		protected function evalVars($vars)
                		{
                			$export_vars = array();
                			foreach($vars as $key => $var)
                			{
                				switch(gettype($var))
                				{
                					case 'object':
                						$export_vars = array_merge($export_vars, array( $key => new TemplateProxyObject($var) ));
                					break;
                					case 'array':
                						$export_vars = array_merge($export_vars, array( $key => $this->evalVars($var) ));
                					break;
                					default:
                						$export_vars = array_merge($export_vars, array($key => $this->prepareVar($var) ));
                				}
                			}
                			return $export_vars;
                		}
                	}
                	$templater = new Templater;
                	$order = new Order;
                	$order->setName('Katya');
                	$vars = array('order'=>$order);	
                	$templater->render('template.phtml',$vars);
                
                • 0
                  Ага, оно работает, и даже с методами (надо поправить опечатку в вызове call_user_func_array()).
                  Но беда в том, что принцип рекурсии, который распространяется на остальные типы, не распространяется на объекты. И если со свойством ещё можно как-то извернуться, то с методом, который возвращает массив — уже, кажется, никак… :(

                  А у меня, в моей практической задаче, есть, к примеру, у юзера свойство $geo, которое само объект, который не инициализирован изначально, а тянется только когда вызван. В общем, я пока бросил эту затею.
                  • +1
                    Ну и все то же самое, нужно только соединить мой пример отсюда с ProxyObject и добавить такой же рекурсивный проход в класс TemplateProxyObject при получении значения свойства.

                    Т.е. на входе у нас массив из чего угодно (объекты со свойствами-объектами, которые сами могут содержать объекты).
                    Дальше мы заменяем все объекты первого уровня на ProxyObject, при вызове свойства которого, если оно — объект. то опять же заменяем его на ProxyObject, если массив то заменяем и экранируем все элементы массива, если значение — просто экранируем и так сколько угодно рекурсивно и с поддержкой lazy-loading.

                    PHP очень гибок в этом плане, с помощью магических методов __call, __get, __toString мы можем реализовать что угодно в нашей шаблонизаторе, а взамен получим огромную библиотеку функций PHP для работы со строками, массивами и т.д. внутри шаблона.
                    Повторю, я не за такой способ шаблонизации, но меня вообще не устраивают любые шаблонизаторы, вставляющие в HTML новый язык. И если уж выбирать, то проще использовать уже известный и многофункциональный нативный PHP.
                    • 0
                      Проблема с не типизированным ProxyObject все равно есть( По-крайней мере я не знаю, как красиво ее решить.
                      Если проксированные объекты в шаблоне могут передаваться, например, во View Helper, который использует type-hinting, либо ему необходима проверка на интерфейс исходного объекта, возникают большие сложности.

                      Решается без костылей только созданием всех возможных проксей, которые реализуют те же интерфейсы, что и проксируемые объекты (вобщем-то классический паттерн и подразумевает следование интерфейсам проксируемого объекта).
                      • 0
                        Ну ведь мы говорим о своем каком-то шаблонизаторе, ведь так? Тогда что мешает запросить у анонимного прокси-объекта информацию об интерфейсе настоящего?

                        	class ProxyObject
                        	{
                        		protected $_object;
                                public function __construct($object)
                                {
                                    $this->_object = $object;
                                }		
                        		public function getObject()
                        		{
                        			return $this->_object;
                        		}
                        	}
                        	Interface IModel
                        	{
                        		
                        	}
                        	class Order implements IModel
                        	{
                        		
                        	}
                        	$order = new Order;
                        	$proxy_object = new ProxyObject($order);
                        	var_dump(($proxy_object->getObject() instanceof IModel));
                        


                        Или конкретизируйте пример, пожалуйста.
                        • 0
                          Для собственного шаблонизатора и зависимых от него напрямую хелперов, конечно можно и так, но лишает возможности использовать, к примеру, сторонние хелперы, которые ничего не знают о ProxyObject конкретного шаблонизатора.
                          Вобщем, для коробочного решения, работающего с любыми хелперами «без допилов» вряд ли годится, но для индивидуального решения — вполне себе работает.
                          • 0
                            Хм, а что это за хелперы в представлении, которые знают об интерфейсах модели?
                            • 0
                              Ну, к примеру, хелперы для рендеринга форм. Контроллер может отдавать в шаблон View Model формы и ее элементов, а хелперы могут помогать эти view model рендерить в зависимости от интерфейса view model.
                              • 0
                                Но что тогда мешает подменить ProxyObject на реальный объект при вызове стороннего хелпера?

                                	function ВЫЗОВХЕЛПЕРА($proxy_object)
                                	{
                                		СТОРОННИЙ_ХЕЛПЕР($proxy_object->getObject());
                                	}
                                


                                а в шаблоне

                                <div>....<?=ВЫЗОВХЕЛПЕРА($order)?>..</div>
                                
                                • 0
                                  тоже ничего не мешает, разве что внутреннее ощущение нарастающего оверхеда и что ради одной возможности (хоть и важной) автоматически экранировать строки на вывод, приходится так интересно развлекаться:)
                                  Поэтому нельзя уж прямо с чистым сердцем сказать, что это легко реализуемо «нативно».
                                  Было бы действительно круто, если бы php сделали возможность регить что-то вроде output_filter, как кто-то из хабровчан выше заметил.
                                  • 0
                                    Ну уже мы разговариваем далеко не просто про экранирование — экранирование было в моем первом примере в 4 строчках. А это уже поддержка многовложенных объектов с магическими свойства, сторонние хелперы и т.д. И собственно разговор о том, что сторонние шаблонизаторы могут больше, с чем я согласиться пока не могу.

                                    Было бы действительно круто, если бы php сделали возможность регить что-то вроде output_filter, как кто-то из хабровчан выше заметил.

                                    Не представляю как это могло бы быть реализовано. Т.е. регистрируем функцию на вывод именно «echo ». Но опять же вопрос с экранированием, если мы вызовем функцию NOTESCAPE, то она вернет нам скларяное значение, которое опять же должно будет экранироваться или что, при ее вызове отключать output_filter?
      • 0
        Я думаю, в случае, когда мы собираем строку из кусков, одни из которых должны интерпретироваться, а другие нет, причём собираем не через какой-то API, а руками (читай, делаем конкатенацию), никакого автоэкранирования быть не должно. В тех же плейсхолдерах SQL мы указываем тип значения, которое мы ожидаем получить из переменной, и соотв. образом эти значения добавляем в запрос.

        По-моему, экранирование (или указание типа укранирования) должно быть явным и осознанным. А неэкранированная вставка переменной в вывод по умолчанию должна считаться потенциальной уязвимостью до тех пор, пока явно не указано, что это значение — «безопасное».
    • –1
      Ужас начинается, когда появляется что-то типа:
      <a href="<?= $page->url ?>">...</a>
      От такого обилия вложенных угловых скобок глаза начинает колбасить.

      Плюс чистый PHP не позволяет удобно использовать всякие полезные вещи, типа наследования шаблонов, автоматического экранирования и т.п.
      • +1
        От такого обилия вложенных угловых скобок глаза начинает колбасить.

        Это проблема не PHP, а смешения HTML-разметки и кода, которое присуще любым шаблонизаторам подобного типа. Поэтому я за чистые шаблонизаторы, которые не суют ничего в HTML.

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

        Про экранирования я писала выше, а с наследованием какие проблемы?
      • +2
        Ну, это уже вкусовщина. У кого-то от угловых рябит, у кого-то — от фигурных.

        А по поводу остальных фич — надо различать РНР как язык разметки шаблонов и Шаблонизатор как модуль приложения. Чистый PHP не означает «чисто include()» как обработчик шаблонов — такой обработчик все равно пишется специально. и в нем уже можно реализовать и наследование и многие другие вкусности
    • 0
      Единственный весомый аргумент, который я когда-либо слышал в пользу шаблонизаторов — это лишить нерадивых джуниоров возможности писать бизнес логику и запросы в БД из вьюшек.
      • 0
        а так же принуждать экранировать данные при выводе, проверки в циклах, и кучу всяких мелочей.
  • +13
    Очень пафосный текст статьи… Особенно
    Laravel Тэйлора Отвелла возник из пепла, чтобы стать любимцем общества
    Не тянет статья на Tips and Tricks, скорее очередная пиар статья с кратким описанием фич.
    • 0
      Это перевод статьи Jeffrey Way. Поэтому я и оставил всё, как есть.
      • +2
        Я и не говорю чего-то в вашу сторону. Я просто не понимаю всей этой шумихи вокруг Laravel, это как-то по детски.
        • 0
          Хороший же фреймворк. Или не так?
          • +2
            Относительно большинства — да, но не лучший. Хотя множество решений в нем действительно хорошо, например тамошний IoC контейнер. Концепция AR мне же очень не нравится, мне больше по душе data-mapper в лице Doctrine. Фасады так же не ок, как бы проблем они не создают, и даже не ломают особо принципы ООП, но как-то не красиво. Но все это субъективизм.

            Просто даже если брать эту статью, она практической пользы как таковой не несет, только рекламирует то что можно в документации почитать. Никаких разборов когда этот фреймворк выгодно использовать а когда нет, как правильно делать (в документации частенько проскакивают штуки, которые противоречат бест практис, в целях упрощения материала как я понимаю).
        • –2
          Ну, учитывая, что большинство пользователей похапешечки не вышли из ясельного возраста, то им такая реклама как раз.
          Те же, которые вышли, или сами понимают сильные и слабые стороны движка безо всякой рекламы, либо вообще пилят большой портал на собственном софте, и им поп-фреймворки перпендикулярны.

          А так-то да — ORM и роутенг преподносятся прям как исключительные заслуги Лярвы, и чуть фанфары из каждого абзаца не играют.
  • +9
    Вот только не Laravel вдохнул новую жизнь в PHP, а всетаки Fabien с Symfony2 и уже потом пришел Composer, во многом благодаря Fabien-у сообщество PHP продвинулась вперед, он попробовал принести PHP в мир enterprise решений.
    • +2
      А по мне так дело обстоит так:
      Сначала в PHP вдохнули жизнь WordPress, Joomla, Drupal и т.д. На этом создали (и создается) огромное число небольших сайтов, шаблонных интернет-магазинов и т.д.
      Затем ВКонтакте, Википедия, Facebook и др. показали, что на PHP можно создавать ведущие интернет-ресурсы в мире. И вот это вдохнуло уже в PHP такую жизнь, что не останавливается до сих пор, а о framework'ах никто, кроме использующих их разработчиках не знает.
      И новичок, стоящий перед выбором будет сравнивать не Laravel, Symphony, ASP, Play или Django, а результаты:
      1. На PHP написано подавляющее большинство сайтов.
      2. История про написание 2 крупнейших соцсетей двумя людьми (Дуров и Цукерберг). Причем, судя по kPHP ВКонтакте вообще не использует ООП.
      3. На PHP можно написать сайт из 1 строчки (чего не скажешь о любом framework'е).

      И вот только потом, уже для продвинутых разработчиков в дело вмешиваются framework'и и доказывают, что на PHP можно писать и крупные проекты не одному человеку со всеми плюшками, в том числе в корпоративной сфере (однако, там где нужна надежность выбирают все еще Java).
      Так что я бы так сильно не стала преувеличивать значимость framework'ов в истории PHP.
      • 0
        Вы правы, я как раз говорил о последнем пункте.
      • +2
        Речь идет о событиях, которые просходят уже после описываемых.

        Интерес к РНР в мире стабильно падает уже несколько лет, и никакой ФБ этому не помеха.
        Сообщества закрываются, трафик на ресурсах падает. На Хабре частота статей по пхп упала в несколько раз. На Стаковерфлоу, скажем, бешеный трафик поддерживается исключительно за счет бангалорских бедняков, для которых писать на пхп — это альтернатива ручной разборке океанских лайнеров на металлолом. И пхп там — исключительно процедурная лапша из прошлого века (которая, кстати, на мой взгляд, и есть главный двигатель популярности). И в начале статьи упоминается именно этот факт.

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

        • +1
          Вы сами себе противоречите, после FB — был бешенный рост, сейчас развиваются framework'и и ужасное падение популярности. Получается как раз таки, что нужны новые facebook'и, а не новые framework'и.
          Но это только если судить по хабру и stackoverflow. Не представляю, что можно спросить о PHP на stackoverflow при работе над серьезным проектом. Разве что — об extensions (и то если нет C-специалистов в команде).
          На Стаковерфлоу, скажем, бешеный трафик поддерживается исключительно за счет бангалорских бедняков, для которых писать на пхп — это альтернатива ручной разборке океанских лайнеров на металлолом.

          А это дело не в PHP, просто в мире уже давно война не эффективности используемых ЯП, а умении грамотно организовать бизнес-процесс.
          Если в 1998 Грэм Пол хвастался преимуществами Lisp в конкурентной борьбе, то сейчас количество разработчиков, серверов и инвестиций решают любые вопросы.
          • 0
            Ну, на моей памяти из недавнего — например, об особенностях работы mysqli_multi_query(). Документация очень невнятная а результаты собственных экспериментов очень легко мисинтрпретировать.
            Или вот я ещё спрашивал про удивительный баг — все функции для работы с файлами как одна молча отказывались работать с HTTP враппером. Ответ, правда, я получил уже после того, как написал воркараунд, но тем не менее.

            После ФБ не было бешеного роста. Вот характерная картинка — www.google.ru/trends/explore#q=%2Fm%2F060kv
            Она, хоть, и в собственных гуглопопугаях, но тренд совершенно очевиден.
            Взрывной рост интереса к ПХП начался в начале века, когда он занял абсолютно пустую нишу, да ещё и предложил нулевой порог вхождения. Но уже к середине первой декады пошел на спад. А в середине второй, я, как активный участник многих ПХП-сообществ, невооруженным глазом вижу снижение интереса и трафика.

            Фреймворки развиваются на фоне падения популярности.
            Новичок читает статьи типа этвудовской «The PHP Singularity» с двойным гвоздодёром на картинке и выбирает что помоднее. Благо, выбор у него есть.
            Бангалорские неприкасаемые не пишут энтерпрайз. Они побираются на одеске за еду. И, сколько в них денег ни влей, «Войну и мир» они не напечатают, увы
            А организатор бизнес-процессов тоже анализирует тренды и выбирает наиболее, на его взгляд, перспективные.
            Вокруг Друпала и Уордпресса уже сложились эффективные экосистемы, в которых 99% пользователей устраивает базовый функционал, а запросы остальных удовлетворяет имеющееся сообщество разработчиков — и особого прорыва с той стороны не видно.

            В общем, падение популярности РНР в последние годы — это факт. И фреймворки — это действительно второе дыхание языка.
            • 0
              www.google.ru/trends/explore#q=%2Fm%2F060kv%2C%20%2Fm%2F07sbkfb%2C%20%2Fm%2F06ff5%2C%20%2Fm%2F0jgqg%2C%20Objective-C&cmpt=q

              Судя по всему динамика трендов практически идентичная для всех языков
            • +1
              Взрывной рост интереса к ПХП начался в начале века, когда он занял абсолютно пустую нишу

              Неправда ваша. Он был прямым конкурентом Perl.
              • –1
                С тобой дискутировать бесполезно, но один раз объяснить можно — именно наличие перла на поляне и означало абсолютно пустую нишу.
                • +1
                  Абсолютно пустую нишу означало бы наличие «на поляне» исключительно компилируемых и т. п. языков. Главным преимуществом перед ними что Perl, что PHP было то, что создать сайт можно было тупо залив по ftp текстовые файлы, которые интерпретировались на лету, любые изменения сразу же отображались без всяких линковок и сборок. В пользу PHP сыграло два важных фактора (вернее один, но с двумя аудиториями) — низкий порог входа для тех, кто никогда не программировал, и низкий порог входа для программистов знакомых с Си и прочими си-образными языками.
            • 0
              Отвечу сразу всем.
              Имхо, падение популярности PHP связано с растущей популярностью ЯП для написания мобильных приложений.
              • +1
                Подождите, но ведь PHP для бэкенда и мобильным приложениям нужен бэкенд, почему бы не расти популярности вместе с ростом потребностей.
      • +1
        Сначала был wordpress, это был пожалуй самый мощьный популяризатор php. А до joomla были всякие mambo и прочие. До версии 5 php воспринимать как полноценный язык для web было смешно, а вот уже 5,3 можно говорить о нем серьезно.

        facebook напомню создавался одним разработчиком по началу, как и vk. Там не особо много думалось о выборе технологий, просто писалось на том, что знали разработчики.

        А по поводу новичков — это не особо интересно. Сейчас куча новичков с подачи интернетов идут в python/ruby, и плодят свой говнокод еще и на них. Не только на php можно писать сайты ничего не зная, благо время идет и все развивается.

        А помимо мелких сайтов есть еще решения для бизнеса, и там фреймворки это хорошо. Да и на базе фреймворков пишут всякие cms-ки.
  • +8
    У меня ощущение, что я читаю машинный перевод.
  • –4
    Зачем писать на пхп если можно писать на руби или хотя бы питоне? Мы не в северной корее, свобода выбора же есть.
    • 0
      Потому что свобода выбора, bro
      • +5
        ОМГ, на работе пишу и на php, и на ruby. Чего там такого у этого руби, не пойму.

        ЗЫ Промахнулся веткой
        • –1
          У руби есть отшлифованая экосистема библиотек и практик, тестирования и красота кода. У пхп нет вообще ничего, кроме популярности.
          Абсолютное большинство стартапов прототипируются на рельсах — это тоже о чем то говорит.
          • +3
            >> У руби есть отшлифованая экосистема библиотек и практик

            Настолько отшлифованная, что для работы с excel приходится юзать аж 2 разные библиотеки: roo — для парсинга, axlsx — для генерации документов.

            >> тестирования

            В PHP с этим не хуже.

            >> красота кода

            Это вообще никогда не было серьезным критерием полезности языка. Кроме того, красиво ruby выглядит только на хелловорлдах. Когда пишешь сложную логику, портянка, что там, что там, факт. Рассказы, будто бы на ruby кода в 2 раза меньше — наглое вранье.

            >> У пхп нет вообще ничего, кроме популярности.

            На PHP сейчас все есть даже для ентерпрайза.

            >> Абсолютное большинство стартапов прототипируются на рельсах — это тоже о чем то говорит.

            Кроме прототипирования ни на что эти рельсы больше и не годятся.

            При всем при этом я не хочу сказать, что PHP > ruby. Средняя температура по больнице одинаковая. Кому что нравится.
            • 0
              >В PHP с этим не хуже.
              нет, ну вот в тестировании нет ничего лучше руби экосистемы. это колыбель TDD

              >Кроме прототипирования ни на что эти рельсы больше и не годятся.
              да. Они медленные. Но ведь прототипирование это важнее для стартапа, переписать можно потом?
              • +2
                это колыбель TDD

                Пруф можно? Емнип, колыбелью TDD считается Smalltalk. Из мэйнстрима — то ли Java, то ли C#, но скорее Java. Ruby — колыбель BDD, но TDD он позаимствовал.
            • 0
              >> Мы не в северной корее, свобода выбора же есть

              Ну и говорить в контексте ruby я такое бы не стал. Нет в ruby никакой свободы. Вы либо пИшите в стиле ruby, либо вообще не пИшите на ruby. В PHP же реализовано целая куча всяких разных паттернов и практик.
              • 0
                Совершенно верно, технически вам никто не мешает создать новые библиотеки. Их будут использовать если они будут *лучше*. Так уж вышло что рельсы и стиль руби *достаточно хороши*. Когда меняешь рубистов им не нужно вникать в архитектуру, в отличии от ПХП, они могут сразу начать писать код, модели/контроллеры устроены одинаково во всех рельс приложениях.

                В пхп же такое разнообразие фреймворков потому что они все недостаточно хороши, и каждую команду тянет написать еще один.
                • +1
                  >> Когда меняешь рубистов…
                  С таким же успехом можно менять Yii-стов или Zend-истов, CakePHP-истов или Laravel-истов.

                  >> в пхп же такое разнообразие фреймворков…
                  Ruby тоже имеет парочку аналогов.
                • 0
                  Ну это болезнь php-сообщества, велосипедостроение. Вообще если брать более мение серьезные фреймворки, типа Symfony/zend, да тот же laravel, который развивается внутри экосистемы symfony, то такой проблемы нету. А вот штуки типа yii/cakephp/ci и т.д. — тут да. Хотя, по сути не так проблемно спускаться с уровня повыше на уровень пониже, просто не приятно.

                  Словом, это вопрос личных предпочтений. Кому-то что-то не нравится, может от неопытности, может от незнания, а может и вовсе от упертости и максимализма, и начинаются велосипеды.
          • +3
            красота кода

            Я конечно понимаю, что о вкусах не спорят. Но от синтаксиса Ruby у меня вынесло мозг, красотой этот язык мой язык (сорри за каламбур) не повернется никогда назвать. Не хочу быть неправильно понятым: я не говорю, что Ruby — говно, нет. Я осознаю его мощь, и в конце концов, именно с RoR'а слизаны многие фишки Laravel'а. Но лично я писать на Ruby не собираюсь.
    • +8
      Зачем писать на руби или питоне, если можно писать на пхп?
      • –9
        Очевидно, потому что пхп говно?
        • 0
          Чем PHP говно? Тем, что до нас было написано куча говно сайтиков с брешами в безопасности? И теперь никто не признает PHP?
          Или чем?

          p.s. никаких наездов, просто вопрос)
        • 0
          Все говно, жизнь боль.
  • +2
    Профессионально работаю на PHP примерно с 2007 года. Начинал с pure, потом был Zend. Видел кратце Yii — ужаснулся. А щас просто фанатею от Laravel. На нем все делается настолько просто и быстро, причем вполне красиво. Уже поднял 3 сайта на нем. Никогда еще не получал большего удовольствия от кодинга, чем щас на Laravel. На все задачи, которые у нас возникают, быстро находим решения на Laravel. Это мое краткое впечатление от фреймворка, подробнее здесь писать не буду, так как очередной холивар на тему «Какой фреймворк лучше» не нужен.
    • 0
      У меня опыт поменьше: сначала работал с проприетарным фреймворком (на котором розетка написана), а сейчас на работе — Yii, но все свои проекты делаю на Laravel! Впечатления такие же!
    • 0
      Попробуйте Symfony 2
      • 0
        Пробовал! Хорош, но Laravel мне больше нравится.
  • +1
    Пожалуй, вброшу немного на вентилятор.

    >> $orders = Order::orderBy('release_date', 'desc')->get();

    Я на Propel одним Enter-ом такое на phpstorm пишу, а тут надо поле руками писать.

    >> $order->title = 'Xbox One';

    На серьезном проекте с кучей бизнес-логики без геттеров-сеттеров далеко не уедешь. Чем этот Eloquent лучше, чем какой-нибудь бородатый Kohana ORM? Синтаксис один в один, как и все проблемы.

    >> php artisan migrate:make create_users_table

    2014 год, а все руками миграции пишем. ОК.

    >> {{ Form::open() }}
    >> {{ Form::text('name') }}
    >> {{ Form::textarea('bio') }}
    >> {{ Form::selectYear('dob', date('Y') — 80, date('Y')) }}
    >> {{ Form::close() }}

    Верстальщики за такое на кол посадят.

    >> $questions = Question::remember(60)->get();

    Зачем ORM лишний раз дергать для кэширования?

    >> IoC контейнер (Inverse of control)

    Ну и толку от этого контейнера, если весь фреймворк в статике написан.
    • 0
      Ну и толку от этого контейнера, если весь фреймворк в статике написан.

      Здешняя «статика» называется фасадами, а в основе их — обычные нестатичные классы. Соотв-но эти самые низлежащие классы инстанциируются через IoC. Любой компонент Лараравела заменяется на собственный простым перебиндиванием в контейнере.
    • +1
      На серьезном проекте с кучей бизнес-логики без геттеров-сеттеров далеко не уедешь. Чем этот Eloquent лучше, чем какой-нибудь бородатый Kohana ORM? Синтаксис один в один, как и все проблемы.

      Никто не мешает усложнить логику сеттеров/геттеров. Можно например написать getTitleAttribute(), который будет вызван при попытке доступа к $model->title;

      Верстальщики за такое на кол посадят.

      Вообще-то PHP-дэвелопер пишет блэйдовский шаблон ПОСЛЕ того, как его сверстали верстальщики.

      2014 год, а все руками миграции пишем. ОК.

      Частично можно автоматизировать, передав дополнительные параметры артизану.

      Одним словом, данная статья — не исчерпывающий сборник рецептов и документация Laravel, а лишь в какой-то степени агитация, как уже говорили выше в комментах.
      • +1
        Никто не мешает усложнить логику сеттеров/геттеров. Можно например написать getTitleAttribute(), который будет вызван при попытке доступа к $model->title;

        … а потом искать, где в коде этот метод вызывается напрямую, где косвенно. Знаю, проходили. Эта проблема, кстати, в других частях L4 еще глубже, так как есть мнеого способов сделать одно и то же — например:
        В isFillable мы проверяем несколько разных способов, которыми может быть обработано массовое назначение. Сначала мы смотрим, установлена ли модель как unguarded, и если это так, то разрешаем назначение. Далее мы проверяем, находится ли атрибут в массиве fillable, тогда мы разрешаем назначение еще раз. Затем вызывается isGuarded, который проверяет, находится ли ключ в массиве guarded, или guarded содержит знак звездочки array('*') (который ставится по умолчанию), тогда мы не разрешаем массовое назначение. Наконец, если fillable пустой, мы возвращаем true, если ключ не начинается с подчеркивания, которое используется для скрытых атрибутов, как это принято и в Rails.

        Если находится unfillable-ключ, то мы проверяем, является ли модель totallyGuarded. По сути это значит, что если fillable пустой и guarded содержит знак * (по умолчанию), тогда возникает исключение MassAssignmentException. Это значит, что если вы не измените свойства fillable или guarded, то при попытке вызвать fill будет возникать исключение MassAssignmentExceptions.
        . Все это сильно затрудняет поддержку проекта.

        Вообще-то PHP-дэвелопер пишет блэйдовский шаблон ПОСЛЕ того, как его сверстали верстальщики.

        … который, конечно, больше никогда не меняется. Такой дзэн.
        • 0
          … который, конечно, больше никогда не меняется. Такой дзэн.

          Как уже писал в ответ товарищу ниже: что, программисты настолько тупые, что не смогут найти различия в верстке?
          • 0
            Есть кучи примеров компаний, в котором очень жестко ограничиваются сферы работ. Нормальная практика не давать бэкэнд разработчику верстать, так как для этого есть отдельный человек который сделает все быстрее. Даже для фронтэнда частенько бывает такое жесткое разделение. Все зависит от процессов в компании.
            • 0
              Ну дык речь не идет о том, что разработчик будет верстать. Верстку делает отдельный человек. Тут спор о том, что верстальщик помимо верстки еще и шаблон должен подстроить под бэк-энд, с чем я категорически не согласен.
              • 0
                именно. верстальщик должен лазать в шаблоны. backend-разработчик напротив не должен. Но это возможно только если разработчик полностью отвязал логику от представления, что в принципе нам и нужно.
                • 0
                  Это красиво звучит в идеальной ситуации. Но зачастую в шаблонах тоже присутствует программерская логика: данные то от бэкэнда получены, но вот вывести их все равно нужно по-особенному. Простейший пример, когда нужно вывести элементы массива в зав-ти от четности-нечетности его нахождения в массиве. Верстальщику придется в какой-то степени уметь программировать, что не вписывается в идеологию полного разделения задач. Ему придется писать foreach, какой-бы шаблонизатор не использовался. Делать проверку на четность и т.д. Или более сложный пример: выводить записи допустим по три на строку. Нужно вести счетчик записей, на каждом третьем закрывать очередной див и открывать новый. В игру входят пускай и простые, но алгоритмы, что накладывает на плечи верстальщика дополнительные требования. А чем меньше требований к кандидату — тем проще его найти.
                  Вот есть забубенный какой-то верстальщик, и умеет он допустим делать шаблоны для како-нибудь Twig'а допустим. Но так сложилось, что пришлось уволится с текущей конторы. Ищет другую работу: а там либо какой-нибудь Smarty используют, либо вообще все на Zend Framework, но политика компании придерживается этого идеала: верстальщик должен писать шаблоны. В итоге верстальщик должен познать еще и шаблонизацию в стиле Zend и т.п. Ситуация гораздо проще, когда верстальщик делает только то, что вложено в это слово — только верстает. Вот покупаете вы детали конструктора Лего допустим. Вы получили детали, аналог верстки. Теперь вам нужно из них построить домик, аналог фронт-энда. В это дело тоже должен вмешиваться производитель Лего, помогая вам из деталей собрать то, что нужно? Или купили болванку DVD пустую. Вы будете обращаться к производителю, чтобы на нее что-то записать? Сверстанный макет — эта та же болванка, те же детали, из которых можно сделать что нужно. И делать это должен программист. Полное разделение задач: дизайнер предоставляет дизайн, верстальщик предоставляет верстку-болванку с Lorem ipsum'ами, программист прикручивает это к написанному им самим бэк-энду. Дизайнер не знает, как верстать. Верстальщик не знает, как рисовать и программировать. Программист не знает как рисовать и верстать. Но в команде они работают как конвейер, не малозначимое изобретение, если не ошибаюсь, Форда. Можно много аналогий проводить.
                  У меня большой опыт разработки на PHP, но с вариантом, когда верстальщик сам делает шаблоны, сталкивался всего один раз. Но тут было несколько но: 1) верстальщик четко знал, что писаться все будет на Zend'е; 2) он сам бывший программист. Но даже в этом случае мы теряли много времени на «состыковку»: какие переменные я сэтчу во вьюхи и каков их формат. Когда он не мог достучаться до меня, он сам лез в код и смотрел, а иногда даже что-то правил под удобный ему формат. И это еще хорошо, что основной функционал у меня был готов до верстки. Иначе бы ему приходилось ждать меня, пока я реализую фишку, чтобы он мог ее отобразить. Он сам «настроил» мой код под использование его шаблонов, так как он знал, как назовет файл лэйаута и другие под-шаблоны. Это не дело.
                  На текущей работе все так, как я считаю и должно быть. Дизайнер --> верстальщик --> программист. Дизайнер нарисовал, отдал, свободен. Верстальщик сверстал, отдал, свободен. А вот программер уже над этим трудится. Верстальщик может отдать верстку до того, как функционал будет готов. Дизайнер же не подстраивается под верстальщика. Так и верстальщик не подстраивается под программиста.
                  Резюмируя: верстальщик не должен уметь программировать и разбираться серверных языках программирования (не считая желательного для любого верстальщика знания JS); верстальщик не должен разбираться в шаблонизаторах. Он должен просто уметь верстать.
                  Но это тоже «крайний случай». Конечно неплохо, когда верстальщик «шарит», но возводить это в обязанность неправильно с моей точки зрения. И со мной согласились все мои друзья и коллеги, кстати.
                  Другими словами, возлагать на верстальщика обязанность подгонять шаблон под бэк-энд — непрактично.
                  • +1
                    Вы действительно считаете что верстальщики должны быть тупыми и не способными применить банальные проверки аля i % 2 == 0? Да и «верстать» сейчас это не так то просто.

                    На самом деле все эти кейсы решаются стилями. Прошли уже те времена когда нужно было руками все это прописывать. Есть псевдоселекторы аля nth-child которые позволяют задавать над какими элементами по порядку нужно производить какие-то действия, над 2n или 2n+1 ( если мы про четность и нечетность).

                    Если человек не тупой, синтаскис шаблонизатора он освоит довольно быстро. Не считаю это сильным ограничением, а вот плюсом в резюме такого верстальщика это будет точно.

                    По поводу вашего опыта:
                    1) верстальщик должен сидеть рядышком, вопросы все эти решаются до того как кто-либо из вас приступит к работе. Так что «что как стыковать» — такого вопроса вообще не должно быть. Если верстальщику чего-то не хватает — в шаблонизаторах есть фильтры. Он реквестит такой-то фильтр, вы его реализуете. Все в рамках тех-процессов. Править же данные, которые вы пробрасываете из контроллера во вьюху что бы поменять представление — это уже странно.

                    2) Верстальщик должен знать хотя бы js на начальном уровне, в его распоряжении не только html+css, но и мириады препроцессоров, например less/sass, или autoprefixer. Так же средства сборки типа grunt/gulp, ну и js иногда нужно впилить простенький. Если вы работаете в рамках какого-то фреймворка, то для такой задачи верстальщику хватит одного проекта что бы въехать как ведется разработка. Да и не забывайте, в идеальном мире, при нормальных процессах, вся команда сидит рядом и что-то спросить не должно занимать много времени. Если у вас проблемы с коммуникацией в команде, это ваши проблемы и только. Верстальщик не должен лесть в код, это да, но и вы должны работать в команде при таком подходе. Я так понимаю что у вас все это было в рамках удаленки или сидели в разных концах офиса.

                    То что вы описываете это очень не продуктивная методика. Для небольших проектов норм, но если проект в активной стадии разработки, то обычно это дизайнер нарисовал кусок — верстка + параллельно имплементация функционала — релиз — цикл повторяется в зависимости от фидбэка. Так что меняются стили и дизайн почти всегда, и тратить время на интеграцию верстки это глупо и не эффективно.
                  • +1
                    Ваши рассуждения сводятся к тому, что есть много разных шаблонизаторов и верстальщику трудно знать их все. Однако и браузеров много (по-крайней мере пока еще) и исходные форматы от дизайнера могут быть разные.
                    И совсем не факт, что степень различия между Photoshop и Illustrator больше чем между Twig и Smarty.
                    Вы говорите, что верстальщику придется программировать, однако не отказываете ему в знании JS. А ведь по сути программирование во всех шаблонизаторах сводится к FOREACH и IF. Это настолько элементарная логика, что думаю под силу любому. Все остальное, модификаторы, наследование и т.д. настолько же декларативно, насколько декларативен сам HTML и уж тем более CSS.
                    Да, проблема интерфейса шаблона (передаваемые переменные) есть, но она касается в целом подхода, а не конкретно разделения программист-верстальщик. А в вашем примере мы с тем же успехом можем сказать, что дизайнер захотел изменить кнопочку, а верстальщик ему не ответил и тот сам полез в HTML-CSS менять ее. Это вообще вопрос организации взаимодействия.

                    Корректными, я считаю, в контексте проблемы были бы рассуждения, кого выгоднее иметь компании — верстальщика-шаблонизаторщика или программиста-шаблонизаторщика, а на спрос уже родятся и предложения.
                    Верстальщик-шаблонизаторщик:
                    1. Позволяет менять дизайн/структуру страницы без дополнительных участников процесса.
                    2. Позволяет менять логику на уровне шаблона без вмешательства бэкенд-программиста.
                    3. Но зависит от переданных переменных, что собственно не относится к представлению, а значит не должно меняться часто. Также тут помогут различные lazy-loading и другие способы обращения к заранее не переданным данным.
                    Программист-шаблонизаторщик:
                    1. Позволяет изменить передаваемые данные и? Сообщить верстальщику, что можно переделывать дизайн под новые данные, затем получить сверстанную заново страницу, заново накидать на нее весь шаблон.
                    2. При изменении дизайна, пункт 1.
                    3. Логику в шаблоне может менять так же независимо от других участников процесса.

                    Я делаю вывод, что компании выгоден верстальщик-шаблонизаторщик, а лень изучить новый шаблонизатор это вообще не разговор.
                    • 0
                      Тогда ответьте товарищу выше на его коммент:
                      >> {{ Form::open() }}
                      >> {{ Form::text('name') }}
                      >> {{ Form::textarea('bio') }}
                      >> {{ Form::selectYear('dob', date('Y') — 80, date('Y')) }}
                      >> {{ Form::close() }}

                      Верстальщики за такое на кол посадят.

                      Значит ему приходилось работать с «тупыми» верстальщиками =) Ибо тут все очень даже просто.
                      • 0
                        С виду несложно, согласна. Но все при том же условии, что верстальщик независим от программиста и бэкенда и занимается представлением, а не моделью. Здесь же, насколько я понимаю — весь синтаксис нужен именно для модели, а не для представления? В таком случае, это явное нарушение инкапсуляции шаблона и вообще всего смысла MVC. И, как следствие, бессмысленность изучения таких команд (по сути логики бэкенда) для шаблонизаторщика.

                        Да, наверное, когда один человек занимается на проекте всем — это быстро и удобно, не могу сказать — давно уже даже если делаю все одна, разделяю внутри себя эти вещи.
                        • +1
                          Готов признать, что по крайней мере частично вы меня переубедили. Как никак, а в споре рождается истина :)
                          Здесь же Form — это можно сказать helper для генерации элементов форм. Очень удобная штука. К примеру нужно отобразить модель $user с полями допустим nickname и email:
                          {{ Form::model($user) }} {{ Form::text('nickname') }} {{ Form::email('email') }} {{ Form::close() }}

                          То есть сгенерятся соотв-но инпуты с проставленными $user->nickname и $user->email. Приятной фишкой также будет, если в бэк-энде будет сделано перенаправление на эту страницу с ->withInput(), то в эти поля проставятся ранее введенные пользователем данные (ситуация, когда пользователь ввел некорректные данные, и бэк-энд вернул пользователя на эту страницу — он увидит введенные ранее данные). То есть сам шаблон лишен логики всякой дополнительной. Все делается в этом хэлпере.

                          P.S. Хабр странно отформатировал код х_Х
                          • 0
                            Ради чего писать все это в шаблоне? Почему просто не создать класс этой формы (или хотя бы тупо массив) и сгенерировать из него html-код?
                            $form = array('nickname' => 'text',....);
                            $view_form = Form::render($form);
                            

                            Можно сказать, ради того, чтобы поля можно было бы вставлять в шаблон отдельно в нужное место, но они могут быть так же другого дизайна (пример с bootstrap). Да и шаблон формы можно описать отдельно один раз, а не вставлять эту кучу каждый раз.
                            • 0
                              Вообще-то рендерить html-форму не в шаблоне — это уже не MVC.
                              Если вдруг нужно повторение одной и той же формы — делается под-шаблон с ней и инклюдится где нужно.
                              • 0
                                MVC — это разделение бизнес-логики от представления. Формы описания любой из частей при этом могут быть как декларативными (шаблон), так и императивными (алгоритмы).
                                Мы можем описать модель декларативно, контроллер — императивно, представление тоже императивно.

                                Например, в Windows Forms формы описываются так (пишу на память):
                                TextBox textbox1 = new TextBox();
                                textbox1.width=100;
                                textbox1.backgroundColor = 165452463;
                                form1.controls.add(textbox1);
                                


                                Т.е. мы не ограничены способами описания представления — это может быть код, автогенерация, шаблон.

                                А шаблоны и HTML/XML-разметку используют потому, что их визуально проще воспринимать. Когда смотришь на картинку — она представляется единым целым, так же и HTML.

                                И код в представлении — это нормальное, даже обычное дело, главное не смешивать его с разметкой.
                                • 0
                                  Не владею подобными терминами, так как универ бросил после первого курса, а теорией никогда не увлекался.
                                  В любом случае, я не понимаю, чем не устраивает запись в шаблоне:
                                  {{ Form::model($user) }}
                                      {{ Form::text('nickname') }}
                                      {{ Form::email('email') }}
                                  {{ Form::close() }}
                                  

                                  Или смущают вызовы методов объекта Form? Так подстановка PHP-переменной в шаблоне — это тоже код.
                                  P.S. Windows Forms — это уже прошлый век. Щас все на WPF.
                                  • 0
                                    Покажите как бы вы сделали дропдаун с выбором связанных сущностей (например принадлежность айтема к категории).
                                    • 0
                                      Немного не понял задачи. Вообще дропдаун посредством Form делается так:
                                      {{ Form::select('name', $items) }}
                                      

                                      Если же имелось ввиду еще дополнительный дропдаун, содержимое которого зависит от выбора в первом, то тут без JS понятное дело не обойтись, и это уже задача не шаблонизатора, а JS.
                                      • 0
                                        Ну вот да, просто частенько доводилось видеть (в контексте работы с yii), что разработчики прямо там делают выборки. В шаблонах. Просто потому что можно.

                                        Как например это делается в Symfony:

                                        у нас есть класс Goods с полем category, которое является связью с классом Category.
                                        У нас есть GoodsFormType, в котором происходит определение полей формы
                                        $formBuiler->add('category');
                                        

                                        форм билдер исходя из метаданных объекта понимает. что у нас там связанные сущности и сам выбирает тип (можно и самому указать, но обычно не нужно). По умолчанию для нашей связи он создаст дропдаут без возможности выбирать несколько вариантов. Можно в настройках явно указать что бы это был список чекбоксов/радиобаттанов, или еще что. А можно свой контрол для этого сделать.

                                        Затем в контроллере у вас нечто вроде такого:
                                        $form = new GoodsFormType();
                                        if ('POST' === $request->getMethod()) {
                                            // я давно с ним не работал, так что уже точно не помню API
                                            // могут быть не точности
                                            if ($form->bindRequest($request)->isValid()) {
                                                // форма валидна, можем делать что-то с данными
                                                // данные уже будут в форме уже готовых к использованию объектов
                                                // в нашем случае getData вернет энтити Goods
                                                $data = $form->getData();
                                                // ...
                                            }
                                        
                                            // предположим что у нашего экшена уже стоит аннотация что делать с данными
                                            // а именно отрендрить темплейт
                                            return ['form' => $form->getView()];
                                        }
                                        


                                        и в шаблонах у нас будет такое:
                                        <form action="#" method="post" {{ form_enctype(form) }}>
                                            {{ form_widget(form}}
                                            <input type="submit" />
                                        </form>
                                        


                                        То есть у нас есть промежуточный FormView который отвечает за представление нашей формы. Причем все на композиции объектов, так что если вы хотите по одному поля отображать со своими настройками — никто вас в этом не ограничивает. А уже как должны обрабатываться данные формы, конвертация их из model в view и прочее, это работа дата трансформеров и относится к логике приложения, потому не следует этого делать прямо в шаблонах.
                                        • 0
                                          Twig есть и в Laravel и прикрутить его можно куда угодно, даже doctrine можно прикрутить к Laravel и вообще можно свой фреймворк собрать из композера, блекджека и twig…
                                          Cпорить о лаконичности или не лаконичности from builder, я бы стал в последнюю очередь при сравнении фреймворков, особенно, учитывая то, что половина морды всё равно пишется на JS и от формбилдера нет никакого проку.
                      • 0
                        Вот так:
                        <form action="#" method="post" {{ form_enctype(form) }}>
                            {{ form_widget(form.name, {'attr': {'class': 'foo'}}) }}
                            {{ form_widget(form.bio) }}
                            {{ form_widget(form.dob) }}
                            <input type="submit" />
                        </form>
                        

                        сами виджеты можно переопределять, можно полностью управлять представлением формы и все такое прочее. А уже саму форму, тип контролов и прочее — все это задается в formType. Но это я все конечно в контексте Symfony Forms. Для небольших проектов этот компонент кажется слегка избыточным, хотя не встречал в итоге более гибкого и мощного компонента для работы с формами.
    • –1
      >> Я на Propel одним Enter-ом такое на phpstorm пишу, а тут надо поле руками писать.
      Можно сделать сниппет в PHPStorm, и проблема решена.

      >> Зачем ORM лишний раз дергать для кэширования?
      А откуда предлагаете получать данные?
      • +1
        >> Можно сделать сниппет в PHPStorm, и проблема решена.

        Я не понял, каким образом проблема решается, если суть в автокомплите. На каждый возможный запрос свой сниппет писать?

        >> А откуда предлагаете получать данные?

        Стандартная теплая ламповая обертка:
        if (!$data = $cache->get('data'))
        {
        $data = Question::all();
        $cache->set('data', $data->serialize(), 3600);
        }

        1 раз взяли из ORM, потом 60 минут дергаем только кеш и не напрягаем ORM. Знаете ли, за простым и милым запросом Question::remember(60)->get(); может скрываться 2k исполняемых строк.
        • 0
          А никто и не заставляет юзать возможности кэша через ORM. Можно точно также занести данные в кэш посредством фасада Cache и так же их получать.
        • 0
          >> Я не понял, каким образом проблема решается, если суть в автокомплите. На каждый возможный запрос свой сниппет писать?
          Автокомплит — вопрос времени, я думаю. А сниппеты можно написать на часто используемые, а остальные — руками написать.

          >> Стандартная теплая ламповая обертка:
          Во-первых, можно посмотреть реализацию, и убедиться, что нет там 2k строк.
          Если надо, можно такую же ламповую обертку написать самому:
          if (!Cache::has('data'))
          {
              Cache::put('data', Question::all(), 3600);
          }
          


          А можно и вот так
          $data = Cache::remember('data', 3600, function() {
              return Question::all();
          });
          


          и 60 минут дергаем только кеш.
          • +1
            >> Во-первых, можно посмотреть реализацию, и убедиться, что нет там 2k строк.

            Очевидно, проверка на кеш происходит в методе get(). Т.е. если мы напишем 5-этажный запрос, весь этот билдер запросов сработает, и 2k строк вполне себе наберется.
    • 0
      а сколько enter'ов у вас занимает описание на xml структур ваших таблиц?
      • 0
        Зато миграции не нужно руками писать, и метаданные всегда точные, по ним можно формы генерить и все такое.
        • 0
          кто-то пишет руками тоны xml, а кто-то красивые миграции.
        • 0
          И никогда не было проблем с такими формами, автоматически сгенерированными по метаданным? Типо как какая-то мелочь может не устроить, где нужно чуть подкастомизировать и т.д.?
      • 0
        Начиная с некоторого момента Ctrl+C и Ctrl+V
  • +1
    >> Никто не мешает усложнить логику сеттеров/геттеров

    Это опять руками надо делать?

    >> Вообще-то PHP-дэвелопер пишет блэйдовский шаблон ПОСЛЕ того, как его сверстали верстальщики.

    Да что вы такое говорите. Нормальный верстальщик должен сам писать шаблон. Как он будет его модифицировать потом?
    Даже если у вас это делается по-другому, когда вам скажут, что хотят {{ Form::text('name') }} в стиле Pure (http://purecss.io/), а {{ Form::textarea('bio') }} в стиле horizontal form из bootstrap, все изъяны смешивания бизнес-логики и представления вылезут наружу.

    >> Частично можно автоматизировать, передав дополнительные параметры артизану.

    Что не отменяет того, что это все руками делается. При каждой миграции лезем в мануал смотреть синтаксис команды, а если какие-то сложные изменения с индексами и прочим, вешаемся. В нормальных ORM (Propel и Doctrine) схема в том или ином виде хранится в коде. После любого изменения схемы вычисляем diff и накатываем на БД. Все, вообще никаких миграций не пишем в принципе.

    • 0
      Это опять руками надо делать?

      А что, есть фреймворки, которые научились читать мысли разраба и писать код автоматически? Допустим, есть. Сколько усилий будет потрачено, чтобы научить такой фрейм писать код немного по-другому, если он вдруг не полностью устраивает?

      Да что вы такое говорите. Нормальный верстальщик должен сам писать шаблон.

      И знать программирование и то, как реализованы скрипты программистами? То есть он должен знать, какую переменную сэтит во вьюху программист, чтобы (даже допустим он владеет такими конструкциями, как if и for(each)) ее выводить? Ну бред же. У нас все четко: дизайнер практически ничего не знает о верстке и программировании, верстальщик не умеет рисовать и не умеет программировать на PHP (но знает болеменее JS, на уровне, достаточном для реализации некоторых динамических вещей типо слайдов, например), а программист не умеет рисовать, но знает основы HTML/CSS (ну само программирование понятно), чтобы в нужных местах в верстке, в которой полностью отсутствует «интеллект», наполнить ее смыслом. Нормальный верстальщик верстает так, что сам HTML переделывать не придется, только CSS. Если же меняется сама структура страницы — нужно быть абсолютно неадекватным программистом, чтобы не найти различия.

      В нормальных ORM (Propel и Doctrine)

      Propel ни разу не юзал, ничего не могу сказать. А вот Доктрина — кромешный ужас. На серьезном энтерпрайзе все раздувается к чертям собачьим. Нагрузки нереальные. Есть опыт написания солидной аппликухи для сети отелей Ramada с использованием Доктрины, никому не пожелаю таких страданий. К тому же что-то смотрю, здешние программисты совсем ленивые. Я тоже ленивый, но не настолько, чтобы поленится написать схему таблиц, будь то на листочке, непосредственно в БД, или в миграции.
      • 0
        Подписываюсь под каждым предложением!
      • +1
        >> А что, есть фреймворки, которые научились читать мысли разраба и писать код автоматически? Допустим, есть. Сколько усилий будет потрачено, чтобы научить такой фрейм писать код немного по-другому, если он вдруг не полностью устраивает?

        Сгенерировать getTitle() и setTitle() — прямо великая задача. Вроде бы пустяковая вещь, зато такая полезная.

        >> Нормальный верстальщик верстает так, что сам HTML переделывать не придется, только CSS

        И что, шаблоны прямо никогда не меняются? Это вы в каком-то зазеркальном мире живете.

        Но, собственно, мы несколько отошли от изначальной темы разговора. Вопрос остается открытым: «хотят {{ Form::text('name') }} в стиле Pure (http://purecss.io/), а {{ Form::textarea('bio') }} в стиле horizontal form из bootstrap». Каким образом такое делается?

        >> На серьезном энтерпрайзе все раздувается к чертям собачьим

        Если на Доктрине раздувается к чертям, то на Eloquent все превратится вообще в кучу неподдерживаемой лапши. Впрочем, я сам не юзаю доктрину и пишу на Propel.

        >> К тому же что-то смотрю, здешние программисты совсем ленивые

        Здешние программисты не ленивые, а эффективные, потому что вместо того, чтобы тратить время на бесполезные миграции, они пишут бизнес-логику.
        • –1
          Если не знаете толком Laravel, то смысл спорить?

          Сгенерировать getTitle() и setTitle() — прямо великая задача. Вроде бы пустяковая вещь, зато такая полезная.

          В Eloquent даже не нужно писать сеттеры и геттеры для простого получения значения из БД.

          И что, шаблоны прямо никогда не меняются? Это вы в каком-то зазеркальном мире живете.

          Я живу в реальном мире, и писал, что если появятся правки в верстке, программисту не составит труда найти различия. Тем более если верстальщик сидит рядом и сам покажет, что изменилось. Верстальщик не должен даже знать, на чем написана серверная часть. Я не прав? Что ж, тогда грош цена верстальщику, который не знает PHP, Ruby и Питон к примеру. Он же должен знать, как построены скрипты (на каком языке), знать, какой шаблонизатор используется и т.д.

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

          И именно поэтому я использую Laravel, потому что все что нужно есть либо в нем из коробки, либо в виде готового пакета расширения. И by the way, я не пользуюсь миграциями. А создаю таблицу сразу в БД. Или это тоже за меня должен сделать какой-то робот, прочитав мои мысли, или сосканировав мои схемы с бумажки?
          • 0
            >> В Eloquent даже не нужно писать сеттеры и геттеры для простого получения значения из БД.

            Я не понял, что вы хотите сказать. Я и парень выше вам хотят сказать, что $article->title — очень-очень плохо, должно быть $article->getTitle(), чтобы это было расширяемо.

            >> Он же должен знать… какой шаблонизатор используется

            PHP, Ruby и Питон никто не заставляет учить, но знать шаблонизатор должен

            >> И by the way, я не пользуюсь миграциями. А создаю таблицу сразу в БД

            А это значит, что вы не пользуетесь системами деплоймента, дальше даже обсуждать нечего.
            • 0
              >> должно быть $article->getTitle(), чтобы это было расширяемо.
              достаточно просто в модели определить метод getTitleAttribute($value) и делать со значением что угодно
            • 0
              Я не понял, что вы хотите сказать. Я и парень выше вам хотят сказать, что $article->title — очень-очень плохо, должно быть $article->getTitle(), чтобы это было расширяемо.

              Если нужно получить просто данные из БД, то можно получить через $article->title. В этом случае отработает магический метод Eloquent, возвращая значение из внутреннего массива $attributes. Если все таки нужно расширить, что бывает нечасто, то пишется public function getTitleAttribute() {… }; что также имеет «магическую» подоплеку. При этом получение этого поля никак не изменится, это будет по прежнему $article->title;

              PHP, Ruby и Питон никто не заставляет учить, но знать шаблонизатор должен

              Ну допустим языки знать не должен, что я еще оспорю. Он должен знать все существующие шаблонизаторы? Не говоря о том, что у каждого языка он свой. Главный Программист Вася владеет N шаблонизаторами. Очередной проект он решает реализовать с использованием шаблонизатора k. Верстальщик должен подстраиваться под программиста, и тоже должен знать этот шаблонизатор… Как то много ложится на плечи верстальщика. Идем далее, насчет языков программирования. Вот ВЕРСТАЛЬЩИКУ нужно вывести на странице допустим список новостей. Перед ним встает вопрос: а в какой переменной в шаблоне доступен этот список? Выхода два: либо спросить у программиста, тратя время обоих, либо самому залезьт в код и посмотреть, тратя свое время, но все равно нуждаясь в навыках программирования на этом языке. Далее, допустим список новостей — это массив объектов. Верстальщик должен знать, как 1) обойти этот массив (но допустим он суперски знает все шаблонизаторы и знает как это сделать) 2) как получить значение поля объекта… хм а массив объектов ли это? Или массив ассоциативных массивов? Пожалуй надо опять дернуть программиста и узнать. Либо залезть в код и посмотреть. Допустим объекты. В PHP это будет "->", где-то еще это будет точка. Одним словом без знаний языка не обойтись. И что же? Теперь верстальщик никуда не годен, если он не знает языки. А на кой нам тогда вообще программист, если и верстальщик умеет писать код?

              А это значит, что вы не пользуетесь системами деплоймента, дальше даже обсуждать нечего.

              Это типо в вас сыграло чувство собственного достоинства? У меня не самые сложные проекты, и хосчу их на обычном shared-хостинге, заливаю файлы посредством FTP, а базу правлю посредством инкрементных SQL-файлов. Или мне обязательно строить из себя продвинутого программиста, используя автоматизированные деплои? На работе мы не юзаем Laravel — у нас свой корпоративный фреймворк. Там мы деплоим автоматом, если что.
              Насчет «не использую миграции» я на самом деле погорячился. Просто в большинстве случаев мне быстрее занести изменения в базу напрямую, чем писать новую миграцию. Но при этом я знаю, как работают миграции в Ларавеле и использовал их по-началу. Вполне себе норм. Так и не понял реплику одного человека выше, что мол писать отдельную миграцию для каждого изменения — плохо. Мол «нужно лезть в доку», чтобы посмотреть синтаксис. Уважаемый, а изучая новую технологию, вы тоже без доков обходитесь? Вся инфа приходит во сне сама собой? Ну раз залез в доку, два, обычный человек к этому времени уже запомнит, что нужно. Исходя из этой логики можно сказать, что PHP — гавно, ибо я иногда забываю порядок аргументов какой-нибудь функции, и «приходится всякий раз лезть в доку, чтобы посмотреть синтаксис» (вместо PHP подставить whatever). А как быть с миграциями, которые требуют допустим изменить какое-то поле во всей таблице? Ваш diff схемы тут как-то поможет? Придется писать отдельный скрипт, который все это сделает. А в Ларике это будет просто новая миграция. Случай конечно в моей практике не встречался, но всякое может быть.
              • 0
                >>… можно получить через $article->title. В этом случае отработает магический метод Eloquent, возвращая значение из внутреннего массива $attributes…

                Т.е. автокомплит не работает. Действительно, с чего бы ему работать, если ORM схему не знает. Скажите пожалуйста, а как Eloquent получает схему таблицы для запроса типа select?
                SHOW COLUMNS FROM my_table;?
                Или костыль типа
                protected $available_columns = ['col1', 'col2'];

                [вангамод]Типов полей конечно же в Eloquent тоже нету, т.е. все время придется руками явно приводить все типы[/вангамод]

                $model->datetime_field = $date_var->format('Y-m-d H:i:s');
                $model->boolean_var = (int) $bool_var;

                • 0
                  Можно в phpdoc прописать @property — будет автокомплит.
                • +1
                  А зечем Eloquent'у знать схему таблицы? Схему должен знать разработчик, делающий этот селект.
                  [вангамод]Типов полей конечно же в Eloquent тоже нету, т.е. все время придется руками явно приводить все типы[/вангамод]

                  А что, PHP у нас оказывается стал строго типизированным языком?
                  А что, на вашем фреймворке, каким бы он ни был, не существует понятия валидации и фильтрации входящих от пользователя данных, прежде чем пихать их в модель и базу?
                  И на всякий случай, Ларик понимает поля datetime/timestamp, и в эти поля можно сэтить объект DateTime, либо Carbon напрямую, без format. Как он это делал раньше я не знаю, а щас для таких полей можно явно указать их в списке protected $dates модели. Я предвкушаю агро на эту фразу (ибо это то, что вызывает у вас отвращение, судя по фразе «Или костыль типа protected $available_columns = ['col1', 'col2'];»), но все в этом мире относительно. xml-схему базы можно назвать таким же костылем — тут каждому свое. Посему считаю спор на тему «что лучше, xml-схема с метаданными vs. миграции» не состоятельным, в чужой монастырь со своим уставом не лезут. Где-то кому-то удобнее схемы, где-то кому-то удобнее миграции.
                  • 0
                    >> А зечем Eloquent'у знать схему таблицы? Схему должен знать разработчик, делающий этот селект.

                    Всегда считал, что ORM для того и нужен в том числе, чтобы не заморачиваться с полями из селекта.

                    >> Я предвкушаю агро на эту фразу

                    Судя по вашему ответу, Eloquent-таки делает вот так SHOW COLUMNS FROM my_table;. Долбить БД однотипными запросами тоже считается хорошей практикой в Laravel?

                    >> А что, PHP у нас оказывается стал строго типизированным языком?

                    А причем здесь PHP? Тип поля выставляется для ОРМ. В Propel я могу поставить тип поля строка и потом делать вот так
                    -> filterByName('%'. $name)
                    и Propel сам понимает, что надо сделать 'LIKE' в запросе
                    • 0
                      Всегда считал, что ORM для того и нужен в том числе, чтобы не заморачиваться с полями из селекта.

                      А никто и «не заморачивается с полями из селекта». Либо я просто не понял, о каких заморочках идет речь.

                      Судя по вашему ответу, Eloquent-таки делает вот так SHOW COLUMNS FROM my_table;. Долбить БД однотипными запросами тоже считается хорошей практикой в Laravel?

                      Не делает он никаких подобных запросов. Ты формируешь запрос разными способами, а он его просто выполняет… Зачем для этого знать схему таблицы? Если ошибка в запросе (например неизвестный column name), то ты ее и получишь от мускуля в ответ.

                      А причем здесь PHP? Тип поля выставляется для ОРМ.

                      Не вижу тут особых преимуществ, в Eloquent очень удобно делать различные запросы для выборки. Если же вдруг средствами Eloquent не получается сформировать нужный запрос, есть Query Builder — тоже довольно удобная и мощная штука. Здесь расписывать примеры не буду, если интересует, даю ссылки на документацию с примерами:
                      Eloquent
                      Query Builder
                    • +2
                      В логах SQL ни разу не видел запроса SHOW COLUMNS FROM my_table;
            • 0
              А это значит, что вы не пользуетесь системами деплоймента, дальше даже обсуждать нечего.

              Впрочем, тут не буду навязываться. В этом вопросе я действительно не силен.
        • 0
          >> Но, собственно, мы несколько отошли от изначальной темы разговора. Вопрос остается открытым: «хотят {{ Form::text('name') }} в стиле Pure (http://purecss.io/), а {{ Form::textarea('bio') }} в стиле horizontal form из bootstrap». Каким образом такое делается?

          Я немного не понял вопроса. Как к форме добавить какие-либо дополнительные атрибуты?

          text(string $name, string $value = null, array $options = array())
          textarea(string $name, string $value = null, array $options = array())

          $options — массив абсолютно любых атрибутов, какие только захотите.

          Я ответил на вопрос? Если нет, пишите, постараюсь ответить.
          • 0
            >> text(string $name, string $value = null, array $options = array())

            Я понял. Т.е. эта штука просто тупо генерит html такого содержания (input type=«text» value=«value» тут аттрибуты). И в чем профит? Зачем притягивать php там, где он не нужен?
        • 0
          Но, собственно, мы несколько отошли от изначальной темы разговора. Вопрос остается открытым: «хотят {{ Form::text('name') }} в стиле Pure (http://purecss.io/), а {{ Form::textarea('bio') }} в стиле horizontal form из bootstrap». Каким образом такое делается?

          Да, забыл ответить. Во-первых, как написал выше автор, это можно сделать посредством Form. Во-вторых, никто не заставляет использовать Form, можно написать форму просто «вручную». Сам на двух своих сайтах сделал вполне себе «bootstrap»-формы посредством Form. См. например SBShare.ru
  • +2
    $questions = Question::remember(60)->get();

    Я честно надеялся, что это опечатка, но, увы, с фреймворком все очень плохо, ведь значение действительно передается в МИНУТАХ!

    github.com/laravel/framework/blob/0e81255e46dc616d7881f5744cd0da9796606e3c/src/Illuminate/Cache/WinCacheStore.php#L49
    github.com/laravel/framework/blob/0e81255e46dc616d7881f5744cd0da9796606e3c/src/Illuminate/Cache/XCacheStore.php#L49
    github.com/laravel/framework/blob/70108fe4f456f343325234063aa77b9012ede7dd/src/Illuminate/Cache/ApcStore.php#L58
    github.com/laravel/framework/blob/dbad9471be94d3028e69a91660ea876e99d16005/src/Illuminate/Cache/RedisStore.php#L69
    github.com/laravel/framework/blob/872bc11f7beb11a309ec41ab2d9f6c19da18acb5/src/Illuminate/Cache/FileStore.php#L199
    github.com/laravel/framework/blob/c343c8b9aa2484c93577c1abc03be2bfa78cd746/src/Illuminate/Cache/MemcachedStore.php#L60

    И оно действительно везде умножается на 60, или вот например игнорируется:
    github.com/laravel/framework/blob/0e81255e46dc616d7881f5744cd0da9796606e3c/src/Illuminate/Cache/ArrayStore.php#L36

    Ну и как Вы думаете… конечно же есть вопрос на форуме «А как закешировать на 1 секунду» — laravel.io/forum/04-10-2014-caching-under-1-second

    И вот этот автор приедет на девконф как «special guest»?)

    Я х*ею в этом зоопарке... Я ничего не понимаю в современных трендах на глупые решения и рекламе этого говна.
    • 0
      О ужас, раз значение таймаута в минутах, то все, однозначно, фрейм говно… На практике, часто ли приходится юзать кэш на секунды? И к тому же, если действительно нужны секунды, можно передать $minutes/60. Есть и другие решения, как например заменить компонент кэша на свой с секундами. Но говорить, что «с фрэмворком все плохо» из-за одной только неустраивающий конкретно вас мелочи неправильно.
    • 0
      Согласен с Amega. Зачем кешировать SQL запрос меньше, чем на минуту?
      • +1
        Я не видел ни одной реализации кэша, где бы время кеширования задавалось в минутах. Эти вот изобретательства своих стандартов в API это не хорошо.

        А по поводу кейсов «зачем», всякое бывает. Может быть у вас есть задача, при которой время жизни кэша не должно быть больше 1 минут 40 секунд (просто так, из головы). Сделать меньше — не эффективно работает система. Сделать больше — часть запросов возвращают устаревшие данные. А писать для этого кастыли вида 100/60 что бы можно было определить время кеша в 100 секунд…

        Да и если покопаться в недрах этого фреймворка, думаю можно еще чего забавного найти. Мое мнение — если вам нравится, используйте. Но не называйте фреймворк «лучшим». Лучших не бывает.
        • 0
          А я и не называл Laravel лучшим.
        • 0
          Лично для меня Ларавел является лучшим фреймворком из всех. Но я подчеркну — для меня, я с этим сразу определился, как только начал его копать. Я конечно не стану утверждать, что он лучший в абсолютном смысле, то есть для всех. У каждого свои предпочтения и вкусы. Кто-то ведь считает лучшим фреймворком Yii, в то в ремя как меня от него рвет наизнанку.

          Насчет кэша в секундах признаюсь, на этот «косяк» уже несколько раз обращали внимание Тэйлора (автора), в том числе и в нашем русском Laravel-коммьюнити, но он упорно не хочет ничего менять, отклоняя пулл реквесты. Что ж, хозяин — барин. Это пожалуй единственный «косяк» фрейма, по кр. мере о котором мне известно. И то, известно только потому, что для кого-то действительно важно иметь таймауты в секундах. Лично мне даже удобнее, что в Ларике таймаут задается в минутах, так как секундные кэши мне пригождались за всю мою жизнь лишь однажды. Хоть я и программист, но мыслю не в нулях и единицах, секундах и тиках, а в десятичной системе счисления и минутах/часах. Используя секунды мне приходится лишний раз вычислять, сколько требуемый мне интервал будет в секундах. Одним словом, лично я считаю таймауты в минутах только плюсом, так как это более human-фрэндли так сказать.

          Насчет покопаться и найти что-то еще «забавное» — тут не знаю. Я уже много внутренностей Ларика перекопал, и нахожу только очень красивые решения и применения современных подходов в программировании. В отличии от все того же Yii, к примеру, где иногда можно аж по несколько классов в одном файле встретить.
          • 0
            Насчет кэша в секундах признаюсь, на этот «косяк» уже несколько раз обращали внимание Тэйлора (автора), в том числе и в нашем русском Laravel-коммьюнити, но он упорно не хочет ничего менять, отклоняя пулл реквесты. Что ж, хозяин — барин.

            Кстати говоря, некоторые вещи хороши именно в запретах. По сути все типы, интерфейсы и т.д. хороши именно тем, что не дают сделать ненужного. Не могу сказать про кэш в секундах, в голову приходит мысль о сервисе с огромным количеством пользователей и часто обновляемой информацией: например, какой-то интерактив читают миллионы пользователей, пишут несколько десятков, обновление достаточно раз в 5-10 секунд.
            Но такие системы конечно никаким Laravel не доверишь — тут уже масштабирование другими средствами, однако это в том числе и ограничивает силу framework'а.
            • 0
              Я сегодня со своим другом, а по совместительству — начальником, решил обсудить эту тему. У него был опыт разработки сервиса подобного. В чем была суть сервиса я не спрашивал, но он говорил про нагрузки приблизительно в 1000 хитов в секунду. У них делался кэш даже не в секундах, а миллисекундах (для меня была новость, что в некоторые кэш провайдеры так сказать можно передавать не просто секунды (int), а float, то бишь миллисекунды). При этом никому в голову не пришло считать это костылем, что мол приходится милисекунды делить на 1000.
              • 0
                Использовать миллисекунды как дробную часть секунды вполне логично и с общечеловеческой точки зрения, и с точки зрения разработчика на PHP (имхо, microtime(true) используется на порядок чаще, чем microtime(false) или просто microtime() ).
    • 0
      О боже! Как теперь жить с этим? Может быть форкнуть и переписать как нужно или как хочется? Или Pull Request создать?

      Можно построить 1000 мостов… (продолжение в гугле)

      Так к чему это я… к тому, что языком трепать каждый горазд. Когда что-то в проекте с открытым исходным кодом не нравится — пишутся PullRequest с исправлениями. Не за что.

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