20210308のlaravelに関する記事は15件です。

XAMPPとLaravelの導入 (Windows)

はじめに

環境

  • Windows 10 Pro 20H2
  • XAMPP 8.0.2
  • Apache 2.4.46
  • PHP 8.0.2
  • Composer 2.0.11
  • Laravel Installer 1.5.0
  • Laravel Framework 8.31.0

XAMPP

  • ダウンロードします。
  • 素直にインストールします。
    • UACに対して警告されますが、そのまま進みます。
    • インストールするものを選択します。
      • 私の場合、FileZilla、Mercury、Tomcat、Perlのチェックを外しました。
      • MySQLと書かれていますが、実際はMariaDBです。
  • コンパネを起動している場合は、いったん終了します。
    • 【重要】 ウインドウを閉じてコンパネを終了してはいけません。
      • 「Quit」を使用せずにウインドウを閉じると、バックグラウンドプロセスが残ってしまいます。
      • コンパネを閉じる場合は、サーバが稼働中かどうかにかかわらず、必ず、「Quit」を使用しましょう。
  • パスが通っているか確認します。
    • スタートメニュー ⇒ 「環境変数を編集」からC:\xampp\phpへパスを通します。
C:>php --version
PHP 8.0.2 (cli) (built: Feb  3 2021 18:36:40) ( ZTS Visual C++ 2019 x64 )
Copyright (c) The PHP Group
Zend Engine v4.0.2, Copyright (c) Zend Technologies
  • 管理者ターミナルから、フォルダにアクセス権を設定します。
    • ユーザー名や元のアクセス権は、環境によって異なります。
    • GUIから操作する場合は、該当ユーザーの継承を止めてから権限を変更します。
コマンドプロンプト (管理者)
C:\WINDOWS\system32>cacls C:\xampp
C:\xampp BUILTIN\Administrators:(OI)(CI)(ID)F
         NT AUTHORITY\SYSTEM:(OI)(CI)(ID)F
         BUILTIN\Users:(OI)(CI)(ID)R
         NT AUTHORITY\Authenticated Users:(ID)C
         NT AUTHORITY\Authenticated Users:(OI)(CI)(IO)(ID)C
C:\WINDOWS\system32>cacls C:\xampp /e /t /p BUILTIN\Users:F
C:\WINDOWS\system32>cacls C:\xampp
C:\xampp BUILTIN\Users:(OI)(CI)F
         BUILTIN\Administrators:(OI)(CI)(ID)F
         NT AUTHORITY\SYSTEM:(OI)(CI)(ID)F
         NT AUTHORITY\Authenticated Users:(ID)C
         NT AUTHORITY\Authenticated Users:(OI)(CI)(IO)(ID)C
  • コンパネを開いて動作を確認します。
    • Apacheが起動しない場合は、Netstatボタンを押してポート80, 443が使用されていないか確認します。
      • Skypeやunity-acceleratorなどが80を使用しますので設定で変更します。
  • コンパネを使わずに使うこともできます。

更新

XAMPP

まだやってません。

PHP

まだやってません。

MariaDB

まだやってません。

phpMyAdmin

  • ダウンロードして展開します。
  • サーバを停止します。
  • バックアップします。
C:\>ren C:\xampp\phpMyAdmin phpMyAdmin__
  • 展開してあったフォルダを移動します。(デスクトップに展開してあった場合)
C:\>move %USERPROFILE%\Desktop\phpMyAdmin C:\xampp\
  • バックアップから設定をコピーします。
C:\>copy C:\xampp\phpMyAdmin__\config.inc.php C:\xampp\phpMyAdmin\
  • サーバを起動して管理ページにアクセスし、問題ないか確認します。
  • バックアップを削除します。

Comporser

  • ダウンロードします。
  • 素直にインストールします。
    • 一箇所、選択ではなく確認のチェックがありますが、それ以外は次へ送るだけです。
  • パスが通っているか確認します。
    • スタートメニュー ⇒ 「環境変数を編集」から%USERPROFILE%\AppData\Roaming\Composer\vendor\binへパスを通します。
C:\>composer --version
Composer version 2.0.11 2021-02-24 14:57:23

更新

C:\>composer self-update
~ 略 ~

Laravel

D:\development>composer global require laravel/installer
~ 略 ~
D:\development>laravel --version
Laravel Installer 4.1.1
  • 新しいLaravelプロジェクトを作ります。
D:\>md D:\development\laravel
D:\>cd D:\development\laravel
D:\development\laravel>laravel new practice
~ 略 ~
  • LaravelをPHPの開発用組み込みサーバーで起動します。
D:\development\laravel>cd practice
D:\development\laravel\practice>php artisan serve
Starting Laravel development server: http://127.0.0.1:8000
[Sun Mar  7 17:51:10 2021] PHP 8.0.2 Development Server (http://127.0.0.1:8000) started
  • http://127.0.0.1:8000/へアクセスして、フロントページが表示されたら成功です。
  • Ctrl+Cでサーバを停止します。

ショートカット

ショートカットの「リンク先」を以下のようにします。

C:\xampp\php\php.exe artisan serve

「作業フォルダー」を以下のようにします。

D:\development\laravel\practice

これで、前述の起動状態になります。

更新

D:\>cd D:\development\laravel\practice
D:\development\laravel\practice>composer update
~ 略 ~
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Laravel]envファイルごとに処理を変更する

概要

ローカル環境と本番環境、テスト環境でDB処理を変えたかったのでその方法を起筆します。

実装

envファイルごとに分岐することで実装しました。

.envファイルと.env.productionファイルを用意してAPP_ENVを以下のようにする。

.env
APP_ENV=local
env.production
APP_ENV=production

