--> -->

skimemo


Laravel のバックアップ(No.4)


_ 今日のLaravel

これは、2018アドベントカレンダー記事で、Laravel(5.4)を使った開発の中で気づいた事を毎日一つメモしていくものです。


_ 2018/12/5 resourceのroute名の変更方法

開発を進めていくと、routeの記述がどうしても長大になりがちな中で、resource定義は一行で複数の挙動が定義できて、しかもroute名も自動で定義してくれてとても助かります。
しかし、例えば以下のように別々のディレクトリ内で同じ定義名を使いたい場合があります。

  1
  2
Route::resource('user/regist', 'UserHogeController');
 Route::resource('product/regist', 'ProductHogeController'); 

この場合、route名はどちらも「regist.index」等となってしまい、別々に識別することができなくなってしまいます。

この問題の解決方法として、マニュアルでは以下のように再定義できると書かれています。

  1
  2
  3
Route::resource('photo', 'PhotoController', ['names' => [
    'create' => 'photo.build'
]]); 

しかし、アクションがindex,create,store,show,edit,update,destroyと7つもあるのに、いちいち書いていたらroute定義が無駄に長くなってしまいます。 そこで、resource()のソースを確認すると、Illuminate\Routing\ResourceRegistrar::getResourceRouteName()で以下のように作成していました。

  1
  2
  3
  4
  5
  6
  7
  8
if (isset($options['names'])) {
    if (is_string($options['names'])) {
        $name = $options['names'];
    } elseif (isset($options['names'][$method])) {
        return $options['names'][$method];
    }
}
(後略) 

stringも許可しています。なので、以下の通り指定すると7つのアクション全てを書き換えてくれます。

  1
  2
Route::resource('user/regist', 'UserHogeController',['names'=>'user-regist']);
 Route::resource('product/regist', 'ProductHogeController',['names'=>'product-regist']); 

便利(^^)


_ 2018/12/6 apiでセッションを使おうとするとformと両立できない

LaravelではAPIアクセスはapi.phpで定義できますが、ステートレスなアクセスを前提としているため、セッションを使うことができません。*1
参考ページの通りに対応すればセッションが有効になりますが、以下の手順で操作した場合にCSRFエラーになります。

  1. フォームの中でボタンを押すとajaxを使用してAPIアクセス
  2. フォームからpostでsubmit
csrf.png


想像ですが、APIアクセス時にセッション保持しているCSRFトークンが書き換わってしまい、フォームに埋め込まれたトークンと一致しなくなってしまうと考えられます。

私の場合はやむなく無認証にしましたが、どうしても認証したい場合は、アクセストークン方式にする必要があるのではないかと思います。


_ 2018/12/7 php5とphp7での配列を使ったメソッド呼び出しの挙動の違い

以下のコードにおいて、php5とphp7で挙動の違いがありました。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
<?php
 
class test {
 
    public function __construct() {
        echo "test!\n";
        $method[0] = "test2";
        $this->$method[0]();
    }
 
    private function test2() {
        echo "test2\n";
    }
 
}
 
new test();
  • php5(5.6.30)の場合
    >php test.php
    test!
    test2
  • php7(7.1.24)の場合
    >php test.php
    test!
    PHP Notice:  Array to string conversion in F:\test.php on line 8
    PHP Stack trace:
    PHP   1. {main}() F:\test.php:0
    PHP   2. test->__construct() F:\test.php:17
            :
    PHP Fatal error:  Uncaught Error: Function name must be a string in F:\test.php:8
    どうやら変数が配列の場合、php7だと「$this->$method」で一旦区切って解釈するようです。

    解決方法は以下の通り。
    -	$this->$method[0]();
    +	$this->{$method[0]}();
    これでphp5でも7でも動作するコードになりました。

_ 2018/12/8 WYSWYGエディタには要注意

WYSWYGはWhat You See What You Getの略で、直訳すると見たままの物が得られる、という意味です。
そんなの当たり前じゃん、と言っているそこの若者! これが誕生した頃は画期的だったのですよ(Appleが広めた)。

まあそんなことはいいとして、フリーで使えるWYSWYGエディタは各種あります。*2
私が試したのはTrumbowyg。簡単にこんなTEXTAREAが得られます。

trumbowyg1.png


使い方はこんな感じ。

  1
  2
  3
  4
  5
  6
  7
  8
  9
{{Form::textarea('description')}}
 {{Html::style(asset('trumbowyg/dist/ui/trumbowyg.min.css'))}}
 {{Html::script(asset('trumbowyg/dist/trumbowyg.min.js'))}}
 {{Html::script(asset('trumbowyg/dist/langs/ja.min.js'))}}
 <script language="JavaScript">
    $('textarea').trumbowyg({
        lang: 'ja',
    });
 </script> 

(スクショはプラグインを幾つか入れてます)

このエディタ、画面上に得るべき物を表示しているということは、HTMLタグをレンダリングしているということになります。このTrumbowygは生HTMLも書けるので、試しにJavascriptタグを埋めてみます。

trumbowyg2.png


そして生HTMLモードを解除してみると・・・

trumbowyg3.png


うーん、ダメだこりゃ。これではユーザーが自由にこのサーバー上でJavascriptを動かせちゃうということです。
生HTMLは書けないモードにして使う必要がありそうです。
Trumbowygはボタンのカスタマイズができますので、例えばこんな感じです。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
<script language="JavaScript">
    $('textarea').trumbowyg({
        lang: 'ja',
        btns: [
            ['undo', 'redo'], // Only supported in Blink browsers
            ['formatting'],
            ['strong', 'em', 'del'],
            ['superscript', 'subscript'],
            ['link'],
            ['insertImage'],
            ['justifyLeft', 'justifyCenter', 'justifyRight', 'justifyFull'],
            ['unorderedList', 'orderedList'],
            ['horizontalRule'],
            ['removeformat'],
            ['fullscreen'],
        ]
    });
</script>