Laravel Функция $q как аргумент функции

StalkerClasses

Новичок
В Laravel есть возможность передать в качестве аргумента функции функцию function ($q) use($city_id) с параметром $q в который можно добавить различные условия.

PHP:
$view->clubs = Places::whereHas('contacts',function ($q) use($city_id){
           $q->where('contacts', function ($q) use($city_id){
               $q->where('id', $city_id);
            });
        })->get();
Как написать обработку такого аргумента для функции?
Places::myFunc(function ($q) use($city_id){})

Что должно быть в функции написано?

function myFunc($ARG){
// Как его обработать?
}
 

StalkerClasses

Новичок
Вот пример кода что написал:

PHP:
    // Выбрать запись (с условиями)
    public static function recSelectByCriteria(Closure $callback = null){
        $class = get_called_class();
        // call_user_func($q);
        if ($callback) {
            $model = $class::getModel();
            $func = $callback($model);
            $models = $func->get();
        } else {
            $models = $class::get();
        }
        return $models;
    }



        // Выбрать все записи
        $limit = 10;
        $rows = ExampleTable::recSelectByCriteria(function($q) use ($limit){
            // Builder $builder;
            $q = $q->select('uid','title');
            #$q->where('field', '=', 1)
            #$q->orderByDesc('title');
            $q = $q->limit($limit);
            #$q->offset(0);
            return $q;
        });
       
        foreach ($rows as $row){
            print $row->title . "<br />";
        }
Получилось реализовать также как это сделано по аналогии с with( FUNCTION )
Но в отличие от with() мне приходится возвращать return $q; в функции.
Полагаю его нужно сделать как ссылку. Как это реализовать?
 

StalkerClasses

Новичок
Смог реализовать.
Код:
        // Выбрать все записи
        $limit = 8;
        $rows = ExampleTable::recSelectByCriteria(function($q) use ($limit){
            #$q->withoutGlobalScope('TestScope');
            #$q->withoutGlobalScopes();
            #$q->select('uid','title');
            #$q->where('field', '=', 1)
            #$q->orWhere('field', '>=', 100)
            $q->orderByDesc('title');
            $q->limit($limit);
            $q->offset(1);
            #$q->with();
            #$q->has('comments');
            #$q->whereHas('comments', function ($query) { $query->where('content', 'like', 'foo%'); }
        });
       
       
    // Выбрать запись (с условиями)
    public static function recSelectByCriteria(Closure $callback = null){
        $class = get_called_class();
        // call_user_func($q);
        if ($callback) {
            $model = $class::getModel()->newQueryWithoutRelationships();
            $callback($query = $model);
            $models = $query->get();
        } else {
            $models = $class::get();
        }
        return $models;
    }
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
Сюда надо добавить несколько уточнений.
1. Замыкания сложно дебажить. Обычно их используют в библиотеках и фреймвоках, чтобы дать возможность авторам ПО вклиниться в цикл исполнения программы. Использовать их в коде приложения - сомнительная идея.
2. Статические вызовы - зло. Ты нарушаешь SRP, IoC и создаешь связанность.
3. Нет смысла указывать тип аргумента nullable closure (Closure $callback = null) - если прийдет null, ошибка будет все-равно, но менее очевидная
4. Аргументу function($q) нужен тип, иначе в вызове $q->select - будет странная ошибка, когда в $q вместо объекта придет null
5. $class::getModel(); $query = $model; $models = $query->get(); - блин, write-only code, ты от кого шифруешься? в yii1 этот изврат создал много проблем, и не просто так это все переделали

То же самое можно написать нормально.
 
Последнее редактирование:

fixxxer

К.О.
Партнер клуба
Аргументу function($q) нужен тип
Не могу не заметить, что в данном конкретном случае с этим все сложно, потому что Eloquent - говно. Разве что union types из восьмерки помогут :)

А вообще, в Eloquent есть scopes, их и надо использовать вместо этой фигни.
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
это в yii1 было 10 лет назад, но глубоко внутри, а во 2м переделали

что такого разного там может приходить без общего интерфейса?
 

fixxxer

К.О.
Партнер клуба
что такого разного там может приходить без общего интерфейса?


taylorotwell commented on Jul 10, 2018
I'm not sure the benefits really outweigh the amount of changes in this PR?
@taylorotwell taylorotwell closed this on Jul 10, 2018
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
ох Ё это ж в точности с yii 1 слизано
там же тоже два разных QB ... было 10 лет назад, когда еще ни namespace, ни composer не было

и отвечает так же ... они с китайцем братья по вере? )))
логики ж нет, ларавель давно уже самый медленный
 

StalkerClasses

Новичок
PHP:
[CODE]        // Выбрать записи (кол-во)

        $rowsCount = ExampleTable::recSelect(null,'count'); // print $rowsCount;

     

        // Выбрать записи (v1)

        $limit = 8;

        $rows = ExampleTable::recSelect(function($q) use ($limit){

            #$q->withoutGlobalScope('TestScope');

            #$q->withoutGlobalScopes();

            #$q->select('uid','title');

            #$q->where('field', '=', 1)

            #$q->orWhere('field', '>=', 100)

            $q->orderByDesc('title');

            $q->limit($limit);

            $q->offset(1);

            $q->with('exampletable1_row_func');

            #$q->with();

            #$q->has('comments');

            #$q->whereHas('comments', function ($query) { $query->where('content', 'like', 'foo%'); }

        });

     

        foreach ($rows as $row){

            print $row['title'] . " // ";

            print $row['exampletable1_row_func']['title'] . "<br />";

        }

     

        $row = ExampleTable::recSelect(177); // Выбрать запись (v2) // print $row['uid'];

        $insertId = ExampleTable::recInsert(['RType'=>'1','title'=>'regge']); // Создать запись // return $$insertId = ;

        ExampleTable::recUpdate(177, ['title'=>'rrr']); // Обновить запись

        ExampleTable::recDelete(175); // Удалить запись

     

        ExampleTable::refAttach('exampletable1_row_func',177,2);

        ExampleTable::refDetach('exampletable1_row_func',177,2);

        ExampleTable::refCollection('exampletable1_row_func',177);