controllerにAPP_ENVによって分岐させる処理を加える。

<?php

namespace App\Http\Controllers;

use App\Http\Requests\PostRequest;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;

class PostController extends Controller
{
    public function store(PostRequest $request)
    {
        if(app()->environment('local')){
        //local環境で行いたい処理を記述
        }else if(app()->environment('production')){
        //production環境で行いたい処理を記述
        }
    }
}

まとめ

なんかもっとスマートな方法がありそうです。
知っていましたら教えてください。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

axiosでREST APIの通信を行う時にSafariではエラーが起きたときの対処法

皆さんこんにちは!

Windowsで開発している僕にとってはSafari特有のエラー程苦しむものは無いです。

ただ、この時代スマートフォンの使用率が圧倒的に高い10代、20代のほとんどはiPhoneを使っていると思います。

僕の周りでもiPhoneの使用率が圧倒的に高いです。

なので、iPhoneのエラーも無視するわけにはいかない。。。

今日はそんなこんなでaxiosでLaravelで作成したバックエンドとの通信でWindows環境で開発しているので、エラー内容は確認できなかったのですが、おそらくCORSエラーが原因でAPI通信を行うことができませんでした。

結論から言いますと、SafariではChromeのように上手くキャッシュの処理を行うことができないそうです。

なので、このキャッシュの問題を解決してあげることでSafariでもAPI通信を行うことができます!

それでは、説明を見ていきましょう!

はじめに

今回は、Vueでの説明となります。

もし、Reactなどを使っている場合は適時変更して下さい。

また、バックエンドではLaravelでCORSドメインの設定などを行います。

もし、Laravel以外でAPIを作成している場合も適時変更してください。

axiosでCookie設定

axiosのデフォルトでは、withCredentialsというCookieを使えるようにするためのプロパティの設定がOFFになっています。

なので、これをONにしてあげましょう!

main.js
// axiosのプロトタイプ宣言
Vue.prototype.$axios = axios
// Cookieの使用を可とする
axios.defaults.withCredentials = true

これでaxiosがデフォルトでCookieを使用することができます。

CORSドメイン設定

次に、axiosでCookieの情報を受け取るためにバックエンドで適切なヘッダーを追加してあげましょう!

> php artisan make::middleware ApiCors
Http/Middleware/ApiCors.php
<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;

class ApiCors
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle(Request $request, Closure $next)
    {
        // すべてのレスポンスに CORS 用のヘッダーを追加する必要はないので URL から判断する
        $paths = explode('/', $request->getPathInfo());
        if ($paths[1] === 'api') {
            return $next($request)
            ->header('Access-Control-Allow-Origin', config('cors.allowed_origins'))
            ->header('Cache-Control', 'no-cache max-age=3600')
            ->header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS')
            ->header('Access-Control-Allow-Credentials', 'true')
            ->header('Access-Control-Allow-Headers', 'X-XSRF-TOKEN, Authorization, content-type, Transfer-Encoding, Accept, Accept-Encoding, Accept-Language');
        }
        return $next($request);
    }
}

$paths = explode('/', $request->getPathInfo());if ($paths[1] === 'api')/api/apis``のようなAPI通信を行う時だけこのミドルウェアを適用するようにしています。

Access-Control-Allow-Origin

Access-Control-Allow-OriginではCORSドメインを許可するドメインを登録しています。

例えば、http://localhost:3000からのリクエストを許可したい場合はここにhttp://localhost:3000と入力してください。

これを*のようにすると全てのドメインからリクエストが可能なので、データ抜き放題となるので注意して下さい。

Access-Control-Allow-Methods

Access-Control-Allow-Methodsでは、使用できるメソッドを書きます。ほとんどの場合は上記のようにしてOKです。

Access-Control-Allow-Credentials

Access-Control-Allow-Credentialstrueにすることで、先ほどaxiosで設定したCookie情報のリクエストを受け取れるようにしています。

Access-Control-Allow-Headers

最後に、Access-Control-Allow-Headersを説明します。

これが重要です!

色々あるのですが2つだけ説明します。

X-XSRF-TOKENはaxiosで発行したトークン情報です。PHPで言うと、formCSRFのようなものです。これを受け取るためにこのヘッダーを追加します。

次に、content-typeです。

これは、GETやHEADの場合は必要ないのですが、以下のようなリクエストを行う場合content-typeapplicatio/jsonとなります。

this.$axios
        .post(process.env.VUE_APP_LARAVEL_SITE_URL + '/api/participants', {
          name: 'akki'
        })

そして、content-typeのデフォルトではapplication/jsonは対応していません。

なので、このようなapplication/jsonの形を受け取るのを許可するためにcontent-typeを追加します。

ちなみに場合によっては、content-typeでエラーが出ます。その時はContent-Typeと設定して見て下さい。

ミドルウェアの適用

最後に作成したこのミドルウェアを適用させましょう!

App/Http/Middleware/Karnel.phpを開いてください。

Karnel.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 = [
        // \App\Http\Middleware\TrustHosts::class,
        // CORSドメインの設定を追加
        \App\Http\Middleware\ApiCors::class,
        \App\Http\Middleware\TrustProxies::class,
        \Fruitcake\Cors\HandleCors::class,
        \App\Http\Middleware\PreventRequestsDuringMaintenance::class,
        \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
        \App\Http\Middleware\TrimStrings::class,
        \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
    ];
    // 省略
}

必ず$middlewareに追加してください!!

なぜかと言うと、$middlewareに追加しないとOPTIONSリクエストに今作成したミドルウェアを適用することができません!

絶対に$middlewareに追加!!!

いかがだったでしょうか?

