Ответы пользователя по тегу Laravel
  • Как задать глобальные ограничения доступа к моделям при запросах?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    Недавно делал похожую задачу, долго возился и в конце пришел к выводу, что если "все" или "большинство" имеет общую связь - то это две базы данных (разные заказчики, разные бд, устанавливаете отдельно, платят отдельно, бизнес очень любит такое, когда дважды платят за одну работу)

    Или одна таблица с морфом, где есть имя модели, имя родителя и айди, как с картинками. То есть доступ определяется по наличию морфа, а не проверке через связь. Один раз грузанул с моделями их морфы, а потом чекаешь isset(). По факту в логике вы все равно вытянете модель из БД, и проверив потом морф бросите 403 исключение, вместо того чтобы "Не тянуть совсем".

    Другой вопрос методы работающие с пачкой, нечто вроде "дай мне все документы, которые принадлежат мне в рамках такой-то компании". Там я думаю можно в одной функции написать whereHas() и не тянуть все записи, так же как вы бы писали вместо LEFT JOIN - обычный JOIN чтобы в выборку не попало то, что не должно там быть.

    Это редкий случай когда лучше обобщить, чем нормализовать. Такой же как и писать action_log в общую таблицу по проекту, или хранить картинки или загруженные файлы по моделям в одной таблице чем создавать под каждую модель. (я просто напомню, что если все таблицы вязать через общее звено (а вот морф это не общее звено, это виртуальная связь не имеющая внешнего ключа), то ваша доктрина будет плакать кровавыми слезами, потому что подразумевает DDD и работу с агрегатом - группой таблиц под задачу) - то есть для нормализованной базы лучше дублировать таблицы под логику, тогда как в этих случаях лучше их обобщать, т.к. контроль доступа штука касающаяся отдельной логики называемой "авторизация", а не каждого элемента логики "по чуть чуть".
    Ответ написан
    Комментировать
  • Как можно сделать обработчик всех ссылок в laravel?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    Мидлварь это и есть обработчик после того как роут определился. С его помощью можно принудительно вернуть ответ 404 или еще какой другой.
    Ответ написан
    Комментировать
  • Почему не работает route::fallback?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    Может мидлвар ->middleware('FrontDataset') ваш не проходит проверку?
    Фолбэк может быть в группе, но заставлять условную 404-ую проходить проверки - опасно. Велика вероятность, что на 404-ой нет достаточного числа инструкций, чтобы проверку пройти.

    А ещё он у вас в неймспейсе, хотя для колбэка это пофиг должно быть.

    Ну и остается какой-то лара прикол связанный с доменом, подразумевающий что ->domain()->fallback() по регулярке никогда не сработает потому что ->fallback() это НЕ регулярка.
    Ответ написан
    Комментировать
  • Как правильно фильтровать значения json с помощью whereJsonContains в laravel?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    Для безопасности твоей головушки сообщу - если оно выглядит "как-то сложновато", то лучше не надо, найди способ обойтись. Даже если ты сжав зубы добъешь фильтрацию по JSON-у в РЕЛЯЦИОННОЙ (созданной чтобы всё, что ищется было в РАЗНЫХ полях) - это потом кто-то не сможет прочитать, поредактировать и вообще исправить если захочет изменить.

    Всё что ищешь положи рядом в поля (создай колонку, пробежись циклом) и пользуйся обычными селектами. А json храни как будто это не знаю... картинка. Просто куча данных которые как положил, так и достал.
    Ответ написан
    7 комментариев
  • Как отправить заголовки в отложенной задаче?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    Используйте пожалуйста ext-curl для пхп, библиотеки написанные разработчиками фреймворков тестируются в ограниченном числе ситуаций, скорее всего ваша не была протестирована. Пока они исправят - можно пару месяцев подождать, но "за чей счет будет банкет". То есть в правильном обществе так и происходит - дается разработчику намек, что надо исправить, он - исправляет, вы ждете. В этом обществе если вы ждете - вы теряете работу. А он ничего. Используйте то, что простое, возможно требующее больше кода, но по крайней мере оно работает.

    Чем меньше "надежных" газзлов и хттп фасадов, работающих так, как запланировали, но вы не знаете кто и когда - тем спокойнее будет жить.
    Ответ написан
    Комментировать
  • Как организовать получение данных из общего объекта в файлах seeder и factory?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    Я константы в модели использую.

    Class Car {
      const ENUM_FUEL_PETROL = 'petrol';
      const ENUM_FUEL_DIESEL = 'diesel';
      const THE_ENUM_FUEL_LIST = [
        self::ENUM_FUEL_PETROL => true,
        self::ENUM_FUEL_DIESEL => true,
      ];
    }


    Но там уже Enum-ы ввели.

    Но если список стран или валют, которых много и черт пойми откуда берется - то просто сидер после наката миграций запускать.
    Ответ написан
    Комментировать
  • Как правильно выстраивать архитектуру метода контроллера на laravel?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    Знакомая боль давняя.
    Принцип следующий - 1) исходные данные 2) превращение в обьект, 3) проверка (валидация) обьекта, 4) передача обьекта в какое-то действие, 5) проверка результата (если нужна) и 6) генерация респонса.

    Исходные данные. Смотрим что за фрейм. Лара. Умеет в инжекцию в метод контроллера и биндинг обьектов, если написать правильно. Можно сразу на вход писать MyActionRequest (сделать как в документации), в итоге первой строкой будет $myActionRequest->validate(), которая еще и выкинет 422 если что-то не так.

    В чем минус ларавельного реквеста? Он представляет собой как бы ВЕСЬ реквест. Это тоже самое что передавать $_GET по программе, что немного странно.

    Рекомендуется сделать свой обьект ДТО. Это по сути твой же реквест, только в нем поля все заранее описаны, голый класс без методов - одни свойства. После валидации ты свои данные из GET/POST/LaravelRequest ручками втыкаешь в поля ДТО и этот заполненный ДТО можешь дальше кидать как "точно проверенная пачка данных" и не боятся каждый раз "а что если что-то не так" - оно точно так, потому что ты уже проверял.

    Попадать в какой-то другой класс ДТО может целиком если это кусок бизнес-части программы или по одному полю / массиву полей если это какой-то кусок ядра или глобалки. Пример ядро - класс Money, который переводит там валюты знач и позволяет их переключать. Туда ваш MyActionDTO будет странно кидать, а вот string $money или PHPMoney/Money- пжалста. А вот в обьект например MyCatalog кинуть MyActionDto уже не так уже и плохо.

    Вот это ваше действие может быть просто SQL запросом. Category::query()->find() это тоже действие, а почему нет. Рекомендуют конечно запросы выбрасывать в "тип классов" (папка, такая же как "модели") репозиторий чтоб потом когда поломается чего не везде править а в одном месте, но тут тоже, пока помните, что где можно не париться, и потом - увлечетесь обобщением поймаете прикол когда не понятно какую половину запроса в контроллер, а какую - в репозиторий. Стоит помнить что мы пишем задачу под задание, задание представляет собой контроллер, а остальной код ему помогает. Поэтому частности в экшон, похожести - в отдельный класс.

    Ну так вот, это "действие" что-то вам вернет. Может это готовый к выводу контент, а может еще какие-то данные которые для вашего экшена может кривые. Вот проверяете "оно? или нет". Частный случай - ничего в базе не нашлось, это критично, и 404 или просто выплюнуть "нет записей" и 200? Проверили ифами, сделали респонсы - где 404ый, где двухсотый, где джсоновский, где иксмэльный, файл-довнлоадный или стримовый.

    Потом пошли в Handler.php написали отлов исключений в целом по программе и их запись куда-то, в базу, в кеш или на удаленный логгер-анализатор, чтобы везде не писать try catch а просто писать throw и знать что оно "хоть как-то но отрисуется" и куда надо запишется.

    public function destroy(Request $request, $id) // или MyDestroyRequest если юзер что-то еще передает
        {
            $request->validate(); // оно под капотом ещё и авторизацию проверит и 422 само выбросит
    
            // ... верно тут можно проверять политику, но в принципе если реквест наследовать то в ларе помоему их можно и в реквест код перенести и первый метод еще и это сделает
          
            $dto = new MyDestroyDto($request->valid()); // там внутри пишем что куда, хотя можно и здесь
    
            $myDomainService = new MyDomainService(); // или new MyCoreService();
            $status = $myDomainService->doSomething($dto); // или $result = $myCoreService->convert($dto->money);
    
            if ($status === 'ok') return $this->jsonDone('@api.msg.ok_message', 200); // вот метод jsonDone в базовом (абстрактном*) контроллере или, например, в трейте, напиши
            return $this->jsonFail('@api.err.error_message', 500); // собаки в тексте для наглядности, трехуровневый ключ перевода из файла lang, по собаке просто можно определить текст уже проходил через переводчик или нет. три уровня нужны, чтобы когда много переводов скапливается их можно было подключать частями. Первый уровень - где подключать (api, catalog, social), второй - что (msg, err, label, placeholder, title, h1)
        }
    Ответ написан
    1 комментарий
  • Как указать дефолтную бд в ларавель?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    В каждом современном фрейме в корне проекта лежат файлы .env, собственно из них функция env() и сосет. Эта штука удобно помогает сделать несколько .env файлов для локала, для теста и сервера и подключать один из них в зависимости от режима сайта. Ставишь там "staging" и он подрубает staging env.

    Конфиги нужны для тех вещей, что не указаны в .env, каких-то узких настроек которые не меняются от "хостинга к хостингу"
    Ответ написан
    Комментировать
  • Есть ли паттерн для morph связи?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    Морфы я бы сказал сами по себе такой костылек, легкий
    Обычно в теории бд есть связи один ко многим, а сущности каждая имеют свою таблицу.

    Морфа в данном случае нужна скорее сущности чтобы вытянуть ссылку только в случае если "тип равно сущность".

    С тем же успехом можно просто хранить ссылки и иметь таблицы привязки ссылок к сущностям отдельно

    Ссылки
    Видосы
    Картинки
    СсылкиВидосы
    СсылкиКартинки

    морф в данном случае выглядит так

    Ссылки
    Видосы
    Картинки
    СсылкиШтуки (type: видосы/картинки)
    (?) ТипыШтук(1. видосы, 2. картинки)

    По делу как с этим работать:

    Модели для каждой таблицы
    Класс-Команда "ПолучательШтукиПоСсылке"
    -- получить(ссылка)
    Класс-Команда "ПолучательШтукиПоИдИТипу"
    -- получить(ид, тип)
    Контроллер Линки
    -- ПолучательШтукиПоСсылке->получить(ссылка)
    Контроллер Картинки
    -- ПолучательШтукиПоИдИТипу->получить(картинка, ид)
    Контроллер Видосы
    -- ПолучательШтукиПоИдИТипу->получить(видос, ид)

    $link = Ссылки::with('image')->where('code', '123456myshortlink')->first();
    return $link->image;
    Ответ написан
  • Как выбрать нужные данные по ключу из многомерного массива / коллекции?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    блин помоему input вернет тебе array, и обращаться нужно как к array
    опять же обязательно должен быть заголовок Content-Type:application/json, иначе input вернет ничего, т.к. по его мнению пришла строка
    Ответ написан
    Комментировать
  • Как в Laravel 6 добавить к Route:: языковой префикс с поддержкой языка "по-умолчанию"?

    gzhegow
    @gzhegow Автор вопроса
    aka "ОбнимиБизнесмена"
    сегодня какимто чудом бубном и такойто матерью разобрался

    Route::pattern('locale', '|ru/|en/');
    Route::get('{locale}route', 'action');
    // /(?P<locale>(?:|en/|ru/))route


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

    Чтоб сделать редирект после сравнения с кукой или сессией косую надо вернуть на место
    Ответ написан
    Комментировать
  • Как сделать что бы Laravel API Возвращало только json?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    <?php
    
    namespace App\Http\Middleware;
    
    class Api
    {
    	public function handle($request, $next)
    	{
    		$request->headers->set('Accept', 'application/json');
    
    		return $next($request);
    	}
    }
    Ответ написан
    2 комментария
  • Как суммировать значения с одинаковыми именами?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    Еще можно вызвать array_combine([id,name], array_map(null, $result)) и получить вместо
    [
      0 => [ id => 1, name => 'vasya' ],
      1 => [ id => 2, name => 'petya' ],
    ]


    массив
    [
      id => [ 1,2 ],
      name => [ vasya, petya ],
    ]


    суммируй потом, фильтруй, что хош делай
    Ответ написан
    Комментировать
  • Автоматически задать новое свойство через setter?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    Намекну что лучше не привыкать учить модель делать то, что она не умеет, потому что она и без того в ларавеле несёт бешенный функционал, а написать свой класс в который класть модель на вход и в конструкторе заполнять данными из неё. И там это свойство сделать и другие модули опереть уже на свой класс, который ничего кроме взять-положить не умеет. Потому что такой лишенный функционала класс можно без проблем оставить навечно, т.к. он всегда будет выполнять задачу "дать-взять", в отличии от модели ларавеля которая умеет слишком много и отказ от неё будет означать мозговой штурм и попытки залепить получившиеся дыры скотчем

    Но если прямо очень хочется модель то прям вот так и сделай

    protected $appends = ['created_at2'];
    getCreatedAt2Attribute() {}

    если нужно чтобы сохранялось в базу - нужно записать в массив $this->attributes[ $name ] = $value; потом вызвать save();
    Ответ написан
  • Вывести значение модели Laravel?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    Дядь если ты делаешь вызов first то иногда он возвращает null, привыкни писать проверку типа через двоеточие. Код сам станет красивым когда поймешь насколько это мощная штука.

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

    А еще коммент лайкс вероятно возвращающее массив ты отнимаешь из него... Цифру. Оно хорошо что вообще работает
    Ответ написан
  • Как правильно записывается массив в контроллер Laravel?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    Весь массив надо воткнуть в ключ arr. Там под капотом функция export
    Ответ написан
    Комментировать
  • Как реализовать присоединение пакета к laravel через интерфейс?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    Если тебе поможет, то я понимаю интерфейсы таким образом:

    Это име4на неких кусков программы, о которых ты можешь пояснить даже директору.

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

    Поскольку у тебя библиотеки две и делают одно и то же, тебе нужен класс обертка, который подобно переключателю может включить первую или вторую, а потом при вызове метода передать исполнителю, на котором сейчас переключатель

    По итогу у тебя будет два интерфейса. Один на обертку с методом переключить, второй на функционал. Можно обойтись и без интерфейса на обертку, тогда неиудастся сделать абстрактный переключатель для любой штуки в программе, будешь писать под каждый включатель новый коасс
    Ответ написан
  • Как правильно работать с Adjacency List в Eloquent/Laravel, если ключ типа uuid?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    Ну вот что я и писал вчера. Как взлетать с Ларавель никто не знает, так обозвали меня и погнали палкой за вопрос

    Потому что если взглянуть в исходник, то
    public function saveMany($models)
        {
            foreach ($models as $model) {
                $this->save($model);
            }
    
            return $models;
        }


    И где ты тут айдишники видишь?
    Он тупо залил, в базе наверное 0 по умолчанию (NOT NULL DEFAULT 0). Или в модели сразу стоит
    $attributes[] = ['parent_id' => 0];

    Добро пожаловать в мир ларавеля, где все знают что он прекрасен, но тебе никто не поможет, потому что он же прекрасен

    Тут конечно нет никакой идеи, но если предположить что я её понял, то там так
    foreach ($childrens as $child) {
      $child->parent()->associate($child)->save();
    }


    Хотя если порыться глубже, то там вроде как присутствует ->setForeignAttributesForCreate(), который должен это делать, но ему то ли геттер не отдает значение, то ли сеттер лочит установку, то ли там еще тыща причин, кроче dd($relation = $this->childSections()), исходник в руки и каждый шаг на экран

    Почему нельзя наоборот? А хрен его знает
    Ответ написан
  • Как в Eloquent запросить все значения некоторого атрибута, который имеет связь many-to-many?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    Попробуй так:

    Products.php
    public function attributes()
    {
    return $this->hasManyThrough(Attributes::class, ProductsAttributes::class...); // тут надо загуглить правильный порядок ключей, не помню
    }

    $product = Products::first(); // берем продукт
    $query = $product->attributes(); // создаем запрос SELECT FROM attributes WHERE exists({subquery});
    $query->select('value')->where('id', 1)->get(); // все значения value, привязанные к первому продукту для аттрибута 1 (но здесь дичь какая-то обычно один атрибут на один продукт, а у тебя получается типа продукт может содержать аттрибут 1 несколько раз?)

    Если нужно вообще все values для всех продуктов то сразу
    Attributes::where('id', 1)->select('value')->get();
    Ответ написан
    Комментировать
  • Laravel 5.8. Почему не работает мутатор?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    Либо ты не передал $_POST['slug'] / $_GET['slug']

    Потом ты передаешь в slug $value, а потом его не используешь - берешь $this->manufacture. Он скорее всего пустой, потому что ты новую модель создаешь
    1) то есть он попробует SELECT * FROM manufacturers WHERE ... (пустой запрос в базу, если база на 300 пинге в облаке, +350мс на создание страницы)
    2) даже если это будет делаться на существующей модели - оно конечно сделает SELECT * и вытянет тебе все поля. Для этого обязательно используют with();

    Стоп чо? ты находишься в manufacture.php, там у тебя setSlug() и внутри $this->manufacture.... У тебя связь parent/child внутри этой таблицы? Откуда ты решил взять $this->manufacture?
    Ответ написан
    Комментировать