[/CODE]

Вполне устраивает...
Условия добавляются на уровне boot
 

AmdY

Пью пиво
Команда форума
И зачем тебе этот код, если даже говнокодя всё можно в цепочку засунуть без без коллбэка?
ExampleTable::eek:rderByDesc('title')->limit($limit)->offset(1);

В варианте с whereHas коллбэк нужен, чтобы чтобы добавить условия при выборке из связанной таблице. При выборе Place ты добавляешь условия для подзапроса в таблицу Contacts, а коллбэк внутри where позволяет группировать условия вроде как скобочки. У тебя же какой-то бред даже в первом примере. ты понимаешь что тот код делает?
 

fixxxer

К.О.
Партнер клуба
Я так понимаю, он где-то услышал про criteria pattern. Но смысла в такой передаче замыкания нет никакого. Это получается та же цепочка вызовов, только с ненужными усложнениями.

Смысла в criteria pattern в Eloquent нет никакого, это не доктрина и тут это просто не работает - отвязки все равно никакой не будет просто потому что это активрекорд. Желание отвязаться от кусков sql снаружи модели понятно. Для этого есть scopes.
 

StalkerClasses

Новичок
Я так понимаю, он где-то услышал про criteria pattern. Но смысла в такой передаче замыкания нет никакого. Это получается та же цепочка вызовов, только с ненужными усложнениями.

Смысла в criteria pattern в Eloquent нет никакого, это не доктрина и тут это просто не работает - отвязки все равно никакой не будет просто потому что это активрекорд. Желание отвязаться от кусков sql снаружи модели понятно. Для этого есть scopes.

С наступающим.

Лично по мне в ларавель очень нравиться функционал который представлен (where, has, with (назвалы бы ref), и другие функции. Но мне очень не нравиться то многообразие которое дает ларавель для работы с теми же шаблонами, и те же find(), get()? Что это такое с точки зрения функции. Мне каждый раз приходится вспоминать как это написать. Вспоминать что SAVE это и INSERT и UPDATE. Другое дело в той ORM которую кажется уже упоминали (стандартные функции SELECT, DELETE, UPDATE, INSERT и все крутится на базе их названий).

Еще что бы хотел добавить в SELECT кастомную функцию...
Допустим мне надо выбирать что-то одно и тоже. Будет что-то типа
$rowsCount = ExampleTable::recSelectCustom('pagePublicList',arg1,arg2); // print $rowsCount;
 

Adelf

Administrator
Команда форума
там же тоже два разных QB ... было 10 лет назад, когда еще ни namespace, ни composer не было
там один и тот же. Просто QB уровня ORM добавляет свои методы и делает:

Код:
public function __call($name, $parameters) {
  ...
  $this->query->{$method}(...$parameters);
}

Я для Laravel Idea делал хелпер-код для элоквента. Генерю жуткую мешанину, для каждой модели генеря классы типа _UserQueryBuilder, _UserCollection и еще парочку. В итоге тип почти везде правильно подсказывает, но с лямбдами конечно пока проблема. Приходится динамически вычислять, и не всегда получается.
 

fixxxer

К.О.
Партнер клуба
там один и тот же. Просто QB уровня ORM добавляет свои методы и делает:

Код:
public function __call($name, $parameters) {
  ...
  $this->query->{$method}(...$parameters);
}

Я для Laravel Idea делал хелпер-код для элоквента. Генерю жуткую мешанину, для каждой модели генеря классы типа _UserQueryBuilder, _UserCollection и еще парочку. В итоге тип почти везде правильно подсказывает, но с лямбдами конечно пока проблема. Приходится динамически вычислять, и не всегда получается.
Вся эта жуткая рантайм-динамика - прямое следствие того, что Тейлор пишет код в блокноте (или там саблайме, какая разница). Писал бы в Сторме - сразу бы автоматически отсек подобные извращения, иначе же задолбаешься хинты расставлять.

С другой стороны, тогда бы и никакой плагин не нужен был, а так вот, тебе есть что продавать)
 

Adelf

Administrator
Команда форума
Именно по этой причине я перестал критиковать код ларки и Тейлора)
 

fixxxer

К.О.
Партнер клуба
Вспоминать что SAVE это и INSERT и UPDATE
А зачем их вообще различать? Единственная причина, которая мне приходит в голову - появление автоинкрементного ID после инсерта - ну так автоинкременты это зло.

В остальном - все делится на две группы:
1) для создания моделей используй статические методы, которые ничего не пишут в базу, а просто инициализируют поля и возвращают инстанс
2) для выборок используй scopes (уже в третий раз про них пишу)
 

fixxxer

К.О.
Партнер клуба
Тем, что искусственно объединяет две разные вещи - генерацию уникального идентификатора сущности и ее персистенцию - в одну операцию. Это часто создаёт проблемы, от небольших неудобств до полной неприменимости определенных архитектурных решений.
 
Сверху