このエラーで3日程時間を費やされたので、本当に苦労しました。

ぜひ皆さんのお力になれたらなと思います。

以上、「axiosでREST APIの通信を行う時にSafariではエラーが起きたときの対処法」でした!

また、何か間違っていることがあればご指摘頂けると幸いです。

他にも初心者さん向けに記事を投稿しているので、時間があれば他の記事も見て下さい!!

あと、最近「ココナラ」で環境構築のお手伝いをするサービスを始めました。

気になる方はぜひ一度ご相談ください!

Thank you for reading

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravel + Cogntitoでサインイン時にエラー"The security token included in the request is invalid."

事象

Laravel環境にCognitoを使用したサインアップ/サインイン機能を搭載したのですが、新規登録・メール検証済みユーザーでサインインしようとした時に全くもってサインインできませんでした。うんともすんとも動かねえぜ。
スクリーンショット 2021-03-08 15.32.05.png

前提条件として、Cognitoのアプリクライアントの設定で「認証用の管理 API のユーザー名パスワード認証を有効にする(ALLOW_ADMIN_USER_PASSWORD_AUTH)」を使用した場合でのエラーです。

結論を言うと環境変数に設定していたAWS_ACCES_KEY_IDが間違っていただけなのですが、なんとこのミスに気づかず6時間以上を無駄にしてしまったため、備忘録として残します。

以下、Laravel+Cognito構築で参考にさせて頂いた記事
https://blackbits.io/blog/laravel-authentication-with-aws-cognito
https://qiita.com/suzumurakk/items/efe4543cf0df2cd31659

原因

タイトルにもある通りで、裏では以下のエラーが返ってきていました。

The security token included in the request is invalid.(リクエストに含まれているセキュリティトークンが無効です。)

このエラーでググると、AWSに送信しているアクセスキーIDもしくはシークレットアクセスキーが無効とのことでした。
Laravelの.envを確認したところ、アクセスキーID(AWS_ACCES_KEY_ID)に余計な文字が入っておりました。チクショー!!
上記解決後、無事にサインインできることを確認しました。

スクリーンショット 2021-03-08 15.31.18.png

反省点

  1. Laravelの認証周り(Guardやプロバイダー)の理解が浅く、原因追求に時間がかかりました。
  2. 真っ先にAWSからのレスポンスを確認すべきでした。次からは必ずそうします!!!

そのうちLaravel+Cognitoを使った認証/メール検証/サインアップの実装記事を書こうと思います。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravel+Cognitoでサインイン時にエラー"The security token included in the request is invalid."

事象

Laravel環境にCognitoを使用したサインアップ/サインイン機能を搭載したのですが、新規登録・メール検証済みユーザーでサインインしようとした時に全くもってサインインできませんでした。うんともすんとも動かねえぜ。
スクリーンショット 2021-03-08 15.32.05.png

前提条件として、Cognitoのアプリクライアントの設定で「認証用の管理 API のユーザー名パスワード認証を有効にする(ALLOW_ADMIN_USER_PASSWORD_AUTH)」を使用した場合でのエラーです。

結論を言うと環境変数に設定していたAWS_ACCES_KEY_IDが間違っていただけなのですが、なんとこのミスに気づかず6時間以上を無駄にしてしまったため、備忘録として残します。

以下、Laravel+Cognito構築で参考にさせて頂いた記事
https://blackbits.io/blog/laravel-authentication-with-aws-cognito
https://qiita.com/suzumurakk/items/efe4543cf0df2cd31659

原因

タイトルにもある通りで、裏では以下のエラーが返ってきていました。

The security token included in the request is invalid.(リクエストに含まれているセキュリティトークンが無効です。)

このエラーでググると、AWSに送信しているアクセスキーIDもしくはシークレットアクセスキーが無効とのことでした。
Laravelの.envを確認したところ、アクセスキーID(AWS_ACCES_KEY_ID)に余計な文字が入っておりました。チクショー!!
上記解決後、無事にサインインできることを確認しました。

スクリーンショット 2021-03-08 15.31.18.png

反省点

  1. Laravelの認証周り(Guardやプロバイダー)の理解が浅く、原因追求に時間がかかりました。
  2. 真っ先にAWSからのレスポンスを確認すべきでした。次からは必ずそうします!!!

そのうちLaravel+Cognitoを使った認証/メール検証/サインアップの実装記事を書こうと思います。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

laravel asset関数でcssファイルとimgを呼び出す

はじめに

HTMLでimgの表示とasset関数でimgを表示するのがごちゃごちゃになったので備忘録として投稿します。

asset関数とは?

asset関数とはlaravelにあるヘルパ関数の一つになります。
詳しくはlaravelの公式ページをご覧下さい。
画像の呼び出し、URLの遷移として使用可能です。

asset関数でimgを呼び出す方法?

asset関数はlaravelのpublicフォルダから見た時に、どこにあるのかを引数として指定する必要があります。laravelのフォルダ構成はスクショの様になっています。
“スクリーンショット” 2021-03-08 14.19.05.jpg

asset関数をどの様に記述するのか?

publicフォルダから見た時に、どこにあるのかを引数として書くには以下の様にします。

index.blade.php
//cssファイルの呼び出し
<link rel="stylesheet" href="{{ asset('/css/bulletin-board/index-list.css') }}" >

//画像の呼び出し
<img src="{{ asset('/css/images/black-board.jpg') }}" >

最後に

HTMLで<img src="images/black-board.jpg">で画像を呼び出せる方法は前から知っていたが知識が増えるとあれはどうなの?これはどうなの?と疑問が増えて試行錯誤の連続があると思います。一度整理してとりあえず書いてどの様に反映されるかを確認するキッカケとなりました。画像やcssファイルを呼び出すときはasset関数で統一するように調整してみます。

