Cors — Http request Laravel => Lumen странные вещи происходят


Содержание

laravel/lumen problem with cors

larave lumen problem with cors with large data size

Please sign in or create an account to participate in this conversation.

The most concise screencasts for the working developer, updated daily.

There’s no shortage of content at Laracasts. In fact, you could watch nonstop for days upon days, and still not see everything!

Want us to email you occasionally with Laracasts news?

Nine out of ten doctors recommend Laracasts over competing brands. Come inside, see for yourself, and massively level up your development skills in the process.

Learn
Discuss
Extras

© Laracasts 2020. All rights reserved.
Yes, all of them. That means you, Todd.

Designed with by Tuds.
Proudly hosted with Laravel Forge and DigitalOcean.

Freek.dev

My team at Spatie is currenlty building Mailcoach, a solution to self host your e-mail newsletter. Mailcoach can be used a stand alone software or as a Laravel package. Subscribe now at Mailcoach to get a notification as soon as we release it.

Handling CORS in a Laravel application

Original – Jan 8th 2020 by Freek Van der Herten – 5 minute read

Recently we released laravel-cors. This package can add the necessary CORS headers of your Laravel app. In this post I’d like to give a quick explanation of what CORS is and how you can use the package.

What is CORS #

Imagine that all JavaScript code for domain X running in a browser would be able to make http requests to an domain Y. Malious code on domain X would be able to interact with site Y without you knowing. In most circumstances you don’t want this. Luckily all major browsers only allow sites to make requests against their own domain. They don’t allow JavaScript code to make request against a sites on different domains. This is called the same-origin policy.

But there are some scenarios where you do want to allow that behaviour. Think of an API running on domain X that you want to consume via JavaScript running on domain Y. CORS stands for cross-origin resource sharing. It’s a standardized way to legitimately poke some holes in the same-origin policy.

Simple requests #

