https://qiita.com/castaneai/items/d5fdf577a348012ed8af
とりあえず動かしたいんじゃってときは、以下が便利 https://gist.github.com/Ryomasao/d0eecd7c5311b9c8984d6d8fba098ac9
$ docker run -d -p 8000:80 --name my-apache-php-app -v "$PWD":/var/www/html php:7.2-apache
$ docker exec -it コンテナ名 bash
リモートデバックなので、ローカル環境にPHPはいらない。 リモート環境とPHPをあわせようとしてanyenv→phpenv導入しようとしたけど、Mojaveからめちゃくちゃめんどくさくなってて萎えた。
リモートデバックそのものは、この記事がとてもわかりやすい https://qiita.com/castaneai/items/d5fdf577a348012ed8af
.vscode/launch.json
{
"version": "0.2.0",
"configurations": [
{
"name": "XDebug on vagrant",
"type": "php",
"request": "launch",
"port": 9000,
"pathMappings": {
// {vagrant上のdocument root}:{ローカルのdocument root}
"/mnt/fuelphp": "${workspaceFolder}/fuelphp"
},
// BreakPointとまんねえって時はとりあえず、entry時にとまるか確かめよう
"stopOnEntry": false
}
]
}
xdebug.remote_enable = 1
; このホストのIPはvagrant内から見た、ホストOSのIP
; なんでこの値になるんだっけ。
xdebug.remote_host = "10.0.2.2"
autostart
の設定をしてもいいけど、クエリパラメータ指定すると起動してくれる。いいね!
http://localhost:8000/?XDEBUG_SESSION_START=test
dockerで使う場合は以下の設定にした。 この辺も参考になりそう。 https://stackoverflow.com/questions/52579102/debug-php-with-vscode-and-docker
普通にコンテナ起動して、VScodeでデバッカ起動して、phpunit実行したら止まった。すごい。
"stopOnEntry": false
をtrueにしてもエラーも吐かずに、デバックできないときがあって、コンテナ落としあげしたら解消した。
; 参考にさせていただいた記事
; https://qiita.com/gigosa/items/90431be7a6a79db78480
[xdebug]
; この設定は、docker-php-ext-enable xdebugを行うことで、以下に書かれる
; /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
#zend_extension=/usr/local/lib/php/extensions/no-debug-non-zts-20190902/xdebug.so
xdebug.remote_enable=1
xdebug.remote_autostart=1
xdebug.remote_connect_back=0
; ホスト側のIP
; host.docker.internalはdockerのhostマシンのIPを解決する
; LAMP環境のDockerを提供するDevitypeだと、docker for Macでhost.docker.internalが使えねえ的は話があった
; 自分の環境だととりあえず大丈夫だった
; https://devilbox.readthedocs.io/en/latest/intermediate/configure-php-xdebug/macos/vscode.html#configure-php-xdebug-mac-vscode
xdebug.remote_host=host.docker.internal
; 空いているport番号(xdebugのデフォルトは9000)
xdebug.remote_port=9001
;xdebugの出力するログの場所
xdebug.remote_log=/tmp/xdebug.log
リポジトリ https://github.com/Ryomasao/hello-graphql/tree/master/server
1.設定済みのプロジェクトルートに移動
$ cd hello-graphql/server
$ code .
2.docker拡張から、graphqlコンテナを起動して、Remote拡張からアタッチしてコンテナの中に入る。
3.VSCode側で、デバックを開始する 4.コンテナの中でphpを実行するとステップ実行できる。最高だ。
こっちにも書いてる。 https://github.com/Ryomasao/hello-graphql/tree/master/server
PHPに関することはこっちにも転記する。
php では、別ファイルは読み込むにはrequireとincludeがある。 requireは指定されたパスのファイルがなかったり、ファイル内で構文エラーがあったりすると、FatalError になるのに対し、includeは waning でになるとのこと。
基本的にrequireを使えばいい気がする。
index.php
require('./moduleA.php");
https://github.com/Ryomasao/hello-graphql/blob/master/server/app/www/autoloader/index.php
php の組み込み関数であるspl_autoload_register
で実装されてる。
これは、クラスを new する際に呼び出す関数を設定することができる。
これを使って、ある程度自動でrequireする仕組みを構築することができる。
class ClassLoader
{
private $dirs;
public function registerDir($dir)
{
$this->dirs[] = $dir;
}
public function register()
{
// spl_autoload_registerは、定義されてないクラスがインスタンス化されたときに呼び出される
// ここでは、loadClassメソッドが呼び出される
// sql_autoload_registerには、callableな値を渡す
// https://www.php.net/manual/ja/language.types.callable.php
spl_autoload_register(array($this, 'loadClass'));
}
public function loadClass($class)
{
// loadClassメソッドは、new Class名のクラス名をもとに、requireを実行する。
// requireする際のディレクトリはregitserDirで事前に設定しておく必要あがる。
print("load class:$class\n");
foreach ($this->dirs as $dir) {
$file = "$dir/$class.php";
if (is_readable($file)) {
require($file);
return;
}
}
}
}
$loader = new ClassLoader();
$loader->register();
$loader->registerDir('./otherDir');
$sample = new Sample();
composerも同じようなことをしてる。
https://github.com/Ryomasao/hello-graphql/tree/master/server/app/www/hellophp
composerを使うときは、index.php
とかに require('vendor/autoload.php');
を書くよね。
これを見てみると、とあるファイルをrequireして、クラスメソッドを実行してる。
<?php
// autoload.php @generated by Composer
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInitf3a755c714b88f92b071e828a83148e4::getLoader();
autoloader_real.php
をみると、spl_autoload_register
がいる。
直後にunregisterしてるのであれ、っておもったら、\Composer\Autoload\ClassLoader
を読み込むためだけに設定してるっぽい。
public static function getLoader()
{
if (null !== self::$loader) {
return self::$loader;
}
spl_autoload_register(array('ComposerAutoloaderInitf3a755c714b88f92b071e828a83148e4', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
spl_autoload_unregister(array('ComposerAutoloaderInitf3a755c714b88f92b071e828a83148e4', 'loadClassLoader'));
classLoaderをみると、こっちで再度registerしてた。
/**
* Registers this instance as an autoloader.
*
* @param bool $prepend Whether to prepend the autoloader or not
*/
public function register($prepend = false)
{
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
}
composerはnew App/Hoge
ってすると、spl_autoload_register
でcomposer.json
でマップした情報をもとにクラスを探してくれる。
マップ情報は実行時に json をみるとかじゃなくってcomposer dump-autoload
を実行することで、マップ情報が埋め込まれた php を生成してるんだ。
{
"autoload": {
"psr-4": {
// Appってつくものは、services配下にあるっていうマップ
"App\\": "services/"
}
}
}
クラスだけじゃなくって、以下のように helper 関数なんかも登録することができる。
{
"autoload": {
"psr-4": {
"App\\": "services/"
},
"files": ["helper/functions.php"]
}
}
以下のように、Appのnamespace配下にない、Carクラスを参照しようとしても、そんなクラスはねえよでこける。
composer.json
{
"autoload": {
"psr-4": {
"App\\": "services/"
},
}
}
index.php
require('vendor/autoload.php');
$car = new App\Car('car');
services/Car.php
<?
class Car {}
composerは、composer.jsonにかかれているマップ情報をもとにクラスを探しにいくから、App/Car
でCar.phpのinlcude自体は実はできている。
ただ、Appのnamsespace配下にないから、クラスがみつかんないよってなる。
namespaceとマップ情報の構造は合わせないとだめなんだね。
Fuelphpの流れを見てみる
index.php
// defineでAPPPATH、COREPATHとかのパスを定数として定義
// Fuelのcoreとして、autloaderをもってるっぽい。
// 中を見るとspl_autoload_registerしてた。
require COREPATH.'classes'.DIRECTORY_SEPARATOR.'autoloader.php'
autoloader.php
protected static function init_class($class, $file = null)
{
// requireじゃなくって、includeしてるっぽ?
// include the file if needed
if ($file)
{
include $file;
}
// おもしろいのが、constructorとは別に、init関数を実行してる
// インスタンス化のタイミングってより、初回autoload時なのかな
// if the loaded file contains a class...
if (class_exists($class, false))
{
// call the classes static init if needed
if (static::$auto_initialize === $class)
{
static::$auto_initialize = null;
if (method_exists($class, '_init') and is_callable($class.'::_init'))
{
call_user_func($class.'::_init');
}
}
}
↑ファイルは、APPPATHのclass配下を探してるっぽかった。
直前のクエリを見る
\DB::last_query();
Fuel/Core/Session
_init()
instance()
forge()
// Session_Driverに対して操作を行う
$driver-> new $class
$driver->init()
$driver->read()
// abstract
Fuel/Core/Session_Driver
※ Session_Driverを継承
Fuel/Core/Session_Memcached
constructor()
init()
read() {
// memcachedのkeyはcookieに格納されているセッションID。ただし、encryptされるので、そのままの値じゃない。
$key = _get_cookie
}
最後のkey一覧が素敵。ただ、localhostとは異なるホストに対してはkeyが取得できなかった。なんでだろ。 https://qiita.com/TatsuNet/items/5c89a2dbce57be28aef7
memcached-toolが使えるなら、以下でkeyとvalueが見れる。 key一覧がみたいときには工夫が必要ね。
memcached-tool localhost:11211 dump | less
memcachedのweigthについて。
https://stackoverflow.com/questions/10901480/php-memcacheaddserver-weight
memcachedの設定で、weight:100、weight:100の2台構成の設定があって、意味があるのか気になった。
怪しい結論なんだけど、weightはただの重み付けなので、上記であれば1:1の割合で分散させるってだけっぽい。 なんで合計100にしなくても、weight:30、weight:30でもいいんじゃないかなと思う。(未検証)
最初は、memcachedが片方死んでも大丈夫構成の意味かと思ったけど、少なくともfuelのmemcachedのserviceでは、addServerしたあとに、getStatsして定義したmemcachedが生きているか確認してる。1個でも死んだらエラーになる構成。 だからweight:100、weight:100で片方しんだら、50%に確率でmiss hitになるはず。
fuelPHPのバージョンを1.7から1.8にあげたとき、libsodium
をインストールしてねってログがでてた。
fuel1.8が依存してるパッケージがPHP7から実装された関数に依存してた。
どうも、PHP7より前はPHPのExtensionとして配布されてた機能がPHP7に標準搭載されたっぽい。
Fuel requires Sodium support in PHP. Either use PHP 7.2+, install the libsodium PECL extension, of the sodium-compat composer package! in /mnt/fuelphp/fuel/core/vendor/paragonie.php on 3
なので、libsodium
を別途入れなきゃいけないんだけど、remiリポジトリをみてもそれっぽいのがない。
ソースからビルドするか、PECLっていうPHPの拡張モジュールをインストールしてくれるやつを使う必要がでてきた。
PECLについては↓がとてもわかりやすそう。結局ちゃんと読んでない。
http://dqn.sakusakutto.jp/2015/07/php_extension_pecl_phpize.html
pecl search libsodium
してからpecl install libsodium
したんだけど、php5じゃ使えねえよっていわれっちゃった。
こういった場合、changelogを見て、指定のパッケージを落としてくるみたい。 ↓だと1系だとPHP5いけるっぽいね。 https://pecl.php.net/package-changelog.php?package=libsodium
なんだけど、この後インストールするために依存パッケージがまたでてきちゃって、そこまでして対応したくないなぁと思ったのでやめた。
DNSの問題とかいろいろあるんだけど、curlしてhttpsでこけてたらこれが原因
https://qiita.com/YumaInaura/items/ef1130eb67a47fe0f2da
$_POST
に全然入ってこねええってなってた。ほんで、公式をよく見ると、なんだと、、、案件。
Content-Type に application/x-www-form-urlencoded あるいは multipart/form-data を用いた
https://www.php.net/manual/ja/reserved.variables.post.php
全然わかってなかったね。
$_POST
に入ってこない形式のデータはphp://input
っていう、リクエストのbody部につながってるストリームを参照するみたい。
https://www.php.net/manual/ja/wrappers.php.php https://thisinterestsme.com/receiving-xml-via-post-php/
phpは関数を返す関数みたいなことはできないっぽい。
<?
function returnFunc() {
return function a($value) {
return $value + 1 ;
}
}
変数に関数をセットしたり引数に渡したりはできるから、いわゆる関数が第1級オブジェクトってやつなのかな。 PHPでクロージャーって言葉もあるんだけど、無名関数として使えるってだけで、jsのようにインスタンスぽく使えるものを指してるんじゃないんだと思った。 callbackとして渡す分にはがんがんつかってけそう。
<?php
$array = [1,2,3];
// mapって便利だよね
$new_array = array_map(function($value){
return $value * 2;
}, $array);
// もちろんもとの配列に影響は与えない
// 1 2 4
var_dump($array);
// 2 4 6
var_dump($new_array);
調べ物ついでにuse
の記事があったのでメモ。
http://var.blog.jp/archives/75503716.html
const FOOD_REPORTS = array(
'onigiri' => array(
'dir' => '',
'file_pattern' => '*onigiri.txt'
),
'umeboshi' => array(
'dir' => '',
'file_pattern' => '*ume.txt'
),
);
$data = array_map(function($report) {
print_r($report);
}, FOOD_REPORTS);
// jsの感覚でmapすると、全然違うので注意
// keyが取得できない。普通にforEachつかったほうがよさそう
//Array
//(
// [dir] =>
// [file_pattern] => *onigiri.txt
//)
//Array
//(
// [dir] =>
// [file_pattern] => *ume.txt
//)
PHPじゃないけど、セットなことが多いのでここに書く。
Apache2.4から Require
とかにかわってるから注意!詳細はまた書こう。すまんな未来の自分。
OPTIONS
とかを禁止したい場合、Limitディレクティブとかがある。
今回は、上記を使わずにRewrite設定で対応した。
<IfModule mod_rewrite.c>
RewriteEngine on
# リクエストメソッドが、OPTIONSから開始される文字列の場合
RewriteCond %{REQUEST_METHOD} ^OPTIONS
# リライトするよ!全部を[F]にもってく。
# Fは403
# https://qiita.com/tsukaguitar/items/e37245260f0b1407341d
# 一致パターン 置換パターン フラグの順に書く
# 403に飛ばしたいだけで、置換は不要なので-にするみたい
RewriteRule .* - [F]
Fuelのフレームワークで、.htaccsess
にindex.phpにリライトする設定が書いてあるから、ここに足すことにした。
http.confとかに書いてみたけど、おそらくこにhtaccessの設定で上書きされちゃう。
Fuelのhtaccsessを抜粋するとこんなかんじ
# リクエストされたファイルが、なかったら
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# index.phpに渡すよ!
RewriteRule ^(.*)$ index.php/$1 [L]
document rootは/publicだよね。だからpublic配下にあるファイルであれば、対象にならない。
-
documentRootにないディレクトリ /cgi-binにアクセスすると403 ScriptAliasがhttpd.confに書いてある。これを消せばいい。
-
documentRootにないディレクトリ/icons にアクセスすると403が返ってくる。なにこれ。 Apacheがデフォルトで用意してるディレクトリ。↓で対策可能。 https://www.ritolab.com/entry/42
-
public配下のディレクトリにアクセスすると403 ちょっとわからん。ファイル一覧を表示させないようにしてるからかな。 https://www.atmarkit.co.jp/flinux/rensai/linuxtips/705noindexes.html
一律404にしたほうがよさげ。
インスタンスに値を設定してからsaveする。
Eloquent->create()の引数に値を設定して保存するパターン。
リレーションに対してcreateができる
# Model/Thread
# Thread has many Reply
$this->replies()->create($reply)
この場合、作成されるリプライにthread_idが自動で乗っかる。
これがとてもわかりやすい。
https://reffect.co.jp/laravel/perfect-understanding-polymorphic
お気に入りレコードがあって、何に対するお気に入りなのかを表現したい場合、以下のようにできる。
export {
favoritedRecords:[
{
id: 1,
// このidはThread->idのこと
favorited_id: 1,
favorited_type: 'App\Thread'
},
{
id: 2,
// このidはReply->idのこと
favorited_id: 1,
favorited_type: 'App\Reply'
}
]
}
hasManyとかだとリレーションを持てるのは1つのテーブルだけだから、ThreadFavorireRecordsとReplyFavoriteRecordsを持つことになっちゃう。
最高。感謝。
https://qiita.com/ucan-lab/items/753cb9d3e4ceeb245341#comments
Thread
Replies
こんときに、$thread->replies
は問題ない。
Threads
Replies
こんときに、N+1問題がでる。
リレーションにはインスタンスのプロパティとしてアクセスする。
$thread->replies
仕組みは、PHPのマジックメソッド__get()が使われている。
こういう構成になっていて、Thread->propsでアクセスすると、Modelで定義している__getが呼ばれる。
Model
trait HasAttribute
Thread extends Model
__getが呼んでるのはこのメソッド。
public function getAttribute($key)
{
if (!$key) {
return;
}
# attributesは、SQL発行後にセットされるColumって思っていいはず
# それがあれば当然それを返す
if (array_key_exists($key, $this->attributes) ||
$this->hasGetMutator($key)) {
return $this->getAttributeValue($key);
}
# このself::classは、Threadではなくって、その親のModelを指す
# traitでのselfはそういうもんなのかな
# なので、Modelにそのpropsが定義されてればそっちを返す
if (method_exists(self::class, $key)) {
return;
}
# それ以外は、relationを返す
return $this->getRelationValue($key);
}
getRelationValueはこんなかんじ
protected function getRelationshipFromMethod($method)
{
# 結局$thread->repliesは、$thread->replies()になる
$relation = $this->$method();
if (!$relation instanceof Relation) {
if (is_null($relation)) {
throw new LogicException(sprintf(
'%s::%s must return a relationship instance, but "null" was returned. Was the "return" keyword used?', static::class, $method
));
}
throw new LogicException(sprintf(
'%s::%s must return a relationship instance.', static::class, $method
));
}
# が、その後$relation(HasManyインスタンス)を使って、queryを発行してるっぽい
return tap($relation->getResults(), function ($results) use ($method) {
$this->setRelation($method, $results);
});
}
プロパティで取得できるメリットってなんだろう。 モデルがデーブルと1:1で紐付いているものとした場合にプロパティで取れるとうれしいってのと同じ感じでリレーションもできるといいってことかな。
relationのメソッドに対して
-
メソッドとして実行すると、HasManyインスタンスを返してくれる。HasManyインスタンスは、クエリビルダぽく使えるので、その後にメソッドチェーンすると、クエリが発行される。
-
プロパティとしてアクセスすると、そのリレーションに関係するデータを持っているかどうかを見てくれて、すでにデータがあるのであれば、クエリを発行せずに値を返してくれる。値がないのであれば、クエリを発行してデーターをコレクションとして返してくれる。
https://qiita.com/Yorinton/items/604c5b1f3445cb23d565
- FacadeSomethingそのものに、処理はなにもかかれていない。
- FacadeSomethingが提供してるのは、メソッドが呼ばれたときに、そもメソッドをもクラスをインスタンス化してるだけ
- 関数でいいんじゃねって思うのは浅はかなのだろうか。
use XXXX\Facades\SOMETHING;
public function boot()
{
SOMETHING::method()
}
Facade.phpをおっかけると、ここでインスタンス化してる
protected static function resolveFacadeInstance($name)
{
if (is_object($name)) {
return $name;
}
# すでにresolveされているのであれば、そっちを使う
if (isset(static::$resolvedInstance[$name])) {
return static::$resolvedInstance[$name];
}
# そうでなければ、appからとってくる
# appは、bootstrapから渡される。Kernel.phpあたりが怪しい
# また、appの実態であるApplicationクラスは、インスタンス[arg]の形式で、argの名前のインスタンスをmakeするってことをやってる。恐ろしい。
# https://www.php.net/manual/ja/class.arrayaccess.php
# https://qiita.com/metheglin/items/87e25bbdf37fbe0cd6e2
if (static::$app) {
return static::$resolvedInstance[$name] = static::$app[$name];
}
}
すごい。詳細に書いてくれてる。 https://teratail.com/questions/171582k
- back()を使うでも書いたとおり、auth()の実態は、以下の流れで解決される
- auth()ヘルパ関数
- app()ヘルパ関数
- Container::make()
- resolve()がDIを実現してる? ↓の記事がとてもよさげなのであとでみよう。 https://blog.fagai.net/2016/09/17/laravel-dependency-injection/#toc5
解決される実態は、AuthManager.php
その次がめっちゃ厄介で、AuthManagerのインスタンスに対して存在しないメソッドを呼ぶと、magicメソッドが呼ばれるとのこと。
public function __call($method, $parameters)
{
return $this->guard()->{$method}(...$parameters);
}
ほんでデフォルトのdriverのnameが返されて、resolve()へ
public function guard($name = null)
{
# defaultDriverは、auth.phpのconfigを元に返す
# defaultはsession
$name = $name ?: $this->getDefaultDriver();
return $this->guards[$name] ?? $this->guards[$name] = $this->resolve($name);
}
resolveでcreateSessionDriverを呼ぶ!
protected function resolve($name)
{
$config = $this->getConfig($name);
if (is_null($config)) {
throw new InvalidArgumentException("Auth guard [{$name}] is not defined.");
}
if (isset($this->customCreators[$config['driver']])) {
return $this->callCustomCreator($name, $config);
}
$driverMethod = 'create'.ucfirst($config['driver']).'Driver';
# ここ!
if (method_exists($this, $driverMethod)) {
return $this->{$driverMethod}($name, $config);
}
実態はこれ。
src/pokemon-draftingtool/vendor/laravel/framework/src/Illuminate/Auth/SessionGuard.php
https://qiita.com/mpyw/items/8c5413b99b8e299f7002
特定のアクションを実行できる許可が、あるユーザーにあるかを決めるクロージャのこと → abilityと呼ぶといいかも
AuthServiceProvider
で、abilityを定義する。
Gate::define('ability-name', function($user){
// trueであれば、abilityがある。
// booleanを返却しなきゃいけないってことではない。
return $user->isxxx
})
ルーティングをまるっと制御したいのであれば、このGateをmiddlewareで使うことができる。
コントローラとかで?個別にGateのabilityを満たしているかチェックしたいのであれば、
allows
・denies
とかを使える。
if(Gate::allows('ability-name')){}
↑はあんまり使わなそう。ゲートはmiddlewareでやって、コントローラの中はPolicyを使えばいいかも?
middlewareはデフォルトで、Kernel.phpに定義されてる。
protected $routeMiddleware = [
'can' => \Illuminate\Auth\Middleware\Authorize::class,
];
middlewareを使う場合の書き方は、 https://readouble.com/laravel/6.x/ja/middleware.html
複数ルートにmiddlewareを適用させる。
// これcanグループを適用させるようにも見えるな、、、
//https://readouble.com/laravel/6.x/ja/routing.html
// Route:middlewareのほうがただしい?
// groupの最初の引数に共通の属性を渡せるとは書いてある。
Route::group(['middleware' => ['can']], function () {
//
});
次が、大事。middlewareのhandleにパラメータを渡したい場合は、こう書く。 p
Route::put('post/{id}', function ($id) {
// middleware名:パラメータ
})->middleware('role:editor');
なので、以下は、canミドルウェアに引数create-groupsを渡すってことね!
Route::group(['middleware' => 'can:create-groups'], function () {
Route::get('/create', 'PostsController@create');
Route::post('/', 'PostsController@store');
});
で、Authorizer.phpのmiddlewareはこんなかんじ。
public function handle($request, Closure $next, $ability, ...$models)
{
// こいつがメイン
$this->gate->authorize($ability, $this->getGateArguments($request, $models));
return $next($request);
}
Gateの正体は、Illuminate\Auth\Access\Gate
で、Illuminate\Auth\AuthServiceProvider
でbindしてる。
protected function registerAccessGate()
{
$this->app->singleton(GateContract::class, function ($app) {
return new Gate($app, function () use ($app) {
return call_user_func($app['auth']->userResolver());
});
});
}
こいつまでの流れは以下の記事がわかりやすい。Facadeの仕組みで前もみたかも。 https://qiita.com/Yorinton/items/604c5b1f3445cb23d565
あとは、Gateをみると、authorizeはこんなかんじ。
public function authorize($ability, $arguments = [])
{
return $this->inspect($ability, $arguments)->authorize();
}
public function inspect($ability, $arguments = [])
{
try {
// このさきは気が向いたら
// おそらくClosureが実行結果がresult
$result = $this->raw($ability, $arguments);
// resultにはboolean以外も返せる
if ($result instanceof Response) {
return $result;
}
// denyをみれば、例外をスローすることがわかる
return $result ? Response::allow() : Response::deny();
} catch (AuthorizationException $e) {
return $e->toResponse();
}
}
web.phpのMiddlewareに適用されている、EncryptCookies
でCookieを復号してる。ブラウザでCookieのlaravel_sessionは暗号化されるので注意。
復号化すると、sessionのkey名が入ってたりする。
public function handle($request, Closure $next)
{
return $this->encrypt($next($this->decrypt($request)));
}
セッションを開始するMiddleware。
Cookieのlaravel_sessionからセッションのkeyとなるものを取得する。StoreクラスにsetIdしてる。
public function getSession(Request $request)
{
return tap($this->manager->driver(), function ($session) use ($request) {
$session->setId($request->cookies->get($session->getName()));
});
}
その後、
protected function startSession(Request $request)
{
return tap($this->getSession($request), function ($session) use ($request) {
$session->setRequestOnHandler($request);
// こいつで、setIdしたidをもとに、セッションを新規に作成or復元してるとおも。
$session->start();
});
}
CSRF対策。セッションとCookieにXSRF-TOKENを書かれてる。
この値を、VerifyCsrfToken
で比較する。
Ajaxの場合、X-XSRF-TOKENヘッダーにセットする、 このへん。
protected function getTokenFromRequest($request)
{
$token = $request->input('_token') ?: $request->header('X-CSRF-TOKEN');
if (!$token && $header = $request->header('X-XSRF-TOKEN')) {
$token = CookieValuePrefix::remove($this->encrypter->decrypt($header, static::serialized()));
}
return $token;
}
READ系のメソッドの場合、tokenの比較はしない。
public function be(UserContract $user, $driver = null)
{
if (isset($user->wasRecentlyCreated) && $user->wasRecentlyCreated) {
$user->wasRecentlyCreated = false;
}
# SessionGuardのsetUser、SessionGuardに認証済Userとしてつっこめる
$this->app['auth']->guard($driver)->setUser($user);
# AuthManager->shouldUse これはなんで必要なんだろ
$this->app['auth']->shouldUse($driver);
return $this;
}
https://qiita.com/cyrt/items/2d90677dc920cd2e5459 DIについて https://qiita.com/kd9951/items/951ab700f28d1d49c9c9
FormRequestServiceProvider
// bootはサービスコンテナにregisterした後に、インスタンス化したオブジェクトに対して行う操作
public function boot()
{
// ValidatesWhenResolved IFを実装しているインスタンスに対して
// validateResolved()を実行する
// この$resolvedは、FormRequestを継承した、CreateRequestとか
$this->app->afterResolving(ValidatesWhenResolved::class, function ($resolved) {
$resolved->validateResolved();
});
$this->app->resolving(FormRequest::class, function ($request, $app) {
$request = FormRequest::createFrom($app['request'], $request);
$request->setContainer($app)->setRedirector($app->make(Redirector::class));
});
}
で、validateResolved
はこいつ。
trait ValidatesWhenResolvedTrait
{
/**
* Validate the class instance.
*
* @return void
*/
public function validateResolved()
{
$this->prepareForValidation();
if (!$this->passesAuthorization()) {
$this->failedAuthorization();
}
// これは、Illuminate\Validation\Validator
$instance = $this->getValidatorInstance();
if ($instance->fails()) {
$this->failedValidation($instance);
}
$this->passedValidation();
}
- back()の実態はヘルパー関数
※ ヘルパー関数は、composer.lockをみるとfiles
の定義で書いてあるので、autoload後であればどっからでも参照できる。
function back($status = 302, $headers = [], $fallback = false)
{
return app('redirect')->back($status, $headers, $fallback);
}
}
- app()関数もヘルパー関数
function app($abstract = null, array $parameters = [])
{
if (is_null($abstract)) {
return Container::getInstance();
}
# make()を追うと、resolve()につながる。resolveはごにょごにょしてargの関係するインスタンスを返してる
#src/pokemon-draftingtool/vendor/laravel/framework/src/Illuminate/Foundation/Application.php
# ↑に、クラスのaliasがきってある。
# redirectの実態は、\Illuminate\Routing\Redirector
return Container::getInstance()->make($abstract, $parameters);
}
つまり、back()はRedirector()->back() 中を見ると、リファラーをみてた。納得。