参考文献

Laravel 5、{{url}}と{{asset}}の違いは何ですか?

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

laravel asset関数でcssファイルと画像を呼び出す

はじめに

HTMLでimgの表示とasset関数でimgを表示するのがごちゃごちゃになったので備忘録として投稿します。

asset関数とは?

asset関数とはlaravelにあるヘルパ関数の一つになります。
詳しくはlaravelの公式ページをご覧下さい。
画像の呼び出し、URLの遷移として使用可能です。

asset関数でimgを呼び出す方法?

asset関数はlaravelのpublicフォルダから見た時に、どこにあるのかを引数として指定する必要があります。laravelのフォルダ構成はスクショの様になっています。
“スクリーンショット” 2021-03-08 14.19.05.jpg

asset関数をどの様に記述するのか?

publicフォルダから見た時に、どこにあるのかを引数として書くには以下の様にします。

index.blade.php
//cssファイルの呼び出し
<link rel="stylesheet" href="{{ asset('/css/bulletin-board/index-list.css') }}" >

//画像の呼び出し
<img src="{{ asset('/css/images/black-board.jpg') }}" >

最後に

HTMLで<img src="images/black-board.jpg">で画像を呼び出せる方法は前から知っていたが知識が増えるとあれはどうなの?これはどうなの?と疑問が増えて試行錯誤の連続があると思います。一度整理してとりあえず書いてどの様に反映されるかを確認するキッカケとなりました。画像やcssファイルを呼び出すときはasset関数で統一するように調整してみます。

参考文献

Laravel 5、{{url}}と{{asset}}の違いは何ですか?

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravel8でログファイルにデバッグする

Laravel8でログファイルにデバッグする方法をサクッと解説します。

ajax通信とかで処理する時は、便利ですよねーってやつなので、ぜひ知っておきましょう。

envファイルの書き換え

下記のように編集しておく

LOG_CHANNEL=single
LOG_LEVEL=debug

ログファイルにデバッグする

use Illuminate\Support\Facades\Log;

//省略

public function test(){
    Log::debug('test');
}

これで/storage/logs/laravel.logに出力されてるはず。

おしまい。簡単。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

アニメーション

アニメーションをまとめます。

チェックボックス

チェックマークがいい感じにつく

ezgif.com-gif-maker.gif

<input type="radio" name="test" id="test1">
<label for="test1">チェックボックス</label>
input[type="radio"] {
    display: none;
}

input[type="radio"]+label {
    display: block;
    position: relative;
    padding-left: 25px;
    margin-bottom: 0px;
    cursor: pointer;
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
}

input[type="radio"]+label:last-child {
    margin-bottom: 0;
}

input[type="radio"]+label:before {
    content: '';
    display: block;
    width: 15px;
    height: 15px;
    border: 1px solid #6cc0e5;
    position: absolute;
    left: 0;
    top: 3px;
    opacity: .8;
    -webkit-transition: all .12s, border-color .08s;
    transition: all .12s, border-color .08s;
}

input[type="radio"]:checked+label:before {
    width: 10px;
    top: -1px;
    left: 5px;
    border-radius: 0;
    opacity: 1;
    border-top-color: transparent;
    border-left-color: transparent;
    -webkit-transform: rotate(45deg);
    transform: rotate(45deg);
}

ツールチップ

text.blade.php
<button type="button" class="btn--circle btn--circle-c btn--shadow tooltip1 bookshelf_store_js" data-id="{{ $novel->id }}">
    <i class="fas fa-book-medical"></i>
    <div class="tooltip_content">本棚に追加</div>
</button>
text.scss
//ツールチップ
.tooltip1 {
    position: relative;
    cursor: pointer;
    display: inline-block;

    i {
        margin: 0;
        padding: 0;
    }

    & .tooltip_content {
        display: none;
        position: absolute;
        margin: 1.5em 0;
        padding: 7px 10px;
        min-width: 120px;
        max-width: 100%;
        color: #555;
        font-size: 0.9rem;
        background: #FFF;
        border: solid 2px $border_color;
        box-sizing: border-box;
        box-shadow: 1px 1px 5px $border_color;
        z-index: 2;

        &:before {
            content: "";
            position: absolute;
            top: -24px;
            left: 50%;
            margin-left: -15px;
            border: 12px solid transparent;
            border-bottom: 12px solid #FFF;
            z-index: 2;
        }

        &:after {
            content: "";
            position: absolute;
            top: -30px;
            left: 50%;
            margin-left: -17px;
            border: 14px solid transparent;
            border-bottom: 14px solid $border_color;
            z-index: 1;
        }
    }

    &:hover .tooltip_content {
        display: inline-block;
        top: 35px;
        left: -40px;
    }

}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

laravelアプリ作成時のコマンド実行で非常に時間がかかるのでダウンロードの詳細を出力してみる

目的

  • laravelアプリ作成時のコマンドが全然終わらないので詳細を出力するオプションをつけて実行してみた

環境

  • ハードウェア環境
項目 情報
OS macOS Catalina(10.15.5)
ハードウェア MacBook Pro (13-inch, 2020, Four Thunderbolt 3 ports)
プロセッサ 2 GHz クアッドコアIntel Core i5
メモリ 32 GB 3733 MHz LPDDR4
グラフィックス Intel Iris Plus Graphics 1536 MB
  • ソフトウェア環境