When JavaScript running on domain X performs a HEAD GET or certain POST request (with application/x-www-form-urlencoded , multipart/form-data or text/plain to domain Y the browser will add an Origin header. The application running on domain Y can use this header to check if the request is permitted. If the server responds with a header Access-Control-Allow-Origin containing the domain X then the browser will conclude that request was allowed. If the server didn’t do that most browsers won’t allow the JS on domain X to perform any requests towards domain Y.

All other requests #

All requests covered by the previous section will probably only be used to retrieve some data. All other ones such as certain POST requests, PUT , PATCH , DELETE will probably modify existing data on the server. For those kinds of request the browser will send a preflight request before doing the actualy request.

This preflight request using the OPTIONS verb. The browser will also send along the Origin header mentioned in the previous section. The server should return a response with the Access-Control-Allow-Origin , Access-Control-Allow-Methods and Access-Control-Max-Age headers set. The Access-Control-Allow-Methods contains the HTTP verbs that are allowed. The Access-Control-Max-Age contains the time in seconds that no new preflight request should be sent.

Using spatie/laravel-cors #

Our spatie/laravel-cors package can handle verifying and setting all required headers for you. The package can be installed via Composer

After that you must register the Cors middleware

Your application will now allow cross origin request coming from all domains. You probably want to publish the config file and set the allow_origins key to all domains you will allow requests from. Here’s the default content of that config file.

Using CORS profiles #

Imagine you want to specify allowed origins based on the user that is currently logged in. In that case the DefaultProfile which just reads the config file won’t cut it. Fortunately it’s very easy to write your own CORS profile. A valid CORS profile is any class that extends Spatie\Cors\DefaultProfile .

Here’s a quick example where it is assumed that you’ve already added an allowed_domains column on your user model:

Don’t forget to register your profile in the config file.

In the example above we’ve overwritten the allowOrigins method, but of course you may choose to override any of the methods present in DefaultProfile .

In closing #

It might appear that this whole CORS business is something that aims to protect your server, but that is not the case. It’s primary purpose is to protect the user of the browser by not making any requests to unwanted other domains. Don’t see CORS as a mechanism to protect your server.

If you want to know more about our laravel-cors package, go check it out on GitHub. You could also opt to use Barry vd. Heuvel’s CORS package. Our package is a modern rewrite of the basic features of Barry’s excellent one. We created our own solution because we needed our configuration to be very flexible.

Be sure to also check out the packages our team has previously made. There’s probably something there that could be of use in your next project.


Stay up to date with all things Laravel, PHP, and JavaScript.

Follow me on Twitter. I regularly tweet out programming tips, and what I myself have learned in ongoing projects.

Every two weeks I send out a newsletter containing lots of interesting stuff for the modern PHP developer.

Expect quick tips & tricks, interesting tutorials, opinions and packages. Because I work with Laravel every day there is an emphasis on that framework.

Rest assured that I will only use your email address to send you the newsletter and will not use it for any other purposes.

Forum > How to handle CORS?

I want to be able to do a ajax (POST, GET) call from domain.com to api.domain.dev . \n

In my route if I do this \n

$headers = [\n ‘Access-Control-Allow-Origin’ => ‘http:\/\/domain.dev’,\n];\n\nreturn Response::json( $validator->messages(), 400, $headers);\n \n

Everything works. \n

I want to be able to create a filter named cors that places that header into the routes I decide, like so: \n

Route::filter(‘cors’, function($route, $request, $response)\n<\n $response->headers->set(‘Access-Control-Allow-Origin’, ‘http:\/\/domain.dev’);\n return $response;\n>);\n \n

And in my route I add that filter like so: \n

But then it stops working. Any help? \n»»/>

It allows you to set up different cors settings for different paths in a configuration file. \n»»/>

It allows you to set up different cors settings for different paths in a configuration file. \n \n

Yeah, I gave up on doing this this way, because it does not work and I have spend too much time trying to figure it. \n

laravel-cors solved my problem. \n»»/>

isCorsRequest($request))\n <\n return $next($request);\n >\n \n static::$allowedOrigin = $this->resolveAllowedOrigin($request);\n \n static::$allowedHeaders = $this->resolveAllowedHeaders($request);\n \n $headers = [\n ‘Access-Control-Allow-Origin’ => static::$allowedOrigin,\n ‘Access-Control-Allow-Methods’ => static::$allowedMethods,\n ‘Access-Control-Allow-Headers’ => static::$allowedHeaders,\n ‘Access-Control-Allow-Credentials’ => static::$allowCredentials,\n ];\n \n \/\/ For preflighted requests\n if ($request->getMethod() === ‘OPTIONS’)\n <\n return response('', 200)->withHeaders($headers);\n >\n \n $response = $next($request)->withHeaders($headers);\n \n return $response;\n >\n \n \/**\n * Incoming request is a CORS request if the Origin\n * header is set and Origin !== Host\n *\n * @param \\Illuminate\\Http\\Request $request\n *\/\n private function isCorsRequest($request)\n <\n $requestHasOrigin = $request->headers->has(‘Origin’);\n \n if ($requestHasOrigin)\n <\n $origin = $request->headers->get(‘Origin’);\n \n $host = $request->getSchemeAndHttpHost();\n \n if ($origin !== $host)\n <\n return true;\n >\n >\n \n return false;\n >\n \n \/**\n * Dynamic resolution of allowed origin since we can’t\n * pass multiple domains to the header. The appropriate\n * domain is set in the Access-Control-Allow-Origin header\n * only if it is present in the whitelist.\n *\n * @param \\Illuminate\\Http\\Request $request\n *\/\n private function resolveAllowedOrigin($request)\n <\n $allowedOrigin = static::$allowedOrigin;\n \n \/\/ If origin is in our $allowedOriginsWhitelist\n \/\/ then we send that in Access-Control-Allow-Origin\n \n $origin = $request->headers->get(‘Origin’);\n \n if (in_array($origin, static::$allowedOriginsWhitelist))\n <\n $allowedOrigin = $origin;\n >\n \n return $allowedOrigin;\n >\n \n \/**\n * Take the incoming client request headers\n * and return. Will be used to pass in Access-Control-Allow-Headers\n *\n * @param \\Illuminate\\Http\\Request $request\n *\/\n private function resolveAllowedHeaders($request)\n <\n $allowedHeaders = $request->headers->get(‘Access-Control-Request-Headers’);\n \n return $allowedHeaders;\n >\n>\n \n

В чем разница между Laravel и Lumen. Что выбрать?

Давайте рассмотрим в чем разница между Laravel и Lumen. Это 2 фреймворка от одного «производителя». То есть можно предположить, что они если не одинаковы, то очень похожи.

Цукерберг рекомендует:  Вакансии Idaproject

Так и есть. Но у них разное назначение и посему и разная начинка.

Laravel

Laravel – это своего рода швейцарский нож для веб-программиста. Тут есть всё: и валидация форма, и удобная ORM, и шаблонизация, и автоматические множественные связи, и очередь выполнения, и свой собственный шедулер, и отправка почты (со встроенным шаблонизатором и даже поддержкой маркдаун разметки), и удобная особенность в представлении данных в виде коллекций (как в C#, например), с которые расширяют стандартное понимание о массиве данных в PHP, и даже интерфейс для управления через коммандную строку есть (кстати, это очень клевая штука, которая позволяет управлять базой данных и наполением, создавать шаблоны моделей и контроллеров (в том числе с предзаполенными функциями) и много другое.

В общем здесь есть почти всё. Всё, чего не хватает, можно подключить через composer. И оно сразу будет работать. Система сама подхватывает нужные контроллеры, классы и модули. Достаточно просто сесть и написать бизнес-логику, что-то вроде: Клиенты::которые(‘средний чек’, ‘>’, ‘1000’)->вывести() (Client::where(‘invoice’, ‘>’, ‘1000’)->get() и Laravel выберет из базы данных всех клиентов с чеком больше 1000. Минимум настроек, всё работает как по волшебству.

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

Lumen

Lumen – это легковесный фреймворк, в котором отключено практически всё. Да, он основан на Laravel, но он пустой. В нём есть только ORM, которую ещё нужно подключить, чтобы она запускалась, и каркас для работы моделей и контроллеров. Даже в коммандной строке всё урезано. Но у него другая задача. Он создан для разработки простых и бескомпромисных маленьких приложений и API, которые даже не предполагают наличие веб-интерфейса (он может быть, но не предполагается). Так вот, чтобы отправить почту из Lumen, нужно не просто подключить модуль через composer, но и потанцевать с бубном, чтобы заработало – вот настолько всё урезано.

Зато разработать API или маленький контроллер, который будет выполняться по крону – вот главное призвание Lumen. Он легкий, простой. Ты можешь ничего дополнительно не включать, он просто обработает за тебя все запросы, и направит в нужный контроллер, в котором ты уже запишешь данные в БД или выдашь их обратно клиенту. Всё просто, но в том же время эллегантно.

Laravel по-русски

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

  • Форум
  • » Laravel 5.x
  • » Laravel 5.4.27 CORS

#1 19.06.2020 10:15:17

Laravel 5.4.27 CORS


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

Не в сети 19.06.2020

#2 19.06.2020 10:57:13

Re: Laravel 5.4.27 CORS

Не в сети 19.02.2015

#3 19.06.2020 14:33:27

Re: Laravel 5.4.27 CORS

Не в сети 19.06.2020

#4 19.06.2020 14:36:00

Re: Laravel 5.4.27 CORS

для того чтобы подключить на страницу скрипт с другого домена CORS не нужен, а вот адблок может запросто залочить какой-то скрипт или картинку просто из-за неудачно выбранного имени – в его наборах есть совершенно идиотские правила…

Не в сети 19.02.2015

#5 19.06.2020 14:37:20

Re: Laravel 5.4.27 CORS

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

Изменено adams (19.06.2020 14:40:04)

Не в сети 19.06.2020

#6 19.06.2020 14:43:59

Re: Laravel 5.4.27 CORS

Просто я не использую его и пробовал с 3 браузеров, итог — скрипт (урл) заблокирован, смотрю через вкладку нетворкс

Изменено adams (19.06.2020 14:45:18)

Не в сети 19.06.2020

#7 19.06.2020 15:52:59

Re: Laravel 5.4.27 CORS

спрашивай здесь. сделай скрин вкладки networks с ошибкой

Не в сети 19.02.2015

#8 19.06.2020 16:10:25

Re: Laravel 5.4.27 CORS

Подключаю на страницу

но если перейти по урл scr то все нормально отдает, как только я вашею на поддомен где весит ларавел тоже все ок

Изменено adams (19.06.2020 16:12:07)

Не в сети 19.06.2020

#9 19.06.2020 16:31:07

Re: Laravel 5.4.27 CORS

что-то с настройками веб-сервера – для первого запроса я вижу не до конца закрашенный зелёный замок – то есть 1.html открывается по https с валидным сертификатом, скрипты грузятся либо по http либо по https с невалидным сертификатом – ни то ни другое делать нельзя, любой браузер такие вещи блокирует без вариантов

Не в сети 19.02.2015

#10 19.06.2020 16:39:57

Re: Laravel 5.4.27 CORS


Я специально не закрасил, я создал тестовую стр на другом своем сайте с валидным шттпс, там же подключаю скрипт src=»https://site.com/1.js» разве он сам не выберет протокол? (скрипт грузиться с сайта без шттпс), просто знаю когда указывал src=»http://site.com/1.js» мне мозила сразу писала, что заблокирована часть смешанного контента, по этому я убрал «http:» и думал, что грузит нормально.

1)что вы имели введу под «что-то с настройками веб-сервера»? у меня стоит нгинкс + пхп фпм

2)если мой второй сайт использует протокол шттп, то мою либу можно подключить только на сайтах с шттп? если хочу, что бы и шттпс работал, то нужно купить сертификат и не настраивать пере адресацию? (что бы можно было и через шттп и через шттпс грузить)

Проясните пожалуйста, как писал выше могу оплатить. я чего-то думал что cors виноват

Изменено adams (19.06.2020 16:44:35)

Не в сети 19.06.2020

#11 19.06.2020 17:00:53

Re: Laravel 5.4.27 CORS

cors не используется при подключении скриптов со сторонних ресурсов

//site.com… должен подключать по тому же протоколу что и документ – это верно, но там https должен быть настроен тоже – должен быть валидный сертификат, соответствующий домену на который отправляется запрос. если сертификат невалидный или выдан для другого домена – такой контент будет считаться «недоверенным» и будет заблокирован. это я и имею в виду под настройками веб-сервера

я вижу в скриншоте только зачёркнутый замок на хосте – значит надо смотреть открывать сведения о запросе и смотреть – какой протокол, какой сертификат, там скорее всего будет описание ошибки

по второму вопросу – если документ загружен по http – он может подключать ассеты (стили, скрипты, изображения) с любого хоста по http либо по https с валидным сертификатом (соответствующим домену, заверенным центром сертификации). если сайт загружен по https с валидным сертификатом – он может подключать ассеты только с хостов по https с валидным сертификатом. если сайт загружен по https с самоподписанным или невалидным сертификатом он может подключать ассеты либо с того же хоста либо с хостов по https с валидным сертификатом. это всё

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

Не в сети 19.02.2015

#12 19.06.2020 17:11:19

Re: Laravel 5.4.27 CORS

На скрине где зачекнут замок идет шттп обычное, не более того, и вы про логи нгикса говорите «скрипты грузятся либо по http либо по https с невалидным сертификатом – ни то ни другое делать нельзя, любой браузер такие вещи блокирует без вариантов»?

Хотите сказать, что если я сделаю обычный самоподписанный сертификат, то сайты с валидным шттпс смогут спокойно загружать мою либу?(насчет самоподписанного, мне мозила вечно просит внести в исключение, по этому лучше приобрети)

Спасибо, я чуть позже перепроверю все! С меня как и говорил мини бонус полагается (напишите в пм номер вм кошелька, пришлю на пиво)

Пс. мини вопрос по https://laravel.ru/docs/v5/eloquent-relationships
Я правильно понимаю, что настройка отношений в итоге даст мне обьект с данными из 2 и тп. таблиц?
И что в продакшене будет производительней? С ларавелем работаю около месяца, но отношения пока не трогал, все данные получаю с помощью моделей Model::whereIn(‘ >plunk(‘key’, ‘id’)->toArray())->get(); мне кажется это менее затратным по ресурсам или ошибаюсь?

Изменено adams (19.06.2020 17:13:14)

Не в сети 19.06.2020

#13 20.06.2020 07:15:50

Re: Laravel 5.4.27 CORS

На скрине где зачекнут замок идет шттп обычное, не более того, и вы про логи нгикса говорите

это не про логи нджинкса, это про политику безопасности браузеров в отношении https и доменов которые его используют

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

не смогут. самоподписанный сертификат не считается валидным – браузер же не знает, кто его выдал, может быть кто-то кто перехватывает трафик и подсовывает свой левый код в страницы? https решает не только и не столько проблему шифрования, сколько обеспечение подлинности источника данных и контента который им предоставлен

С меня как и говорил мини бонус полагается (напишите в пм номер вм кошелька, пришлю на пиво)

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

мне кажется это менее затратным по ресурсам или ошибаюсь?

ошибаешься. то что ты описываешь уже реализовано в моделях, почитай раздел про «жадную загрузку» (eager loading в оригинальной документации) – оно как раз для того и сделано чтобы одним запросом можно было загрузить все связанные модели и разложить их куда нужно. это намного проще и работает эффективно

Не в сети 19.02.2015

#14 20.06.2020 12:08:18

Re: Laravel 5.4.27 CORS

Уже глянул, надо подробнее вникнуть, я просто русскую версию смотрел, а это критическое «исправление», просто у меня уже прилично кода использует такие «зависимости», вот и думаю если ли смысл переписать? или можно оставить, а на будущее писать через https://laravel.com/docs/5.4/eloquent-r … one-to-one one-to-one мне же это подходит, если я хочу связать данные с одной таблицы с данными с другой? и последний вопрос, я правильно понимаю, что на выходе будет один объект с общими данными из двух таблиц?(или будет вложенность объектов?!)

Изменено adams (20.06.2020 12:09:35)

Не в сети 19.06.2020


#15 20.06.2020 12:35:59

Re: Laravel 5.4.27 CORS

если ли смысл переписать?

one-to-one мне же это подходит, если я хочу связать данные с одной таблицы с данными с другой?

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

я правильно понимаю, что на выходе будет один объект с общими данными из двух таблиц?(или будет вложенность объектов?!)

связи на моделях представлены как их атрибуты. для hasOne и belongsTo такой псевдоатрибут содержит единичную модель, для hasMany и belongsToMany – коллекцию моделей

Background

I am developing an Ionic apps and a Lumen application as REST API. This Lumen deployed in Docker container with port 81 exposed while the Ionic run in chrome browser. The communication between them figured as below:

When I ran the ionic it’s showing CORS error and caused the app stop working.

Why it happen?

According to Mozilla developer website, CORS happen when a web application tried to send requests to resource that has a different origin (domain, protocol, and port) than its own origin. In my case, http request was made from same host as target resource ( localhost) but different port number.

Цукерберг рекомендует:  Алгоритм - Сложность алгоритма

Solution

If you google “how to fix/allow CORS” then you’ll find some websites tells you to add extra headers to your HTTP response by modifying web server configuration. But there is another way you can do in case you have a very little experience with server configuration or you were unable to reach infra guys to ask their help, fix it with Middleware.

What is M >Middleware is a mechanism for filtering HTTP request coming to your application so you can easily modify HTTP Request and Response in a very convenient way.

Now let’s get to step-by-step:

Create The >Create a new file CorsMiddleware.php inside directory app\Http\Middleware

This class is used to modify Http Response header, what important here is line number 22 where we tell browser to accept request from any sources (*)

HTTP Requests (HTTP-запросы)

Получение объекта HTTP-запроса

При помощи фасада

Фасад Request дает доступ к объекту HTTP-запроса:

Не забудьте использовать конструкцию use Request; в начале файла класса.

При помощи DI (dependency injection)

Можно получить объект HTTP-запроса при помощи DI (dependency injection, внедрение зависимости). Способ заключается в том, что в аргументы конструктора контроллера помещается (type-hint) объект, который нам нужен, и Laravel, когда создает контроллер, создает этот объект (см. сервис-контейнер) и подает на вход конструктору контроллера:

Если ваш метод контроллера ожидает параметр из роута, укажите его после зависимостей:

Входные данные

Получение входных данных

Объект Illuminate\Http\Request предоставляет доступ к входным данным, например, к переменным POST или PUT, полученным из формы. Вам не нужно указывать явно метод запроса, есть универсальный метод:

Получение переменной с дефолтным значением

Определение, содержится ли переменная в запросе

Получить все переменные запроса

Получить избранные переменные

C массивами можно работать через нотацию с точкой:

Предыдущие входные данные

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

Сохранение запроса во flash-переменных сессии

Метод flash сохранит текущие входные данные в сессии, так, что они будут доступны в следующем запросе.


Сохранение избранных переменных запроса

Редирект

Since you often will want to flash input in association with a redirect to the previous page, you may easily chain input flashing onto a redirect.

Чаще всего нам нужно сохранить данные и сделать редирект на урл с формой. В Laravel есть способ записать это просто и коротко:

Получение предыдущих данных

Чтобы получить сохранённые в сессии данные запроса, используйте метод old :

Для использования в шаблонах можно использовать этот простой хэлпер:

Все куки, которые пишет Laravel, зашифрованы — это значит, что на клиенте они не могут быть изменены. Изменённую на клиенте куку фреймворк просто не сможет расшифровать и прочесть.

Получение значения куки

Добавить новую куку к запросу

Хэлпер cookie создает объект Symfony\Component\HttpFoundation\Cookie . Полученный класс может быть добавлен к HTTP-ответу (response) методом withCookie :

Создание вечной куки

«На самом деле нет». Время жизни «вечной» куки — 5 лет.

Файлы

Получение загруженного файла

Определение, загружался ли файл в запросе

Метод file возвращает экземпляр класса Symfony\Component\HttpFoundation\File\UploadedFile , который расширяет стандартный PHP-класс SplFileInfo и содержит все его методы.

Определение валидности загруженного файла

Перемещение загруженного файла

Другие методы работы с файлами

Полный список методов класса Symfony\Component\HttpFoundation\File\UploadedFile смотрите справке API.

Другая информация о запросе

The Request class provides many methods for examining the HTTP request for your application and extends the Symfony\Component\HttpFoundation\Request class. Here are some of the highlights.

Класс Request предоставляет множество методов позволяющих работать с HTTP-запросами в вашем приложении, является расширением класса Symfony\Component\HttpFoundation\Request . Вот некоторые из основых методов:

20 хитростей в Laravel Eloquent о которых вы не знали

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

1. Инкременты и Декременты

$article = Article::find($article_id);
$article->read_count++;
$article->save();

Вы можете делать так:

$article = Article::find($article_id);
$article->increment(‘read_count’);

Article::find($article_id)->increment(‘read_count’);
Article::find($article_id)->increment(‘read_count’, 10); // +10
Product::find($produce_id)->decrement(‘stock’); // -1

2. XorY методы

В Eloquent существует несколько методов которые можно объеденять в один, что-то вроде «Сделай Х, и в случае неудачи сделай Y».

Пример 1: findOrFail():

$user = User::find($id); if (!$user)

Вы можете делать так:

Пример 2: findOrCreate():

Вместо вот такого:


$user = User::where(’email’, $email)->first();
if (!$user) <
User::create([
’email’ => $email
]);
>

Лучше делать вот так:

$user = User::firstOrCreate([’email’ => $email]);

3. Метод boot()

В методе boot() вы можете переопределить поведение Eloquent модели:

class User extends Model
<
public static function boot()
<
parent::boot();
static::updating(function($model)
<
// do some logging
// override some property like $model->something = transform($something);
>);
>
>

Самым распростронненным примером использования метода boot() — установка значения по-умолчанию для какого-либо поля. Например, сгенерируем UUID в момент создания модели:

public static function boot()
<
parent::boot();
self::creating(function ($model) <
$model->uu > >);
>

4. Relationship с условиями и сортировкой

Вот так обычно определяют отношения:

public function users() <
return $this->hasMany(‘App\User’);
>

Но знали ли вы, что уже на данном этапе можно добавить orderBy? Например, если мы хотим добавить relation только для определенного типа пользователей, с сортировкой по email, то мы можем сделать так:

public function approvedUsers() <
return $this->hasMany(‘App\User’)->where(‘approved’, 1)->orderBy(’email’);
>

5. Свойства модели: timestmap, appends, и т.д.

В Eloquent модели имеется несколько свойств, о которых многие не знают. Самые популярные:

class User extends Model <
protected $table = ‘users’;
protected $fillable = [’email’, ‘password’]; // which fields can be filled with User::create()
protected $dates = [‘created_at’, ‘deleted_at’]; // which fields will be Carbon-ized
protected $appends = [‘field1’, ‘field2’]; // additional values returned in JSON
>

Но существуют и другие, такие как:

protected $primaryKey = ‘uuid’; // Если у вас нету поля ‘id’
public $incrementing = false; // Указывает что primary key не имеет свойства auto increment
protected $perPage = 25; // А тут мы переопределяем кол-во результатов на странице при пагинации (по-умолчанию: 15)
const CREATED_AT = ‘created_at’; const UPDATED_AT = ‘updated_at’; // А этими константами можно переопределить название полей для created_at и updated_at
public $timestamps = false; // или можно указать что мы вообще не используем поля created_at и updated_at

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

6. Поиск нескольких записей

Все знают про метод find(), верно?

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

7. WhereX

В Eloquent существует элегантный способ превратить это:

$users = User::where(‘approved’, 1)->get();

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

Так же существует несколько подобных методов для работы с датами, которые Eloquent содержит изначально:

User::whereDate(‘created_at’, date(‘Y-m-d’));
User::whereDay(‘created_at’, date(‘d’));
User::whereMonth(‘created_at’, date(‘m’));
User::whereYear(‘created_at’, date(‘Y’));

8. Сортировка по relation

Более сложный трюк. Что если у нас есть форумные темы и мы хоти отсортировать их по дате последнего поста? Довольно таки обыденная задача, верно?

Для начала мы пропишем отдельную связь latest post в модели темы:

public function latestPost()
<
return $this->hasOne(\App\Post::class)->latest();
>

И затем, в нашем контроллере, мы можем творить магию:

9. Eloquent::when() — избавляется от if-else

Многие из нас пишут подобные условные конструкции:

if (request(‘filter_by’) == ‘likes’) <
$query->where(‘likes’, ‘>’, request(‘likes_amount’, 0));
>
if (request(‘filter_by’) == ‘date’) <
$query->orderBy(‘created_at’, request(‘ordering_rule’, ‘desc’));
>

Но есть более изящный способ это сделать:

$query = Author::query();
$query->when(request(‘filter_by’) == ‘likes’, function ($q) <
return $q->where(‘likes’, ‘>’, request(‘likes_amount’, 0));
>);
$query->when(request(‘filter_by’) == ‘date’, function ($q) <
return $q->orderBy(‘created_at’, request(‘ordering_rule’, ‘desc’));
>);


10. BelongsTo и Модель по-умолчанию

Представим что у нас есть модель Post, которая belongsTo к модели Author, и мы выводим автора в шаблоне:

Но что случится если модель автора удалена или null по какой-нибудь причине? Будет ошибка! Конечно мы может сделать проверку:

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

public function author()
<
return $this->belongsTo(‘App\Author’)->withDefault();
>

В данном примере relation author() вернет пустую модель Author, если в Post нету связи с реальной моделью. Мы можем даже указать свойства по-умолчанию для этой пустой модели:

public function author()
<
return $this->belongsTo(‘App\Author’)->withDefault([
‘name’ => ‘Guest Author’
]);
>

11. Order by Mutator

Представим что у нас есть такой код:

function getFullNameAttribute()
<
return $this->attributes[‘first_name’] . ‘ ‘ . $this->attributes[‘last_name’];
>

Вы хотите сделать сортировку по full_name? Такой подход не сработает:

$clients = Client::orderBy(‘full_name’)->get(); // так не работает

Решение довольно простое. Мы должны сортировать результаты ПОСЛЕ того как мы их получили:

$clients = Client::get()->sortBy(‘full_name’); // а вот так работает!

Обратите внимание что мы используем не orderBy, а sortBy, функцию из Collection .

12. Сортировка по-умолчанию для глобального scope

Что если мы хотим, чтобы запрос User::all() всегда был отсортирован по полю name ? Мы можем назначить глобальный scope для определения такого поведения. Давайте вернемся к методу boot(), о котором мы говорили ранее, и используем его:

protected static function boot()
<
parent::boot();

// Order by name ASC
static::addGlobalScope(‘order’, function (Builder $builder) <
$builder->orderBy(‘name’, ‘asc’);
>);
>

Подробнее можно почитать в документации.

13. Raw запросы

Иногда нам нужно осуществлять «сырые» (raw) запросы к базе данных. К счастью Eloquent поддерживает и их:

// whereRaw
$orders = DB::table(‘orders’)
->whereRaw(‘price > IF(state = «TX», ?, 100)’, [200])
->get();

// havingRaw
Product::groupBy(‘category_id’)->havingRaw(‘COUNT(*) > 1’)->get();

// orderByRaw
User::where(‘created_at’, ‘>’, ‘2020-01-01’)
->orderByRaw(‘(updated_at — created_at) desc’)
->get();

14. Replicate: создать копию записи

Очень коротко: вот так можно создать копию записи в базе данных:

$task = Tasks::find(1);
$newTask = $task->replicate();
$newTask->save();

15. Метод Chunk для больших таблиц

Это больше относится к коллекциям, а не к Eloquent, но все равно. Если у вас есть большая таблица (с тысячами записей) и вы не можете получить их все за один запрос, то можно использовать метод chunk , который будет доставать записи по «чуть-чуть»:

User::chunk(100, function ($users) <
foreach ($users as $user) <
// .
>
>);

16. Создаем дополнительные вещи при создании модели

Все мы знаем про команду php artisan make:model Company . Но знали ли вы, что вы сразу можете сгенерировать: миграцию, контроллер, и даже указать что контроллер должен быть REST? Используя дополнительные флаги мы можем сделать это одной командой:

php artisan make:model Company -mcr

Где флаги означают:

  • m — создать файл миграции
  • c — создать контроллер
  • r — контроллер должен быть REST

17. Не обновлять update_at при сохранении


Зналил ли вы, что метод ->save() принимает дополнительные параметры? Например, мы можем указать что не нужно обновлять timestamps, если нам это не нужно:

$product = Product::find($id);
$product->updated_at = ‘2020-01-01 10:00:00’;
$product->save([‘timestamps’ => false]);

Такой код не будет обновлять update_at при вызове save() .

18. Узнать результат update()

Задавались ли вы когда-нибудь вопросом что возвращает такой код:

$result = $products->whereNull(‘category_id’)->update([‘category_id’ => 2]);

Я имею ввиду не что конкретно делает метод update() , а что в результате будет в переменной $result ?

Ответ: кол-во затронутых строк! Так что если вы захотите узнать сколько строк обновил ваш вызов update() — вам не требуется ничего делать! Вы можете просто посмотреть на значение которое он вернул.

Цукерберг рекомендует:  Macos - Конфигурация MacBook для программирования

19. Преобразование скобочек из SQL в Eloquent запрос

Что если у вас имеется подобный SQL запрос:

. WHERE (gender = ‘Male’ and age >= 18) or (gender = ‘Female’ and age >= 65)

Как правильно составить Eloquent запрос для него? Вот так неправильно:

$q->where(‘gender’, ‘Male’); $q->orWhere(‘age’, ‘>=’, 18);
$q->where(‘gender’, ‘Female’);
$q->orWhere(‘age’, ‘>=’, 65);

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

$q->where(function ($query) <
$query->where(‘gender’, ‘Male’)
->where(‘age’, ‘>=’, 18);
>)->orWhere(function($query) <
$query->where(‘gender’, ‘Female’)
->where(‘age’, ‘>=’, 65);
>)

20. orWhere с несколькими параметрами

В завершение: вы можете передавать массив параметров в orWhere() метод. Обычно делают так:

Вы же можете быть более крутыми, и делать вот так:

Я уверен что существует еще множется трюков, о которых мы не знаем. Возможно кто-то поделится ими в комментариях.

Lumen — новый PHP-микрофреймворк от разработчика Laravel

Буквально несколько дней назад Taylor Otwell, разработчик широко известного и, наверное, наиболее популярного в западном мире фреймворка Laravel, написал в своем твиттере, что помимо Laravel он готовит к выпуску кое-что еще, чем, конечно же, заинтриговал подписчиков.

What if Laravel 5.1 isn’t the only framework I’m preparing for release? http://t.co/7oHVioDRYr

Долго ждать не пришлось. Уже через неделю был представлен Lumen, микрофреймворк на основе компонентов Laravel. Почему он так называется — «Lumen»? Потому что компоненты Laravel, как известно, носят название Illuminate.

Что же собой представляет этот фреймворк? Давайте посмотрим.

Размер чистого фреймворка на диске — что-то около 10 МБ. Не такой уж он и маленький! Тем не менее, это не мешает ему называться «микро», поскольку «микро» — это не только размер.

Внутри — компоненты Laravel 5. Модели Eloquent, авторизация Auth, шаблоны Blade, а также валидация, кэш, middleware, DIC и прочее.

Роутинг основан на библиотеке FastRoute, что позволяет ему быть довольно шустрым.
Тэйлор заявляет скорость бо́льшую, чем у микрофреймворка Slim, и уж еще бо́льшую, чем у Silex.

Третья версия Slim, которая еще не вышла, но уже потихоньку готовится, также пишется на роутере FastRoute.

Синтаксис Lumen классичен для микрофреймворков на PHP:

Также поддерживаются контроллеры-классы:

Руководство по кросс-доменным запросам (CORS)

На прошлой неделе я внедрял в проект CORS-запросы – современный способ кросс-доменного Аякса. По следам прочитанной документации и набитых шишек подготовил небольшой мануал. Это вольный пересказ англоязычных статей, вопросов со Стека и скромный личный опыт.

Но сначала короткая предыстория. Я неравнодушен к собеседованиям, как вы, наверное, знаете. Чаще я собеседовал бекенд, т.к. к фронтенду отношусь прохладно. Но тема фронтенда обладает огромным потенциалом для оценки уровня кандидата. Я считаю, что разработчик должен в деталях понимать протокол HTTP и тонкости работы браузера.

Один из вопросов на тему фронтенда звучит банально: как на клиенте получить данные с другого домена?

Некоторые кандидаты отвечают, что проблемы нет, достаточно выполнить Аякс-запрос. И с большим удивлением узнают, что, оказывается, нельзя: сработают какие-то там политики безопасности.

Один собеседуемый заявил, что в Фаерфоксе это работает, достаточно зайти на страницу для разработчиков и что-то там переключить. Я не против такого ответа. Следующий вопрос, как вы заставите всех пользователей установить именно Фаерфокс и поменять системный флаг?

С понятием JSONP вообще беда – никто не может объяснить, как это устроено. Разработчики думают, что это обычный Аякс, только с каким-то P на конце, то ли баг, то ли фича. А это вообще ни разу не Аякс.

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


Разберем вопросы из предыдущих абзацев. Действительно, слать Аякс-запросы к серверам с другим доменом запрещено на уровне браузера. Однако, в интернете полно сайтов, где значимая часть контента подгружается со сторонних серверов. Например, этот блог работает на статичном генераторе Jekyll, в котором нет комментариев. Делиться мнениями помогает сервис Discuss: лента комментариев встраивается Джаваскриптом. Получая и отправляя комментарии, вы взаимодействуете с серверами Discuss, а мой блог вообще ни при чем. Значит, слать запросы Аяксом все же можно?

Нет, здесь работает JSONP. Аббревиатура значит JSON with Padding (с подкладкой). Идея основана на лазейке в стандартах: загружать скрипты с других доменов не запрещено! Скажем, если в файле example.js на чужом сервере написано что-то вроде:

, то достаточно подгрузить его тегом

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

Предположим теперь, что сервер отдает не статичный файл, а генерит его динамически в зависимости от параметров. Например, мы добавляем на страницу скрипт с адресом:

В переменой method указываем, какое действие требуем от сервера. В данном случае, получить пользователя по идентификатору. Айдишку передаем следующим параметром user_id . Пусть такой пользователь найден на сервере, теперь его нужно отдать клиенту. Если просто выплюнуть объект:

, то на клиенте ничего не произойдет: объект просто считается в память. Именно поэтому передают третий параметр callback – имя функции, объявленной на клиенте, в которую нужно завернуть пользователя. С этим параметром ответ станет другим:

На клиенте отработает код, зашитый в функцию processUser : вывести данные в консоль, отрисовать виджет и т.д. Вот как работает JSONP.

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

Далее, подгрузка скриптов ни разу не безопасней, чем Аякс. Целое семейство вирусов занимается тем, что добавляет на страницу браузера скрипты для отрисовки баннеров порно и казино. Когда вы подключаетесь к интернету через мобильных операторов, обсосы вставляют в HTML-трафик скрипты для отрисовки виджетов (если соединение не HTTPS).

JSONP работает только методом GET, что сводит на нет возможности REST-интерфейса. Для REST-сервисов приходится писать прокладки-прокси, т.е. множить костыли.

Добавив скрипт на страницу, в дальнейшем вы не можете отследить его судьбу. Если у Аякс-запроса есть специальные коллбеки для основных событий (начало, удачное завершение, таймаут, неудачное завершение), то у скрипта ничего такого нет. Загрузился ли он? Ответил ли сервер? Была ли ошибка? Никто не знает.

Ясно, что в 2020 году приложениям на js нужен надежный способ забирать данные с серверов. Чтобы это была законно, а не по-воровски в обход протоколов и стандартов. Таким способом стал CORS – Cross-Origin Resource Sharing , кросс-доменные запросы.

Идея проста – пусть клиент шлет Аякс-запрос к чужому серверу. Браузер добавит в запрос особые заголовки с информацией о том, что запрос с другого домена. На их основании сервер решит, как обрабатывать такой запрос, и добавит особые заголовки в ответ. Удобно, правда?

Техническая реализация несколько сложнее. Стандарт CORS различает “простые” и “сложные” запросы. Простым считается запрос методами:

  • Accept
  • Accept-Language
  • Content-Language
  • Last-Event-ID
  • Content-Type, но только со значениями:
    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain

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

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

и ответа с разрешением на получение данных:

Обратите внимание на такую вещь: мы намерены использовать CORS, чтобы дергать чужие API. С вероятностью почти 100% они работают по протоколу JSON , то есть принимают и отдают заголовок Content-Type: application/json . Вроде бы мелочь, но такой запрос автоматом перестает быть простым и переходит в разряд “сложных”, где схема взаимодействия иная.

Сложные запросы проходят в два этапа. Сначала браузер делает запрос по тому же урлу, но методом OPTIONS . Сервер должен ответить: какими другими методами и дополнительными заголовками (помимо стандартных) можно обращаться к этому урлу. И только получив разрешение, браузер сделает запрос на основной урл.

При этом браузер не дурак и все запомнит: если разрешили только методы GET и POST, то PUT и DELETE не сработают. Аналогично с заголовками: если помимо стандартных разрешено использовать только Authorization , то нужно передать его и ничего другого.

Пример сложного запроса:

Клиент хотел отправить Аяксом запрос методом PUT на урл http://api.alice.com/cors с сайта http://api.bob.com . Поскольку это сложный запрос, браузер запросил разрешение: типа, хочу сделать PUT на этот урл с особым заголовком X-Custom-Header . Сервер ему на это:

Или иными слвами: разрешено ходить методами GET, POST, PUT и с заголовком X-Custom-Header. Это подходит под критерии первоначального запроса. Браузер делает второй запрос куда мы намеревались вначале.

Первая стадия, когда делается запрос OPTION, официально называется preflight request . Надо сказать, такое взаимодействие весьма прозрачно отражается в браузере. Например, в консоли разработчика в Хроме видны оба запроса со всеми заголовками.

Вот такие строгости. В нашем проекте API на стороне сервера требует заголовки Version (версия операции), Authorization (авторизация по токену) и Content-Type (JSON), поэтому в ответе указываем

, иначе запрос не пройдет.

Теперь все это можно протестировать. Запускаем локальный сервер, открываем консоль Хрома и пишем:

Забавно, что заголовок Origin в этом случае будет равен https://google.com , потому что Хром считает пустой страницей главную Гугла.

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

Несмотря на кажущуюся простоту, реализовать поддержку CORS на сервере требует времени. Первоначально я хотел использовать чужую библиотеку, но после 10 минут чтения исходного кода понял, что автор НЕПРАВИЛЬНО понял спецификацию и реализовал ее с ошибками. Лишний раз убедился, авторы сторонних библиотек – не боги, а такие же смертные. Они могут тупить, ошибаться. Лучше потратить день на чтение спеки и сделать все правильно, чем доверять первому встречному решению.

Расскажу теперь о тонкостях, с которыми столкнулся при внедрении CORS в проекте. Прежде всего, чтобы сократить число preflight-запросов, стоит либо кешировать эндпоинт OPTIONS заголовками:

, либо вообще объявить его на уровне Nginx:

Еще одна тонкость: даже если возвращаете ответ с не-положительным статусом, например, не прошла валидация или нет прав, заголовок Access-Control-Allow-Origin обязан присутствовать. Если заголовка нет, браузер решит, что CORS-запрос запрещен и не прочитает ответ.

В нашем случае это вылилось в следующее: CORS-декоратор оборачивал ответ в заголовки только в положительном случае. Если не проходила валидация, приложение отсылало ответ еще до того, как доходила очередь декоратора. Браузер не мог внятно сказать, почему не прошел запрос. Пришлось поднять декоратор на самый верх стека.

С CORS разобрались, теперь не будет лишним почитать другое руководство про часовые пояса

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

Сайт, целиком посвященный CORS: описание, статьи, конфиги, примеры кода.

Понравилась статья? Поделиться с друзьями:
Все языки программирования для начинающих