Laravel по-русски

Русское сообщество разработки на PHP-фреймворке Laravel.

Ты не вошёл. Вход тут.

#2 Re: Хорошие практики (FAQ) » Контроллеры » 13.11.2017 14:53:01

Зачем сливать контроллеры?
А если изменится логика работы блога и новостей?
Опять разбивать?
Есть такая практика, как разделение логического функционала.
1. Модели разные используются
2. Может изменится логика
3. Роуты разные.

Сделать один общий абстракт? Так уж лучше общий трейт.
Но я не вижу смысла... ни абстракта, ни трейта.
Так как в контроллере много разного может быть... модели, валидаторы, ФормРеквесты, возвращаемый результат. Очень часто бывало так, что сегодня это схожий функционал, а завтра надо добавить пару строчек в одном из вариантов.
Вот и выходит, что чтобы объединить схожий функционал в контроллерах, необходимо продумать как будет реализована передача входящих данные, передача нужной модели, и возможность возвращать необходимые результат (вьюхи, json и прочее).
Я задумывался над подобными вопросами... но пришел к выводу, что это не имеет смысла. Лучше иметь несколько нормально описанных контроллера, чем общий абстракт или фасад... от контроллеров всё равно не уйти. Их по любому придется реализовывать в файлах.

#3 Re: Хорошие практики (FAQ) » В какой последовательности принято записывать use » 13.11.2017 14:37:00

Я обычно писал так:

namespace App\Http\Controllers\Admin;

use Exception;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Config;

use App\Classes\Models\User;
use App\Classes\Models\Payment;
use App\Http\Controllers\Controller;

1. Корень
2. Фрейм
3. Апп общее
4. Модуль

Когда начал писать под php7, стал писать в таком виде:

namespace App\Http\Controllers\Admin;

use Exception;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\{Validator, Auth, Config};

use App\Http\Controllers\Controller;
use App\Classes\Models\{User, Payment};

Классы, которые объявлены в корневом пространстве, я обычно не добавляю, а использую в виде \Exception...

 try {
     ...
 } catch( \Exception $e ) {
     ...
 }

Исключения только тогда, когда таково требование стилизации заказчика или компании с которой я работаю.

#4 Re: Хорошие практики (FAQ) » Коммерческий код » 10.11.2017 17:33:29

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

Да, в Ваших словах есть львиная доля правды. Но в данный момент мы пишем используя клавиатуру, что уже является не вполне естественным и конечно имеют место быть рефлекторные огрехи.
И в Нашем Великом Русском Языке очень много не естественных для нашего языка слов, позаимствованных у других народов с совсем другой фонемой.

Первично - это логика и содержание

Абсолютно с Вами согласен! Но! Если всё слитно и смазано написано, воспринять логику и содержание сложно.
А вот когда всё "удобно-читаемо", понимать описанную логику и содержание куда приятней и проще.
Это как говорить внятно, четко и громко вместо шепеляво, быстро и тихо.

Забавно, а для меня логичнее всегда ставить статические члены в начале класса.

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

PROCEDURE Install* (T: Task);
  VAR t: Task;