項目 情報 備考
PHP バージョン 7.4.8 Homebrewを用いてこちらの方法で導入→Mac HomebrewでPHPをインストールする
Laravel バージョン 6.X commposerを用いてこちらの方法で導入→Mac Laravelの環境構築を行う
MySQLバージョン 8.0.19 for osx10.13 on x86_64 Homwbrewを用いてこちらの方法で導入→Mac HomebrewでMySQLをインストールする
Node.jsバージョン v8.9.4 Homwbrewを用いてこちらの方法で導入→Mac HomebrewでNode.jsをインストールする

情報

  • 筆者はMacに直接laravelアプリ動作環境を構築してlaravelアプリの作成を行った。

困りごと

  1. 下記コマンドを実行してlaravel8のアプリを作成しようとしたが全然処理が完了しない。

    $ composer create-project "laravel/laravel=8.*" todos
    

ダウンロード進捗状況を逐一出力するようにしよう

  1. -vvvというオプションを付けることによりコマンドの作業進捗が出力される。

    $ composer create-project "laravel/laravel=8.*" todos -vvv
    
  2. フリーズすることもなく着々と依存性の解決とパッケージのダウンロードが行われていた。これなら時間が解決してくれそうなので気長に待つこととする。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Trying to get property of non-objectエラー

laravelでビューを作成している際に、Trying to get property of non-objectというエラーが出ました。
これは、アロー演算子の先に値がないというエラーです。

これを解決するには、optional()関数を使います。

{{ optional($post->category)->name }}

ヘルパー関数optional()は第二引数と共に利用し、第一引数(optionalの中)がnullでない時、第二引数を実行します。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Trying to get property of non-objecエラー

laravelでビューを作成している際に、Trying to get property of non-objecというエラーが出ました。
これは、アロー演算子の先に値がないというエラーです。

これを解決するには、optional()関数を使います。

{{ optional($post->category)->name }}

ヘルパー関数optional()は第二因数と共に利用し、第一因数(optionalの中)がnullでない時、第二因数を実行します。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【オススメ書籍・教材あり】共同開発前に知っておかないと損すること5選

今回は、私が共同開発を経験し、開発前に知っていると開発がもっとスムーズだったなと思うことを5つにし記述していきたいと思います!

読むのをオススメする人

・共同開発をこれから始める人
・実務に初めて入る人

共同開発前に知っておかないと損すること5選

考え方
1. 抽象と具体
コミュニケーション
2. 進捗確認
3. メンバーとのコミュニケーション
技術面
4. 検索能力
5. Git・GitHubの使用方法

これらの5つです。

では一つ一つ説明をしていきます!

考え方:抽象と具体

これすごく大事です!!

抽象とは、解釈の自由度が高く・応用が効く
具体とは、解釈の自由度が低い・応用が効かない
ものです。

これを聞くと、どういう意味???

となると思いますので、今から抽象と具体について分けて説明していきます!

抽象とは

抽象とは、「いくつかの共通の事柄を一括りにしたもの」と考えてください

例:掃除
あるパーティの後、片付けをしないといけない時に支配人に
「テーブルにあるコップをゴミ箱に床に、落ちているゴミをゴミ箱に入れて、床をホウキではいてください」と言われると聞いていてとても煩わしくありませんか?

普通に掃除してというとすむ話なのにと

これこそが抽象です!

抽象を使うことによりお互いがある状況・知識を知っているととてもコミュニケーションが円滑に進める事ができます!

それに加えて思考がとてもシンプルに整理する事ができるというメリットつきです!

開発でわからないものがある時に要はこれは何と何を使って機能を実装するのかがわかると後で出てくる検索力が格段に上がります!

しかし、抽象概念だけを極めたとしてもそれだけでは、相手に何か質問をする時などに解釈の相違が出てきてしまいます!
その時に大事になってくるのが具体的な考え方です!

具体とは

具体とは、先ほどの抽象と逆の考え方で細かく細分化していく考え方になります!

私を例に出してみると
人間→男→Daichi
このDaichiというのが具体的な考え方ということになります!

具体的な考え方がなぜ必要なのか??
それは質問をする時・何か機能を実装する時に必要になるからです!

プログラミング初学者は、必ずエラーに悩まされます←これは絶対です!

しかし、最初の方は何でエラーが起きているか全くわかりませんその時に誰かに相談する時大体Slackなどのアプリで文字ベースで質問になると思います!

質問内容
「エラーが出てきてわかりません」
では質問された方も何の原因でエラーが起きているかがわかりません

その時に具体的に説明ができると回答者も回答がしやすくなります!

    オススメの質問方法
  1. エラーが起きた時点の状況←できるだけ詳細に書く
  2. エラーのメッセージの画像とエラーメッセージのコードを貼り付ける←コピーができる様に
  3. 何を試したか
  4. そこまでに至ったかを書く←自分の理解度を深めるためにも良い

具体の考え方ができるととても質問がやりやすくなります!

これはどんな時にも言えます!
状況:算数の5+5がわからない時の質問
A「算数がわからないです!」
B「算数の何がわからないの??」
A「足算!!」
B「足算のどの問題がわからないの??」
A「5+5がわからない!!(何でわかってくれないの)」
B(初めからそう言ってくれれば良いのに)

この様な状態が起きるのを避けるためにも具体的に状況を説明できる様にすると良いです!

なぜ抽象と具体を分ける必要があるのか

まとめると、
何か機能を作る時に
検索なら検索・いいね機能ならいいね機能とその機能を作るためのおおよそ作り方は検索するとわかりますが、検索機能であればそのまま自分の開発に貼り付けてうまく動きません個別により使うカラムとかが違うからです!

なので、何か機能を実装したいときは、どの様に作られているかの大枠を検索で学び、自分の機能には、それをどの様に使っていくかを考えていくのが大事になります!

