😸

Laravelの開発に関するTips

2022/03/30に公開

composer install update require の違い

composer とは

パッケージ間の依存関係を処理しながらパッケージをインストールしてくれる。

composer install

composer.jsonの内容に基づいて、依存関係を解決しながらパッケージをインストールする。
加えて、composer.lockが存在している場合は、その内容に基づいてインストールを行う。
ちなみに、composer.lockにはcomposer installでインストールされたパッケージのバージョンに関する情報が書かれている。

composer update

composer.jsonの内容に基づいて、依存関係を再度解決しながらパッケージの最新版をインストールする。
さらに、composer.lockの内容を更新する。

composer require

開発環境で、新しいライブラリなどを追加するときに、実行する。

vendor

composer install もしくは、composer updateによって、インストールされたパッケージが入っている。
基本的には、gitの管理対象からは除外する。

PHPでデバッグのやり方

デバッグのやり方を簡単に記述する。

処理がどこまで通っているかを確かめるときに使う

error_log("hello"."\n", 3, "./debug.log");

変数の中身をlogファイルに出力する方法

error_log(print_r($conferences,true),3, "/var/www/html/dev02/debug.log");

公式ドキュメント
https://www.php.net/manual/ja/function.error-log.php

logを閲覧する

tail -f debug.log

変数の中身を見る

echo "<pre>";
var_dump($sample);
echo "<pre>";

echo "<pre>";は出力の時に、改行をして見やすくするために入れる。

応用

error_log(var_export($sample), 3, "./debug.log");

これで指定のファイルに、変数の中身を出力して確認ができる。

middlewareを使って認証機能を作成する

session とは

参考サイト
https://qiita.com/hot_study_man/items/c7e081d51ec29272c326

sessionの扱い方

// 登録
request()->session()->put('customer_name', $data['customer_name'])

// 取得
request()->session()->get('customer_no')

// 全削除
request()->session()->flush()

middleware とは

laravelでmiddlewareを使うと、認証が通っている場合のみ、 web.phpapi.php に定義したルーティングにアクセスできるようになる。

laravelでmiddlewareを使う

app/Http/Kernel.php

<?php

namespace App\Http;

use Illuminate\Foundation\Http\Kernel as HttpKernel

class Kernel extends HttpKernel
{
    /**
     * The application's global HTTP middleware stack.
     *
     * These middleware are run during every request to your application.
     *
     * @var array
     */
    protected $middleware = [
        \Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
        \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
        \App\Http\Middleware\TrimStrings::class,
        \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
        \App\Http\Middleware\TrustProxies::class,
        \App\Http\Middleware\EncryptCookies::class,
        \Illuminate\Session\Middleware\StartSession::class,
        \App\Http\Middleware\VerifyCsrfToken::class,
    ];

    /**
     * The application's route middleware groups.
     *
     * @var array
     */
    protected $middlewareGroups = [
        'web' => [
            \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
            \Illuminate\Session\Middleware\StartSession::class,
            // \Illuminate\Session\Middleware\AuthenticateSession::class,
            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
            \App\Http\Middleware\VerifyCsrfToken::class,
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],

        'api' => [
            //'throttle:60,1',
            'bindings',
        ],
    ];

    /**
     * The application's route middleware.
     *
     * These middleware may be assigned to groups or used individually.
     *
     * @var array
     */
    protected $routeMiddleware = [
        'authentication' => \App\Http\Middleware\Authenticate::class,
        'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
        'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
        'can' => \Illuminate\Auth\Middleware\Authorize::class,
        'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
        'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
    ];
}

以下のようにして、kanel.phpに書いたmiddlewareの定義を指定したルーティングに対して適用することができる。

web.php(かapi.php)
Route::group(['middleware' => ['authentication']], function () {
)};

Linter と Formatter の導入

開発をする際に、未使用変数が残ってしまったり、
エンジニア間でコードのフォーマットが、バラバラになってしまったりするなどの問題があったため、
社内の一部のプロジェクトで、静的解析ツールとフォーマッターを導入することにしました。
補足ですが、laravelプロジェクトに静的解析ツールとフォーマッターを導入しました。

静的解析の主なルール

  • 未使用変数のチェック
  • 未使用変数が残っていないかをチェック
  • 未使用関数が残っていないかをチェック
  • コードの複雑度を示す
  • メソッド名がcamelCase表記になっているかをチェック
  • var_dump()、print_r()などを検出する
  • クラス/インターフェース定数名が大文字で定義されているかをチェック

静的解析ツール導入

まずは、phpの静的解析ツールである、 phpmd から導入する。

$ composer require "phpmd/phpmd" "@stable"

以下の ruleset.xml をlaravelのルートディレクトリに配置することで、
静的解析を実行した際にチェックする項目を詳細に設定することができる。