BEGIN t := PrevTask;
    WHILE (t.next # PrevTask) & (t.next ff T) DO t := t.next END;
    IF t.next = PrevTask THEN T.next := PrevTask; t.next := T END
END Install;

Вот честно... ключевые слова в верхнем регистре мало встречал в Delphi... возможно в начальных версиях и попадалось такое безобразие... но с 3й версии точно не попадалось... даже в сторонних компонентах.

Вот так обычно было:

function Encrypt(const InString: string; StartKey, MultKey, AddKey: Integer): string;
var
    i: Byte;
begin
    Result := '';
    for i := 1 to Length(InString) do
    begin
        Result := Result + Char( Byte(InString[ i ]) xor (StartKey shr 8) );
        StartKey := ( Byte(Result[ i ]) + StartKey ) * MultKey + AddKey;
    end;
end;

#5 Re: Хорошие практики (FAQ) » Коммерческий код » 10.11.2017 15:18:08

Мне это напоминает...
- "Я езжу на ВАЗе и мне не нравятся ваши Мерседесы! Наши автомобили лучшие в мире!"

Но!
- "Если кормить волка овсом всю жизнь, он будет считать, что это лучшая еда. Но стоит ему попробовать мясо, он больше не будет есть овёс!"

#6 Re: Хорошие практики (FAQ) » Коммерческий код » 10.11.2017 14:50:42

Я не буду спорить... но вот пример из фреймворка Laravel:

    public function url($path)
    {
        $adapter = $this->driver->getAdapter();

        if (method_exists($adapter, 'getUrl')) {
            return $adapter->getUrl($path);
        } elseif ($adapter instanceof AwsS3Adapter) {
            return $this->getAwsUrl($adapter, $path);
        } elseif ($adapter instanceof RackspaceAdapter) {
            return $this->getRackspaceUrl($adapter, $path);
        } elseif ($adapter instanceof LocalAdapter) {
            return $this->getLocalUrl($path);
        } else {
            throw new RuntimeException('This driver does not support retrieving URLs.');
        }
    }

В коммерческом виде было бы так:

    public function url( $path )
    {
        $adapter = $this->driver
                        ->getAdapter();

        if( method_exists($adapter, 'getUrl') ) {
            return $adapter->getUrl( $path );

        } else if( $adapter instanceof AwsS3Adapter ) {
            return $this->getAwsUrl( $adapter, $path );

        } else if( $adapter instanceof RackspaceAdapter ) {
            return $this->getRackspaceUrl( $adapter, $path );

        } else if( $adapter instanceof LocalAdapter ) {
            return $this->getLocalUrl( $path );

        } else {
            throw new RuntimeException(
                'This driver does not support retrieving URLs.'
            );
        }
    }

Разве так не лучше?

#7 Re: Хорошие практики (FAQ) » Коммерческий код » 10.11.2017 14:18:19

Зачем было исковеркивать PSR-1/PSR-2 и обзывать эту смесь "коммерческим" кодом?

Коммерческий код появился за долго до появления всяких PSRов и над стилизацией работали куча оченб грамотных людей. В то время как PSR появился позже и много было заимствовано из коммерческого кода с изменениями.
Коммерческих код не использовался на PHP никогда... только на C (C++) и Pascal'е.
И на сколько я знаю, PSR был принят сообществом только потому, что нужно было стандартизировать стилизацию кода на PHP. И принят он был чисто условно на пальцах... типа "А давайте так писать?", а давайте!
Над коммерческим кодом работали и доводили до идеала. Над PSR никто не работал... просто притянули за уши с других языков... по большей части с C++.
Я программирую ещё с 1987 года на С и C++, на Delphi с 1995. И был владельцем BBS (Maximus 3.0 с фидо ретранслятором)... и об интернете тогда ещё никто "слыхом не слыхива"... я не говорю уже о PHP и PSR.
Но то, что я вижу сейчас в PSR меня удивляет.
Вот и хочется показать людям более понятную стилистику, которая "слизывается мозгом" и не приходится напрягать глаза и мозги, что бы понять, что же там написано.

#8 Хорошие практики (FAQ) » Коммерческий код » 10.11.2017 13:55:21

Cruide
Ответов: 11

Давным давно, когда люди забивали гвозди использую ASM и готовили DOS на Quick C...
О чём это я? А!
Да, есть такое понятие как "Коммерческий код". Это некая форма стилизации кода для лучшего восприятия кода мозгом.
Такой вид форматирования сильно облегчает понимание сути описанного в коде алгоритма.
К сожалению о нём забили, а многие даже и не слышали.
Данный вид форматирования был создан группой людей (из FidoNet). Использовался он для написания коммерческих программ, которые продаются вместе с исходным кодом.
На сегодняшний день почти все используют PSR и не задумываются о таких вещах, как скорость восприятия чужого кода на интуитивном уровне.
Вот и хочу Вам... рассказать... или напомнить... или предложить стиль кода "Коммерческий".
Чем он отличается и какие правила он применяет:

Большинство пишет код так:

class Text {
    const TEST = 1;
    
    public static $test = '';
    public $filename = '';
    public $name = '';
    private $a;
    protected $b;

    public functuion getA() {
        if(self::$test == self::TEST) {
            return $this->a;
        }
        /* Или такой вариант
        if (self::$test == self::TEST) {
            return $this->a;
        }
        */
        return null;
    }
}

Коммерческий код выглядит так:

class Text 
{
    // Константы всегда в начале
    const TEST = 1;
    
    // Затем всегда паблик    
    public $filename = '';
    public $name     = '';
    
    // Потом протектед
    protected $b;

    // и приватные
    private $a;

    // Далее так же и статические
    public static $test = '';

    // Такое же правило относится и к методам
    public functuion getA() 
    {
        // Обязательно if( пробел условие пробел )
        // if( - мозг воспринимает лучше чем if (
        // условия типа
        // if(!$data) или if (! $data)
        // воспринимается хуже чем if( !$data )
        if( self::$test == self::TEST ) {
            return $this->a;
        }

        return null;
    }
}

все переменные и свойства в snake_case
все методы в lowerCamelCase
все функции (процедуры) в snake_case
все имена классов в UpperCamelCase

описание последовательности вызова методов:
    return $users->default()
                 ->actived()
                 ->get();

а не:
    return $users->default()->actived()->get();

все простые условия типа:
    if( self::$test == self::TEST ) {
        return $this->a;
    }

    return null;

должны описываться так:
    return ( self::$test == self::TEST ) ? $this->a : null;

почему скобки? для визуального отделения условия от логики;
При длинных вариантах:
    return ( self::$test == self::TEST ) ? $users->default()->actived()->get() : $users->actived()->get();

Надо писать так:
    return ( self::$test == self::TEST )
               ? $users->default()->actived()->get()
               : $users->actived()->get();

Это будет восприниматься быстрей и понятней.

Я часто встречаю записи такого вида и они просто неудобно-читабельны:
    return $this->response($this->presenter->full($infraction));
или:
    $infraction->users()->attach($original->users->pluck('id'));

И исправляю их на:
    return $this->response(
        $this->presenter->full(
            $infraction
        )
    );
и:
    $infraction->users()
               ->attach(
                   $original->users
                            ->pluck('id')
               );


Так воспринимается куда более быстрей.

Много всего, но Коммерческий код воспринимается всеми программистами (и профи и новичками) с одинаковой скоростью и лёгкостью.
Что скажете?

#9 Re: Laravel 5.x » Утечка памяти после сохранения в базу данных (Eloquent) » 09.11.2017 18:31:09

А зачем return; в конце если это void да ещё конец метода?
Что такое SnapshotsTeamspeakVirtualServers? Модель?
Что такое new TeamSpeak( $this->instance_id )? Тоже модель?
Почему не

if( ($data = $this->GetAllServersSnapshots()) && is_array($data) )
{
    SnapshotsTeamspeakVirtualServers::create( $data );   
}


Много не понятного... нельзя просто взять и ответить почему небо синее...

Утечка может происходить из-за вновь создающегося объекта(ов) и хранящегося в памяти...
Типа
return self::$a[] = new Obj();

А данный метод может вообще не причём.

#10 Re: Хорошие практики (FAQ) » Некоторые дополнения » 07.11.2017 18:15:50

Проще, но только новичку. Читабельнее только для того, кто только что это написал. Другому разработчику или автору кода через несколько месяцев прочитать это будет довольно сложно.

Если всё (код) нормально оформлено и грамотно прокоментированно, никаких проблем не будет. Вся логика по шагам будет видна сразу и не придётся искать где данные перебиваются. А другому разработчику так вообще проще-простого, зашел по роуту и всё увидел.

Вобщем, на вкус и цвет все фломастеры разные.
Просто я уже много раз сталкивался (и не только на Laravel) с тем, что приходится очень долго искать где и почему меняется 1 на 2. Вот именно в таких "дебрях"... в контроллере 2 строчки... и начинаешь 2 часа рыться по коду, вместо того, что бы сделать работу.

#11 Re: Хорошие практики (FAQ) » Некоторые дополнения » 07.11.2017 17:41:43

В таких случаях нужно использовать преобразователи (mutators), значения по умолчанию и т.д.

А если зависимость значений куда более сложна... и важна очередность проверки с различными переключениями в зависимости от появившихся логических изменений, а не единичные. где в зависимости от определенных входящих данных будет зависеть значение некоторых переменных, а уже от их значений зависит другие значения? Как тогда?
Мутаторов не всегда достаточно, array_merge тоже не всегда подойдёт... ведь важна последовательность логики.
Вот и выходит, что категоричность в данном случае не однозначна. Ваш вариант хорош, но не однозначен. В крупных проектах очень часто при сохранении данных нужно учитывать различные факторы которые в зависимости от логических изысканий могут меняться в процессе вычисления значений.
Конечно, часть логики можно вынести на фронт, что-то в валидатор/реквест, что-то убрать в дефолты и часть в модели, но этого бывает не достаточно и потом очень сложно искать, что и где не так.
Проще и "читабельней" всю логику описать в контроллере, в одном месте и в случае необходимости не рыться в куче файлах, а просто в контроллере поменять логику.
А так получается ООП программирование ради ООП программирования.
Можно сказать просто я хочу домой... а можно рассписать как Вы хотите в одном месте, почему Вы хотите домой в другом, в третьем как Вы будите идти домой, в четвёртом по какой дороге... а в итоге, если кто-то после Вас полезет в код, будет долго искать где у Вас описание цвета сандалей, в которых вы идёте домой.

#12 Хорошие практики (FAQ) » Некоторые дополнения » 07.11.2017 17:08:13

Cruide
Ответов: 5

Отлично написано! Респект автору!

Но всё же есть некие... так сказать "несогласия":
1. Название переменных и свойств классов таки правильней писать в snake case. И это не только на PHP. Но на PHP принято всеми. Lower Camel Case всё же для методов.
2. Вот здесь:
   $category->article()->create($request()->all());
Тоже не согласен. В большинстве простых случаем это Верно, но частенько бывает необходимость расставлять значения по условиям.
Если не заполнено это поле и заполнено то поле, значит значение в 1... А если не заполнены оба, значит 2... или если заполнено То без Этого, значит 3...
Таких примеров масса в средних и больших проектах и тогда обработку, и приведение данных правильней (на мой взгляд) делать в контроллере... ведь он для этого и создан.
тогда получается что-то вроде:
$category->article()->create([
   'title' => $request->title,
   'date' => $request->date ? $request->date : now(),
]);

Короткий и читаемый синтаксис.
Да и более того, в Laravel каждый раз добавляется много хелперов которые мало документированы... изучайте код.
Или создавайте свои хелперы типа:

    if( !function_exists('is_auth') ) {
        function is_auth()
        {
            return auth()->check();
        }
    }

    if( !function_exists('is_ajax') ) {
        function is_ajax()
        {
        return \Request::ajax();
          }
    }

Добавлю ещё пару-тройку хелперов авторизации:
auth()->check(); // \Auth::check();
auth()->user();
auth()->id();

И добавлю от себя...
- "Правильное описание модели и связанных с ней релейшенов это уже 30% приложения!"

#13 Re: Laravel 5.x » Стартовый пароль администратора в .env файле » 07.11.2017 11:54:00

Я бы всё таки заводил пользователя (Admin или  Superuser) в миграции с заданным паролем.

#14 Поиск работы » Ищу работу на Laravel 5 (Middle Laravel) » 07.11.2017 11:47:42

Cruide
Ответов: 2

На Laravel пишу где-то года 3. На PHP больше 10 лет. В основном Backend с MySQL (MariaDB), но есть опыт с jQuery + Bootstrap. Хочется найти интересный проект и приятную команду. Живу в Домодедово (Московская область), езжу на авто. Желательно не дальше полутора часов езды.
Хочется найти работу на долгие годы.

#15 Re: Laravel 5.x » Шорткоды » 16.10.2015 10:48:51

Johnson пишет:

Шорткоды нужны для того чтобы человек, который работает в редакторе мог в определенный момент вставить нужный функционал в контент из текстового редактора путем вставки в него шорткода, например пусть cats - это котики, давайте ка выведем вот на этой странице котиков, и вставляет шорткод - [cats]. При чем тут циклы с массивами, в теле функции шорткода можно реализовать все что угодно, а вот как внедрить сам механизм, пока не знаю, пока есть идея по распарсиванию контента на предмет шорткода, может кто-нибудь знает более элегантное решение, кстати формат шорткодов не обязательно в скобках, это для примера.

Старые добрые BB коды... Судя по вопросу, как я понимаю, контент хранится в базе... тогда только парсить... или писать быблиотеку для создания шорткодв... что бы можно было привязывать короткий код к методам классов... типа:
\BB::add('cats', function() {

});

или

\BB::add('cats', '\App\Lib\Cats', 'getCatList');

А после получения текста из базы, сделать:

$text =  \BB::make( $post->content );

Ну, по крайней мере, я бы что-то вроде этого сделал...

Подвал раздела