なので、抽象的な考えだけでもダメですし、具体的な考えができるだけでもダメと言うことになります。

オススメ書籍:具体抽象トレーニング

コミュニケーション:進捗確認

ここからはコミュニケーションについて書いていきます!

プログラム書いていくだけなのにコミュニケーションと思った方もいるかもしれませんが、これはとても大事なことです!!

なぜなら、
プログラミング書いているのは、人だからです!

結局、
個人で作れるアプリには限界があります。
会社単位になるとみんなで一つのもの作るのにしっかりコミュニケーションを取らないと次の機能実装がやりにくいなどがあるからです。

進捗確認することは相手を安心させるのにもつながります!

そのためにオススメのアプリは、Trelloです!!

これは、ほとんどの方が使っていると思うのですが、軽く説明をすると
タスクごとにカードを作り
完成までの日にち・誰が作成中か・進捗報告もできる
優れものです。

僕も共同開発中は、とても使わせていただきました!!

メンバーとのコミュニケーション

これは、今どんなエラーで悩んでいるか・どこまで進んだかの共有するということです!

なぜ必要か??
共同開発で大切なことは悩みの共有です!

正直、共同開発をしていると自分の知らないエラーが必ず出てきます。
その時に一緒に考える事ができるメンバーがいるのは、とても助けになります!

僕自身それで何度も救われてきました!

自分が知らなくても相手ならその問題を知っている事が多々ありますその逆に相手が知らないことを自分が知っている場合があります!

この様に悩みを共有することによりより効率的に作業を進める事ができます!

自分がわからないエラーが出た際には
相手は、アウトプットになるために勉強になるし、自分は相手になるべくわかりやすく質問をしないといけません。
お互いにメリットがあります!!

さらにプログラミングを書いていると1人の時間が多く投げ出してしまいたくなる時もメンバーとコミュニケーションをとっているとメンバーも頑張ってるし自分も頑張らなければという感情になります!

やる気も大事ですが、そのやる気を維持させるための環境づくりも同じくらい大事になってきます!

技術:検索能力

これは1番大事と言っても過言ではないと思います!

プログラミングで全ての機能を覚える事は不可能です!!

なので、基礎概念などをしっかりと覚えると後は、いろんな機能の実装の度に自分でわからないことを調べそれを自分の実装したい機能の時にはどの様に応用するかを考えないといけません!

その際にも必要になってくるのが、抽象と具体です!

調べる際に自分の機能の具体的な内容を書き綴ってもあなたの機能にそのまま使える物はありません!

なので、まず何がわからないか細分化する必要があります!

カレーを作りたい時は、カレーの作り方を調べてその後に必要な食材を一つずつ列挙していく様に

プログラミングの機能実装も実装したい機能を検索しそれに必要なことを一つづつ調べていく

必要があります!

疑問に思った時に使える検索エンジン・サイト:


  • Google
    検索をする際は、Googleでほとんど全てを網羅できます!

  • Udemy(有料)
    動画で学ぶ事ができとても内容が濃いいです!
    教材購入時期は、月に何度かくるセールの時がお得!!

  • GitHub
    わからない事があれば他の人がすでに作った機能のコードを読み参考にする事ができます!

  • Qiita(無料)
    まさに今僕が書いているサイトです!
    いろんな人が自分の経験・知見などを書いてくれています!

上記のものをしっかりと使いこなす事ができかつそれを自身の問題に応用ができる様になるとどんなことでも解決できるはずです!

Git・GitHubの使用方法

これまでは、個人でやってたからGitHubなんて使ったことないという人もいると思いますが、共同開発では必ず必要になってきます!

実際にGit・GitHubの使ったことありますかという質問は就職の面接でも聞かれるくらい大事です!

Git・GitHubとは何なのか??

バージョン管理システムです!

どう言うこととなると思いますが、セーブ機能と考えてくれていると良いです!

これらを使うことによりいつでも戻りたい地点に戻ったり・エラーを確認したのちに新しく機能を実装できる様になります!

例えば、
アプリをリリースした際に他に追加機能を実装したい場合アプリをリリースしたファイルをそのまま編集をしていくと実装しきるまでそのアプリは、使えなくなる可能性があります!
さらに、追加機能をしている途中でファイルがぐちゃぐちゃになった際に前の状態に戻りたい時に一つ一つ戻すのは面倒ですし、大規模になるとどこを変更したかわからなくなり戻せなくなる可能性があります!

それを回避できるのがGit・GitHubです!
一つのタスクができるととりあえずセーブをしておき他のタスクに取り掛かる事ができます!
これをコミット・ブランチをきると言います

さらに、今やっているタスクがうまくいかなく前の状態に戻り作りたい際に前のセーブポイントに戻り再度作り直す事ができます!
これをチェックアウトと言います!

今回は、詳しくは書きませんがこれらはとても共同開発をする際には必須になりますので、共同開発をする前は必ず触りだけでもやっておくことをオススメします!


オススメの教材:
Udemy無料(Git:初めてのGitとGitHub)
Udemy有料(Git: もう怖くないGit!チーム開発で必要なGitを完全マスター)



こちらの2つの講座は、僕も受けましたが本当にわかりやすくかつ本質的な内容でしたのですごくオススメです!!

終わりに

今回は、共同開発前に僕がしておけばよかったなと思ったこと5選について書かせていただきました!

言語の基礎能力をつけるなどは、最低限ある状態を想定して書いたので今回の記事には書いておりません!
これが少しでも誰かに役に立つ幸いです!

最後までお読みいただきありがとうございました!!

*この記事は、アフィリエイトリンクは使っておりません

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

configファイルに好きなファイルを作成したら...