ruleset.xml
<?xml version="1.0"?>
<ruleset name="My first PHPMD rule set"
         xmlns="http://pmd.sf.net/ruleset/1.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0
                     http://pmd.sf.net/ruleset_xml_schema.xsd"
         xsi:noNamespaceSchemaLocation="
                     http://pmd.sf.net/ruleset_xml_schema.xsd">
    <description>
        My custom rule set that checks my code...
    </description>
    <!-- ここから利用したいルールを書く -->
    <!-- 未使用変数、未使用関数などを検出する -->
    <rule ref="rulesets/unusedcode.xml" />
    <!-- コードの複雑度を示す -->
    <rule ref="rulesets/codesize.xml/CyclomaticComplexity" />
    <!-- メソッド名がcamelCase表記になっているかをチェック -->
    <!--<rule ref="rulesets/controversial.xml/CamelCaseMethodName" />-->
    <!-- var_dump()、print_r()などを検出する -->
    <rule ref="rulesets/design.xml/DevelopmentCodeFragment" />
    <!-- クラス/インターフェース定数名が大文字で定義されているかをチェック -->
    <rule ref="rulesets/naming.xml/ConstantNamingConventions" />
</ruleset>

静的解析を実行する

以下のコマンドで設定したルールを基に静的解析を実行できる。

$ ./vendor/bin/phpmd [対象ファイル] text ruleset.xml

フォーマッターの主なルール

以下のようにすれば、個別のルールがどのようなフォーマットに整形してくれるのかをターミナルで確認できる。

./vendor/bin/php-cs-fixer describe [ルール名]

フォーマッター導入

次に、phpのフォーマッターである、 php-cs-fixer を導入する。

$ composer require "friendsofphp/php-cs-fixer" "^2.16"

以下の、 php_cs.dist をlaravelのルートディレクトリに配置すると、
フォーマットを実行した際の、整形ルールを細かく設定することができる。

.php_cs.dist
<?php

return PhpCsFixer\Config::create()
    ->setRiskyAllowed(true)
    ->setRules([
        '@PSR2' => true,
        'align_multiline_comment' => true,
        'array_syntax' => true,
        'binary_operator_spaces' => true,
        'blank_line_after_opening_tag' => true,
        'blank_line_before_statement' => ['statements' => ['declare', 'do', 'for', 'foreach', 'if', 'switch', 'try']],
        // 'cast_spaces' => true,
        'class_attributes_separation' => true,
        // 'combine_consecutive_issets' => true,
        // 'combine_consecutive_unsets' => true,
        'compact_nullable_typehint' => true,
        'concat_space' => true,
        'declare_equal_normalize' => true,
        // 'declare_strict_types' => true,
        // 'dir_constant' => true,
        // 'ereg_to_preg' => true,
        // 要検討
        // 'escape_implicit_backslashes' => true,
        // 要検討
        // 'explicit_indirect_variable' => true,
        // 要検討
        // 'explicit_string_variable' => true,
        'final_internal_class' => true,
        // 要検討
        // 'function_to_constant' => true,
        'function_typehint_space' => true,
        // 'general_phpdoc_annotation_remove' => ['annotations' => ['class', 'package', 'author']],
        // 要検討
        // 'hash_to_slash_comment' => true,
        // 'heredoc_to_nowdoc' => true,
        'include' => true,
        // 要検討
        // 'is_null' => ['use_yoda_style' => false],
        'linebreak_after_opening_tag' => true,
        // 'list_syntax' => true,
        // 'lowercase_cast' => true,
        // 'magic_constant_casing' => true,
        'method_chaining_indentation' => true,
        'method_separation' => true,
        // 'modernize_types_casting' => true,
        // 'native_function_casing' => true,
        // 'no_alias_functions' => true,
        'no_blank_lines_after_class_opening' => true,
        'no_blank_lines_after_phpdoc' => true,
        'no_empty_comment' => true,
        'no_empty_phpdoc' => true,
        'no_empty_statement' => true,
        'no_extra_consecutive_blank_lines' => ['tokens' => ['break', 'continue', 'extra', 'return', 'throw', 'use', 'switch', 'case', 'default', 'parenthesis_brace_block', 'square_brace_block', 'curly_brace_block', 'use_trait']],
        // 'no_homoglyph_names' => true,
        // 要検討
        // 'no_leading_import_slash' => true,
        'no_leading_namespace_whitespace' => true,
        // 'no_mixed_echo_print' => true,
        // 'no_multiline_whitespace_around_double_arrow' => true,
        'no_multiline_whitespace_before_semicolons' => true,
        // 'no_null_property_initialization' => true,
        // 'no_php4_constructor' => true,
        // 'no_short_bool_cast' => true,
        'no_singleline_whitespace_before_semicolons' => true,
        'no_spaces_around_offset' => true,
        'no_trailing_comma_in_list_call' => true,
        'no_trailing_comma_in_singleline_array' => true,
        // 'no_unneeded_control_parentheses' => true,
        // 'no_unneeded_curly_braces' => true,
        // 'no_unneeded_final_method' => true,
        // 'no_unreachable_default_argument_value' => true,
        'no_unused_imports' => true,
        'no_useless_else' => true,
        'no_useless_return' => true,
        'no_whitespace_before_comma_in_array' => true,
        'no_whitespace_in_blank_line' => true,
        'normalize_index_brace' => true,
        'object_operator_without_whitespace' => true,
        // 'ordered_class_elements' => true,
        'ordered_imports' => true,
        'php_unit_construct' => true,
        'php_unit_dedicate_assert' => true,
        'php_unit_mock' => true,
        'php_unit_namespaced' => true,
        'phpdoc_add_missing_param_annotation' =>  true,
        'phpdoc_align'  => true,
        'phpdoc_annotation_without_dot' => true,
        'phpdoc_indent' => true,
        'phpdoc_inline_tag' => true,
        'phpdoc_no_access' => true,
        'phpdoc_no_empty_return' => true,
        'phpdoc_no_package' => true,
        'phpdoc_order' => true,
        'phpdoc_return_self_reference' => true,
        'phpdoc_scalar' => true,
        'phpdoc_single_line_var_spacing' => true,
        'phpdoc_summary' => true,
        'phpdoc_to_comment' => true,
        'phpdoc_trim' => true,
        'phpdoc_types' => true,
        'phpdoc_types_order' => true,
        'phpdoc_var_without_name' => true,
        // 'pow_to_exponentiation' => true,
        // 'protected_to_private' => true,
        // 'random_api_migration' => true,
        'return_type_declaration' => true,
        'self_accessor' => true,
        'semicolon_after_instruction' => true,
        'short_scalar_cast' => true,
        'simplified_null_return' => true,
        'single_blank_line_before_namespace' => true,
        'single_line_comment_style' => true,
        'single_quote' => true,
        'space_after_semicolon' => true,
        'standardize_not_equals' => true,
        'ternary_operator_spaces' => true,
        // 'ternary_to_null_coalescing' => true,
        'trailing_comma_in_multiline_array' => true,
        'trim_array_spaces' => true,
        'unary_operator_spaces' => true,
        // 'void_return' => true,
        'whitespace_after_comma_in_array' => true,
        // 'yoda_style' => ['equal' => false, 'identical' => false],
    ])
    ->setFinder(PhpCsFixer\Finder::create()
        ->exclude('vendor')
        ->in(__DIR__)
    )
    ;