基本的なことになりますが、laravelでconfig配下に好きなファイルを作成したら、下記コマンドを実行しなければ反映されません。

php artisan config:cache
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

laravel8マルチログイン

はじめに

フロント画面と管理画面でログイン認証を分けたい場合の
実装方法を記載する。
業務ではオリジナルテンプレートを使用するパターンが多いので、
『laravel/ui』なし、独自コントローラーでの実装を目指します。
ログイン機能を作成します。
※ログアウトやリマインダーは今回はやりません。

やりたいこと

users:顧客
admins:管理者
別々のログイン画面でログイン認証可能にする。

環境

PHP 7.3.2
Laravel Framework 8.5.12
MariaDB 10.1.38

事前準備

Composerをインストール
https://weblabo.oscasierra.net/php-composer-windows-install/

laravel8環境構築

LaravelをComposerでインストール
composer create-project --prefer-dist laravel/laravel LaravelMultiLogin "8.*"
※しばらく時間がかかります

ディレクトリ移動
cd LaravelMultiLogin
サーバ起動
php artisan serve

ブラウザでhttp://localhost:8000/
にアクセスしてLaravelって表示されれば成功

ライブラリインストール

・fortify
composer require laravel/fortify
・laravelcollective
composer require laravelcollective/html

各種設定

①config/app.php 言語設定変更

config/app.php
'timezone' => 'Asia/Tokyo',
'locale' => 'ja',
'fallback_locale' => 'ja',
'faker_locale' => 'ja_JP',`

キャッシュクリア
php artisan config:cache

②「.env」設定変更(DB接続先の環境に合わせて変更)

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=db_name
DB_USERNAME=root
DB_PASSWORD=

③エラーメッセージ日本語化

下記、からダウンロード
https://github.com/Laravel-Lang/lang/tree/master/src/ja

メッセージファイルを配置
C:\XXX\LaravelMultiLogin\resources\lang\ja\auth.php
C:\XXX\LaravelMultiLogin\resources\lang\ja\pagination.php
C:\XXX\LaravelMultiLogin\resources\lang\ja\passwords.php
C:\XXX\LaravelMultiLogin\resources\lang\ja\validation-inline.php
C:\XXX\LaravelMultiLogin\resources\lang\ja\validation.php

validation.php
'attributes' => [
    'email' => 'メールアドレス',
    'password' => 'パスワード'
],

テーブル作成

マイグレーション作成

database\migrations\XXXX_XX_XX_XXXXXX_create_admins_table.php
    public function up()
    {
        Schema::create('admins', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->string('email')->unique();
            $table->timestamp('email_verified_at')->nullable();
            $table->string('password');
            $table->rememberToken();
            $table->timestamps();
        });
    }

マイグレーション実行
php artisan migrate

SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes (SQL: alter tableusersadd uniqueusers_email_unique(email))

上記エラーが発生した場合は、下記設定をし再度実行
※一度DB内で作成されたテーブルを全て削除

app\Providers\AppServiceProvider.php
namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Schema; // 追加

class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        //
    }

    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        //
        Schema::defaultStringLength(191); // 追加
    }
}

ログインデータ作成

seedファイル作成
php artisan make:seed MultiAuthTableSeeder\MultiAuthTableSeeder.php

        \DB::table('users')->insert([
            [
                'name' => 'user',
                'email' => 'user@example.com',
                'email_verified_at' => now(),
                'password' => \Hash::make('password'),
                'created_at' => now(),
                'updated_at' => now()
            ],[
                'name' => 'user2',
                'email' => 'user2@example.com',
                'email_verified_at' => now(),
                'password' => \Hash::make('password'),
                'created_at' => now(),
                'updated_at' => now()
            ]
        ]);
        \DB::table('admins')->insert([
            [
                'name' => 'admin',
                'email' => 'admin@example.com',
                'email_verified_at' => now(),
                'password' => \Hash::make('123456789'),
                'created_at' => now(),
                'updated_at' => now()
            ],[
                'name' => 'admin2',
                'email' => 'admin2@example.com',
                'email_verified_at' => now(),
                'password' => \Hash::make('123456789'),
                'created_at' => now(),
                'updated_at' => now()
            ]
        ]);
database\seeders\DatabaseSeeder.php
    public function run()
    {
        // \App\Models\User::factory(10)->create();
        $this->call(MultiAuthTableSeeder::class); // 追加
    }

seed実行
php artisan migrate:fresh --seed

コンフィグファイルを変更

config/auth.php
    'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],
        'admins' => [               // 追加
            'driver' => 'session',  // 追加
            'provider' => 'admins', // 追加
        ],                          // 追加

        'api' => [
            'driver' => 'token',
            'provider' => 'users',
            'hash' => false,
        ],
    ],

    'providers' => [
        'users' => [
            'driver' => 'eloquent',
            'model' => App\Models\User::class,
        ],
        'admins' => [                               // 追加
            'driver' => 'eloquent',                 // 追加
            'model' => App\Models\Admin::class,    // 追加
        ],                                        // 追加
    ],

    'passwords' => [
        'users' => [
            'provider' => 'users',
            'table' => 'password_resets',
            'expire' => 60,
            'throttle' => 60,
        ],
        'admins' => [                       // 追加
            'provider' => 'admins',         // 追加
            'table' => 'password_resets',   // 追加
            'expire' => 60,                 // 追加
            'throttle' => 60,               // 追加
        ],
    ],

キャッシュクリア
php artisan config:cache

モデル作成

php artisan make:model Admin -m
※Userモデルはあるため不要

app/Models/Admin.php
namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Foundation\Auth\User as Authenticatable; // 追加

class Admin extends Authenticatable // 変更
{
    use HasFactory;
}
routes/web.php
// ユーザーログイン
Route::get('user_login', [\App\Http\Controllers\UserLoginController::class, 'showLoginForm']);
Route::post('user_login', [\App\Http\Controllers\UserLoginController::class, 'login']);

Route::prefix('user')->group(function () {

    Route::middleware('auth:web')->group(function () {
        Route::get('dashboard', function () {
            Auth::guard('web')->logout();
            return 'ユーザーでログイン';
        });
    });
});

Route::prefix('admin')->group(function () {
    // 管理者ログイン
    Route::get('admin_login', [\App\Http\Controllers\AdminLoginController::class, 'showLoginForm']);
    Route::post('admin_login', [\App\Http\Controllers\AdminLoginController::class, 'login']);


    Route::middleware('auth:admins')->group(function () {
        Route::get('dashboard', function () {
            Auth::guard('admins')->logout();
            return '管理者でログイン';
        });
    });
});

コントローラー作成

php artisan make:controller UserLoginController

app/Http/Controllers/UserLoginController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class UserLoginController extends Controller
{
    //
    public function showLoginForm()
    {
        return view('user.login');
    }

    public function login(Request $request)
    {
        $this->validate($request, [
            'email' => 'required|email', 'password' => 'required',
        ]);

        $credentials = $request->only(['email', 'password']);

        if (\Auth::guard('web')->attempt($credentials)) {

            return redirect('user/dashboard'); // ログインしたらリダイレクト

        }

        return back()->withInput($request->only('email'))
            ->withErrors([
                'email' => ['認証情報が記録と一致しません。']
            ]);
    }
}

view作成

未ログイン時のリダイレクト先変更

/app/Exceptions/Handler.php
use Illuminate\Auth\AuthenticationException; // 追加

    protected function unauthenticated($request, AuthenticationException $exception)
    {
        if ($request->expectsJson()) {
            return response()->json(['message' => $exception->getMessage()], 401);
        }
        if ($request->is('admin') || $request->is('admin/*')) {
            return redirect('admin/admin_login');
        }
        return redirect('user_login');
    }

unauthenticated メソッド追加

resources/views/user/login.blade.php
<!doctype html>
<html lang="ja">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>ログイン</title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" crossorigin="anonymous">
</head>
<body>
<div id="app">
    <div class="container">
        <div class="row justify-content-center mt-5">
            <div class="col-md-6">
                <div class="card">
                    <div class="card-header">ユーザーログイン</div>
                    <div class="card-body">
                        {{ Form::open(['method' => 'post']) }}
                            <div class="form-group">
                                {{ Form::label('email', 'メールアドレス') }}
                                {{ Form::text('email', null, [
                                    'class' => 'form-control' . ($errors->has('email') ? ' is-invalid' : '')
                                ]) }}
                                @error('email')
                                    <div class="invalid-feedback">
                                        {{ $message }}
                                    </div>
                                @enderror
                            </div>
                            <div class="form-group">
                                {{ Form::label('password', 'パスワード') }}
                                {{ Form::password('password', [
                                    'class' => 'form-control' . ($errors->has('password') ? ' is-invalid' : '')
                                ]) }}
                                @error('password')
                                    <div class="invalid-feedback">
                                        {{ $message }}
                                    </div>
                                @enderror
                            </div>
                            <div>
                                <button type="submit" class="btn btn-primary">ログイン</button>
                            </div>
                        {{ Form::close() }}
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
</body>
</html>

php artisan make:controller AdminLoginController

app/Http/Controllers/AdminLoginController.php
<?php
namespace App\Http\Controllers;

use Illuminate\Http\Request;

class AdminLoginController extends Controller
{
    //
    public function showLoginForm()
    {
        return view('admin.login');
    }

    public function login(Request $request)
    {
        $this->validate($request, [
            'email' => 'required|email', 'password' => 'required',
        ]);

        $credentials = $request->only(['email', 'password']);

        if (\Auth::guard('admins')->attempt($credentials)) {

            return redirect('admin/dashboard'); // ログインしたらリダイレクト

        }

        return back()->withInput($request->only('email'))
            ->withErrors([
                'email' => ['認証情報が記録と一致しません。']
            ]);
    }
}
resources/views/admin/login.blade.php
<!doctype html>
<html lang="ja">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>ログイン</title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" crossorigin="anonymous">
</head>
<body>
<div id="app">
    <div class="container">
        <div class="row justify-content-center mt-5">
            <div class="col-md-6">
                <div class="card">
                    <div class="card-header">管理者ログイン</div>
                    <div class="card-body">
                        {{ Form::open(['method' => 'post']) }}
                            <div class="form-group">
                                {{ Form::label('email', 'メールアドレス') }}
                                {{ Form::text('email', null, [
                                    'class' => 'form-control' . ($errors->has('email') ? ' is-invalid' : '')
                                ]) }}
                                @error('email')
                                    <div class="invalid-feedback">
                                        {{ $message }}
                                    </div>
                                @enderror
                            </div>
                            <div class="form-group">
                                {{ Form::label('password', 'パスワード') }}
                                {{ Form::password('password', [
                                    'class' => 'form-control' . ($errors->has('password') ? ' is-invalid' : '')
                                ]) }}
                                @error('password')
                                    <div class="invalid-feedback">
                                        {{ $message }}
                                    </div>
                                @enderror
                            </div>
                            <div>
                                <button type="submit" class="btn btn-primary">ログイン</button>
                            </div>
                        {{ Form::close() }}
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
</body>
</html>

参考記事

https://blog.capilano-fw.com/?p=8159
https://www.webopixel.net/php/1665.html

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む