php-cs-fixerを実行した際に、 .php_cs.cache というファイルが出力されるのですが、
こちらはgitの管理対象に含める必要はないので、 .gitignore を以下のように修正。

.gitignore
.
.
.php_cs.cache

フォーマッター実行

以下のコマンドを実行すると、設定したルールを基にフォーマットされる。

$ ./vendor/bin/php-cs-fixer fix [対象ファイル]

git の pre-commit を設定する

ファイルを編集した後に、毎回手動で静的解析と、フォーマッターを実行するのは、非常に面倒なので、
git のpre-commitを設定して、commitの直前に自動で実行されるようにする。
これによって、git commit時に変更のあったファイルに対して、ソースコードの自動整形を行い、
静的解析を行った際に、ソースコードに何か問題があった場合、commitを中止させることができる。

pre-commit
#!/bin/bash

if git rev-parse --verify HEAD >/dev/null 2>&1
then
    against=HEAD
else
    # Initial commit: diff against an empty tree object
    against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi
# Redirect output to stderr.
exec 1>&2
SYNTAX_CHECK=0
## 静的解析、及びフォーマッターの実行
# コミットされるファイルのうち、.phpで終わるもの
for FILE in `git diff-index --name-status $against -- | grep -E '^[AUM].*\.php$'| cut -c3-`; do
    # シンタックスのチェック
    if php -l $FILE; then
        # PSR準拠でコード書き換え
        ./vendor/bin/php-cs-fixer fix $FILE
        git add $FILE
        # PHPMDで未使用変数などのチェック
        if ! ./vendor/bin/phpmd $FILE text ruleset.xml; then
            SYNTAX_CHECK=1
        fi
    else
        SYNTAX_CHECK=1
    fi
done


## 最後の確認
if [ $SYNTAX_CHECK -eq 0 -a $IS_ERROR -eq 0 ]; then
    exit 0
else
    echo -e "\e[31;43m 修正を行った上で再度コミットしてください \e[m"
    exit 1
fi

Discussion