20201009のlaravelに関する記事は11件です。

Laravel [マイグレーションの設定~テーブル作成〜カラム作成]

マイグレーション設定

モデルは artisan コマンドを使えば良いので php artisan とした後に、 make:model そして モデル名を今回は記事の Model なので Post としてあげましょう。
その後にバージョン管理するためのマイグレーションファイルも作りたいので、 php artisan make:model Post --migration のようなオプションを付けてあげましょう。
スクリーンショット 2020-10-08 16.00.27.png
こうする事でPostモデルとマイグレーションフォルダができます。

マイグレーションの記述

migration ファイルには up() と down() というメソッドがあるのですが、 up() がこのマイグレーションで行いたい処理、 down() はそれを巻き戻すための処理になります
スクリーンショット 2020-10-08 16.05.22.png

カラムの追加

column の種類なんですが、 SQL でいうところの varchar は string で設定していくので string('title') 、そして body に関してはテキストで設定したいので text('body') としてあげれば OKです。
スクリーンショット 2020-10-08 16.18.53.png
その後に、
php artisan migrate とするとdbにテーブルができます。

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

Laravel Sanctum(Laravel8)とNuxt.jsによるSPA認証

概要

業務でフロントを分離したくなってLaravelのAPI認証について調べてみると、Laravel7からSanctumの利用を推奨されていた。
Nuxtとの連携を調査したので作業ログも兼ねて記事として残します。

Sanctumについて

APIトークンを発行するタイプと、SPA認証の2種類を提供するライブラリです。
ここではSPA認証を紹介します。
和訳ドキュメント

完成品

最終的なコードを置いておきます。
https://github.com/nagi125/nuxt_laravel_auth_spa_sample
nuxt_laravel_auth_spa.png

環境

docker-composeで構成し、nginxでRPしています。

  • Host:Mac
  • Docker
    • nginx:1.19-alpine
    • node:13.8-alpine (Nuxt2.14.x)
    • php:7.4-fpm-alpine (Laravel8.x)

docker-composeは下記の通りです。

docker-compose.yml
version: '3'
services:
  nginx:
    container_name: nginx
    build:
      context: ./.docker/nginx
      dockerfile: Dockerfile
    ports:
      - 80:80
    tty: true
    restart: always
    depends_on:
      - web

  web:
    container_name: web
    build:
      context: ./.docker/web
      dockerfile: Dockerfile
    environment:
      PORT: '3000'
      HOST: '0.0.0.0'
    expose:
      - 3000
    volumes:
      - ./web:/app
    stdin_open: true
    tty: true
    restart: always
    depends_on:
      - api

  api:
    container_name: api
    build:
      context: ./.docker/api
      dockerfile: Dockerfile
    environment:
      LANG: 'ja_JP.UTF-8'
      TZ: 'Asia/Tokyo'
      LOG_CHANNEL: 'stderr'
      DB_CONNECTION: 'pgsql'
      DB_HOST: 'db'
      DB_PORT: '5432'
      DB_DATABASE: 'laravel_development'
      DB_USERNAME: 'docker'
      DB_PASSWORD: 'docker'
      SESSION_DOMAIN: 'localhost'
      SANCTUM_STATEFUL_DOMAINS: 'localhost'
    volumes:
      - ./api:/app
    expose:
      - 9000
    tty: true
    restart: always
    depends_on:
      - db

  db:
    image: postgres:12
    container_name: db
    environment:
      TZ: 'Asia/Tokyo'
      POSTGRES_USER: 'docker'
      POSTGRES_PASSWORD: 'docker'
      POSTGRES_DB: 'laravel_development'
    volumes:
      - db:/var/lib/postgresql/data
    ports:
      - 5432:5432

volumes:
  db:

「nginx」「web」「api」コンテナの細かい構成については下記から確認してください。
https://github.com/nagi125/nuxt_laravel_auth_spa_sample/tree/main/.docker

検証環境構築

完成品をCloneしていただいて、下記のコマンドで準備。

$ docker-compose up

Nuxt側

$ docker-compose exec web yarn install
$ docker-compose exec web yarn dev

Laravel側

$ docker-compose exec api composer install
$ docker-compose exec api cp .env.example .env
$ docker-compose exec api php artisan key:generate 
$ docker-compose exec api php artisan migrate:refresh --seed

以上で、Nuxt側・Laravel側の準備が完了です。

動作確認

http://localhost/login
メールアドレスとpasswordについてはLaravel側のseedで確認してください。
http://localhost/secret
にアクセスできれば認証成功です。

認証設定について

認証設定について何をしたのか記載していきます。

Laravel側

Sanctumの準備

$ docker-compose exec api composer require laravel/sanctum
$ docker-compose exec api php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"

Sanctumの設定

KernelにClassを追加

api/app/Http/Kernel.php
<?php

namespace App\Http;

use Illuminate\Foundation\Http\Kernel as HttpKernel;
use Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful; // 追加

// ...

    protected $middlewareGroups = [
        'api' => [
            EnsureFrontendRequestsAreStateful::class, // 追加
            'throttle:api',
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],
    ];

CORS設定

api/config/cors.php
<?php

return [
    'paths' => ['api/*'], // 変更
    'allowed_methods' => ['*'],
    'allowed_origins' => ['http://localhost:3000'], // 変更
    'allowed_origins_patterns' => [],
    'allowed_headers' => ['*'],
    'exposed_headers' => [],
    'max_age' => 0,
    'supports_credentials' => true, // 変更
];

.envに環境変数をセットする
※サンプルコードではdocker-compose.ymlに環境変数をセットしています。

SESSION_DOMAIN=localhost
SANCTUM_STATEFUL_DOMAINS=localhost

LoginControllerの準備

最低限の動作さえすればいい実装にしています。実際に使う場合はValidation含め作り込んでください。

api/app/Http/Controllers/Api/Auth/LoginController.php
<?php

namespace App\Http\Controllers\Api\Auth;

use App\Http\Controllers\Controller;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;

class LoginController extends Controller
{
    /**
     * @Method POST
     * @param  Request  $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function login(Request $request): JsonResponse
    {
        $credentials = $request->validate([
            'email' => 'required|email',
            'password' => 'required'
        ]);

        if (auth()->attempt($credentials)) {
            return response()->json(['message' => 'OK!'], 200);
        }

        return response()->json(['message' => 'ユーザーが見つかりません。'], 422);
    }
}

Routeの設定

認証用のRouteとUser情報取得用のRouteを設定します。
※ Laravel8からControllerの指定の仕方が変わったので注意してください。

api/routes/api.php
<?php

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\Api\Auth\LoginController;

Route::prefix('auth')->group(function() {
    Route::post('/login', [LoginController::class, 'login']);
});

Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
    return $request->user();
});

Laravel側は以上で準備完了です。

Nuxt側

Nuxtのプロジェクト作成にはUniversalモードとSPAモードとありますが、SPAモードで作成します。
※1. SSRではstoreの関係上、MiddlewareでAuthの設定が上手く反映されません。
※2. プロジェクト作成時にAxiosとBootStrapを指定しています。

必要ライブラリのインストール

サンプルを動かせばinstallされていますが、作業ログとして記録しておきます。

$ docker-compose exec web yarn add @nuxtjs/auth

Auth設定

web/nuxt.config.js
export default {
  // ....

  modules: [
    'bootstrap-vue/nuxt',
    '@nuxtjs/auth', // 追記
    '@nuxtjs/axios', // 追記
  ],
  axios: {
    baseURL: "http://localhost",
    credentials: true,
  },
  auth: {
    redirect: {
      login: '/login',
      logout: '/',
      callback: false,
      home: '/'
    },
    strategies: {
      local: {
        endpoints: {
          login: { url: '/api/auth/login', method: 'post', propertyName: false },
          user: { url: '/api/user', method: 'get', propertyName: false },
          logout: false
        },
        tokenRequired: false,
        tokenType: false,
      }
    },
    localStorage: false,
  },
  router: {
    middleware: ['auth']
  },
}

Store設定

store利用するためにindex.js用意しろと怒られるので作成します。

$ docker-compose exec web touch store/index.js

Loginページ設定

サンプルコードを見ていただければよいのですが、Loginページだけ記載しておきます。

web/pages/login.vue
<template>
  <div class="container">
    <h1 class="h1 pb-1 border-bottom border-dark">Login</h1>
    <p>ログイン状態: {{ $auth.loggedIn }}</p>
    <div class="row justify-content-md-center">
      <div class="col-6">
        <form name="login" @submit.prevent="login()">
          <div class="form-group">
            <label for="email">Email</label>
            <input type="email" class="form-control" id="email" placeholder="Enter email" v-model="form.email" required />
          </div>
          <div class="form-group">
            <label for="password">Password</label>
            <input type="password" class="form-control" id="password" placeholder="Enter password" v-model="form.password" required />
          </div>
          <button type="submit" class="btn btn-success">Submit</button>
        </form>
      </div>
    </div>
  </div>
</template>

<script>
  export default {
    data() {
      return {
        form: {
          email: '',
          password: ''
        },
      };
    },
    mounted() {
      // csrf対策 
      // nginxでRPする場合は/sanctumがapi側を見に行くようにしてください
      this.$axios.get('/sanctum/csrf-cookie');
    },
    methods: {
      async login() {
        try {
          const response = await this.$auth.loginWith('local', { data: this.form });
          console.log(response);

        } catch(error) {
          console.log(error);
        }
      },
    },
  };
</script>

作業は以上となります。

最後に

今回はLaravel Sanctumを利用したSPA認証について書きました。
あまりサンプルがなくて実装に苦労してしまったので、誰かにお役に立てればと思い、記事とします。
課題はSSR時にどうするかですね。そちらも解決できたらまた記事を書きたいと思います。

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

XAMPPで作ったLaravelプロジェクトをGitHubにアップする。*for Windows

そのままタイトル通りの記事になります。超初心者で、とりあえずGitHubにアップする手順を手っ取り早く確認したい、と言う方には読んでもらえる価値があるかも。環境はWindowsです。
※Git自体の説明はしていません。あくまでGitHubにアップする手順しか解説していません。

1. Gitをダウンロードする

手順1: 以下のサイトからGitをダウンロードします。
https://gitforwindows.org/
↓↓ 赤枠の部分からダウンロードします。
image.png

手順2: ダウンロードしたらインストールします。インストールする際の諸々の設定に関しては、特にカスタムせずにデフォルトのままで進めて問題ありません。
細かくカスタムされたい方は、↓↓こちらのサイトで詳しく説明されていたので、おススメです。
https://eng-entrance.com/git-install

2: Git Bashで確認する

手順1: インストールが終わったら、Git Bashを立ち上げて確認していきます。
Git BashはGit for Windowsをインストールした時に、自動的にインストールされているので、もう既にお使いのコンピューターに入っています。
Windowsのスタートメニューに『git』と入力すると、Git Bashが出てきますので、それを立ち上げます。

↓↓ここに『git』と入力します。
image.png

手順2: 正常にGitがインストールされているかを確認します。Git Bash(以後、ターミナルと称します。)に、『git version』と入力します。
以下画像のようにバージョン情報が出てくれば、正常にインストールされています。
image.png

3:GitHubでアカウント登録する

GitHubにまだアカウントを持っていない場合は、以下のサイトからアカウント登録します。
https://github.com/
アカウントの登録方法は沢山の分かりやすい記事がありますので、そちらでご確認を。因みに、noteで以下の記事を発見しました!
https://note.com/snmal_jp/n/n3ef510a8181e

4:Gitの初期設定をする

手順1: ターミナルからGitのコマンド操作をする為に、初期設定をしていきます。ユーザー名、メールアドレス、使用するエディターの3つの設定を行います。コマンドは以下の通りです。
ユーザー名:『git config --global user.name "Tomochan-taco"』("Tomochan-taco"の部分は、ご自身のGitHubのユーザー名を入れてください。)
メールアドレス:『git config --global user.email ***@gmail.com』(***@gmail.comの部分は、ご自身のメールアドレスを入れてください。)
使用するエディター:『git config --global core.editor "code --wait"』("code --wait"の部分は、ご自身の使用するエディターを入れてください。これはVisual Studio Codeの場合です。他に例えばATOMとかだったら、"atom --wait"です。)

↓↓ 以下の画像は、メールアドレス部分のみ隠させてもらいました。('ω')
image.png

手順2: 設定確認をします。『git config user.name』『git config user.email』『git config core.editor』のコマンドで、それぞれ確認することができます。
image.png
他にも『git config --list』で、設定項目を一度に確認することができます。また、『cat ~/.gitconfig』で設定ファイルの中身を確認することができます。

5:gitディレクトリを作成する

git add や git commit コマンドを操作する為に必要となる、gitディレクトリを作成します。
※ コマンドの意味については、Gitの構造自体の説明が必要となりますので、ここでは省きます。

手順1: どこにでもいいので、新規フォルダを作ります。
とりあえず私の場合は、Cドライブのユーザフォルダの個人フォルダ(C:\Users\TOMOKO OHASHI)に『restaurant_menu』という名前でフォルダを作ります。(『restaurant_menu』っていうプロジェクト名のアプリを作ったんです。。チュートリアルを後日公開予定♪ww )

手順2: 『restaurant_menu』フォルダに、XAMPPで作ったLaravelのプロジェクトの中身(C:\xampp\htdocs\restaurant_menuに作ったもの。)をドカーンと全部移動します。

手順3: ターミナルに戻り、cdコマンドで、『restaurant_menu』フォルダに移動します。
image.png
※ C:\xampp\htdocs に作ったプロジェクトのフォルダを、そのままgitディレクトリにしても問題ない場合は、手順1~手順3をすっ飛ばしてもらって構わないです。

手順4: 『git init』コマンドで、gitディレクトリを作成します。
image.png

手順5: 『ls -a』コマンドで、フォルダの中を確認してみます。lsコマンドは、-aオプションをつけると隠しファイルも見れるようになるので、『.git』ディレクトリも見れています。(『.git』ディレクトリは元々隠しファイルになっています。)
image.png

↓↓こちらの画面でも、隠しファイルにチェックを入れると、『.git』ディレクトリが作成されていることが確認できます。
image.png

6:git add をする

『git add』コマンドを実行して、ステージに追加します。今回はワークツリー全体を追加するので、『 git add . 』と打ちます。
image.png

7:git commitをする

『git commit』コマンドを実行して、レポジトリに記録します。
登録しておいたエディタが立ち上がりますので、必要なメモがある場合は記載して閉じます。
image.png

8:GitHubで準備する

GitHub側でレポジトリを作る準備をします。GitHubにサインインしておきます。

手順1: 画面右側上部のアカウントボタンをクリックして、Your Profileをクリックします。
image.png

手順2: 『Repositories』をクリックします。
image.png

手順3: 『New』をクリックします。
image.png

手順4: レポジトリ名を入力します。
image.png

手順5: レポジトリ名を入力したら、後は特に何も変更せずに『Create repository』をクリックします。
image.png

手順6: すると、以下のような画面となりますので、赤枠の部分をコピーしておきます。
image.png

9:Pushする

手順1: ターミナルに戻ります。まずはGitHubのリモートレポジトリを登録します。前回の手順6でコピーしておいたコマンドをターミナルに貼り付けます。
image.png

『git remote add origin 』ですが、このコマンドは、originという名前のショートカットで、GitHubのリモートレポジトリを登録するよ、という意味になります。

手順2: 『git push -u origin master』コマンドを実行して、pushします。ここで-uオプションをつけると、これ以降は『git push』だけでpushできるようになります。
image.png

git pushコマンドは、『git push <リモート名> <ブランチ名>』という構造になり、originとmaterは、それぞれデフォルトのレポジトリ名とブランチ名になります。詳しくは、以下のQiitaの記事で解説がありました!
https://qiita.com/seri1234/items/e651b3e108a695a92809

10:アップされているかを確認する

GitHubのサイトに戻って、<code>の部分をクリックします。
image.png
すると、以下画像のようにソースコードが無事アップロードされています!
image.png

以上で完了です!

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

Laravel5.5LTS: ライブラリを使わないマルチ認証-Fell版

Laravelのマルチ認証の記事はたいていコピペを多用してます。
コピペの多用バグの温床になりやすいので条件分岐で極力減らしてみました。

前提条件: Laravel5.5 インストール

Laravel5.5認証(公式)

.env(DB設定)

.env
//DB接続設定
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE={データベース名}
DB_USERNAME={user}
DB_PASSWORD={password}

AppServiceProvider.php

app/Providers/AppServiceProvider.php
//DBの191文字超えエラー回避設定
class AppServiceProvider extends ServiceProvider
{
    public function boot()
    {
++      \Illuminate\Support\Facades\Schema::defaultStringLength(191);
    }
}

Authとマイグレーション

認証のインストールとマイグレーション
//認証のインストール
$ php artisan make:auth
//認証用DBテーブル作成
$ php artisan migrate
//-> DBにusers・password_resetsテーブルが作成されたか確認。

Adminモデルの生成

Adminモデルとマイグレーションの生成
$ php artisan make:model Admin -m
//-> App/Admin.php
//-> database/migrations/{日付}_create_admins_table.php

Adminモデル

app/Admin.php
<?php
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;

class Admin extends Authenticatable //modify
{
    use Notifiable;
    protected $fillable = [
        'name', 'email', 'password',
    ];
    protected $hidden = [
        'password', 'remember_token',
    ];
}

Adminテーブルのマイグレーション

create_users_table.phpの内容をコピーして変更

database/migrations/{日付}create_admins_table.php
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateAdminsTable extends Migration //modify
{
    public function up()
    {
        Schema::create('admins', function (Blueprint $table) { //modify
            $table->increments('id');
            $table->string('name');
            $table->string('email')->unique();
            $table->string('password');
            $table->rememberToken();
            $table->timestamps();
        });
    }
    public function down()
    {
        Schema::dropIfExists('admins'); //modify
    }
}

adminテーブルのマイグレーション実行

$ php artisan migrate
//adminsテーブルが生成されたか確認

tinker -> adminユーザーの生成

password_hash(公式)

tinker
$ php artisan tinker
>>> $admin = new App\Admin;
>>> $admin->name = 'admin';
>>> $admin->email = 'test@test.com';
>>> $admin->password = password_hash('password', PASSWORD_DEFAULT);
>>> $admin->save();
//phpMyadmin等でユーザー生成の確認

auth.php(公式)

admin側の定義の追加

config/auth.php
<?php
return [
    'defaults' => [
        'guard' => 'user',
        'passwords' => 'users',
    ],
    'guards' => [
        'api' => [
            'driver' => 'token',
            'provider' => 'users',
        ],
        'user' => [
            'driver' => 'session',
            'provider' => 'users',
        ],
 +       'admin' => [
 +           'driver' => 'session',
 +           'provider' => 'admins',
 +      ],
    ],
    'providers' => [
        'users' => [
            'driver' => 'eloquent',
            'model' => App\User::class,
        ],
+        'admins' => [
+            'driver' => 'eloquent',
+            'model' => App\Admin::class,
+        ],
    ],
    'passwords' => [
        'users' => [
            'provider' => 'users',
            'table' => 'password_resets',
            'expire' => 60,
        ],
+        'admins' => [
+            'provider' => 'admins',
+            'table' => 'password_resets',
+            'expire' => 60,
+        ],
    ],
];

Laravelの認証機能は「ガード」「プロバイダ」を中心概念として構成されています。ガードは各リクエストごとに、どのようにユーザーを認証するかを定義します。たとえば、Laravelにはセッションストレージクッキーを使いながら状態を維持するsessionガードが用意されています。

ログインしていないときのリダイレクト先

app/Exceptions/Handler.php
<?php
namespace App\Exceptions;

use Exception;
use Illuminate\Auth\AuthenticationException; //add
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;

class Handler extends ExceptionHandler
{
    protected $dontReport = [
        //
    ];
    protected $dontFlash = [
        'password',
        'password_confirmation',
    ];
    public function report(Exception $exception)
    {
        parent::report($exception);
    }
    public function render($request, Exception $exception)
    {
        return parent::render($request, $exception);
    }
    //未ログイン時 -> ガード属性のログインページにリダイレクト
    public function unauthenticated($request, AuthenticationException $exception)
    {
        if($request->expectsJson()){
            return response()->json(['message' => $exception->getMessage()], 401);
        }
        if (in_array('admin', $exception->guards())) {
            return redirect()->guest(route('admin.login'));
        }
        return redirect()->guest(route('login'));
    }
}

ルーティング

route/web.php
<?php
Auth::routes();
// User 認証不要
Route::get('/', function () { 
    return redirect('/home');
});
// User ログイン後
Route::group(['middleware' => 'auth:user'], function() {
    Route::get('/home', 'HomeController@index')->name('home');
});
// Admin 認証不要
Route::group(['prefix' => 'admin'], function() {                                  
    Route::get('login', 'Admin\loginController@showLoginForm')->name('admin.login');
    Route::post('login', 'Admin\LoginController@login');     
});                                                                                 
// Admin ログイン後
Route::group(['prefix' => 'admin', 'middleware' => 'auth:admin'], function() {
    Route::post('logout', 'Admin\LoginController@logout')->name('admin.logout');
    Route::get('home', 'HomeController@index')->name('admin.home');
});

コントローラーの構成

adminフォルダを作成してAuthフォルダからLoginController.phpをコピーします。
WS000039.png

LoginController.php(Auth)

app/Http/Controller/Auth/LoginController
<?php
namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Http\Request;            //add
use Illuminate\Support\Facades\Auth;    //add

class LoginController extends Controller
{
    use AuthenticatesUsers;

    protected $redirectTo = '/home';

    public function __construct()
    {
        $this->middleware('guest')->except('logout');
    }
    public function logout(Request $request)
    {
        Auth::guard('user')->logout();  //modify
        return redirect('login');  //modify
    }
}

LoginController.php(Admin)

app/Http/Controller/Admin/LoginController.php
<?php
namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Http\Request;            //add
use Illuminate\Support\Facades\Auth;    //add

class LoginController extends Controller
{
    use AuthenticatesUsers;

    protected $redirectTo = 'admin/home'; //modify

    public function __construct()
    {
        $this->middleware('guest:admin')->except('logout');//modify
    }
    public function showLoginForm()
    {
        //login.blade.phpは共用
        return view('auth.login');  //modify
    }
    protected function guard()
    {
        return Auth::guard('admin');  //modify
    }
    public function logout(Request $request)
    {
        Auth::guard('admin')->logout();  //modify
        return redirect('admin/login');  //modify
    }
}

コントローラーの使用例(条件分岐の例)

HomeController.php
コントローラーではルート名からguardを判断します。
ルーティングがしっかりしていれば問題ないと考えます。

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

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;    //add

class HomeController extends Controller
{
    /**
     * 条件分岐に使用できるメソッド例
     * ヘルパ関数に登録しておけば便利になると思います。
     * ログインしているユーザーのadmin権限の有無
        public function isAdminRoute() {
            $bool = strpos(\Route::currentRouteName(), 'admin') !== false;
            return $bool;
        }
     * ログインしているユーザー情報を取得します。
        public function getUser() {
        if ($this->isAdminRoute()) {
            return Auth::guard('admin')->user();
        } else {
            return Auth::guard('user')->user();
        }
     */
    public function __construct()
    {
        $this->middleware('auth');
    }
    public function index()
    {
        //ユーザー情報の取得テスト
        //dd($this->getUser());
        return view('home');
    }
}

ログイン後のリダイレクト先

app/Http/Middleware/RedirectIfAuthenticated.php
<?php                                                               
namespace App\Http\Middleware;                                      

use Closure;                                                        
use Illuminate\Http\Request;                                        
use Illuminate\Support\Facades\Auth;                                

class RedirectIfAuthenticated                                       
{                                                                   
    public function handle($request, Closure $next, $guard = null) {
        if (Auth::guard($guard)->check()) {                         
            switch ($guard) {                                       
                case 'admin':                                       
                    return redirect('/admin/home');                 
                    break;                                          
                case 'user':                                        
                    return redirect('/home');                       
                    break;                                          
            }                                                       
        }                                                           
        return $next($request);                                     
    }                                                               
}                                                                   

ビュー

ルート名からguardを判断しています。
これもルーティングがしっかりしていれば問題ないと思ってます。

WS000041.JPG
ビューはコピペせずに条件分岐でuseradminの制御を行います。

app.blade.php

resources/views/layouts/app.blade.php
<!-- $now_route -> 現在のルート名 -->
<?php $now_route = \Route::currentRouteName(); ?>
~~略~~
    <!-- Styles -->
    <link href="{{ asset('css/app.css') }}" rel="stylesheet">
    @if (strpos($now_route, 'admin') !== false)
        <style>body{background-color: tomato;}</style>
    @endif
~~略~~
    <!-- Right Side Of Navbar -->
    <ul class="nav navbar-nav navbar-right">
        <!-- Authentication Links -->
        <!-- 未ログインの`user` -->
        @if (is_null(Auth::guard('user')->user()) && strpos($now_route, 'admin') === false)
            <li><a href="{{ route('login') }}">Login</a></li>
            <li><a href="{{ route('register') }}">Register</a></li>
        <!-- 未ログインの`admin` -->
        @elseif (is_null(Auth::guard('admin')->user()) && strpos($now_route, 'admin') !== false)
            <li><a href="{{ route('admin.login') }}">Login</a></li>
        @endif
            <li class="dropdown">
                <!-- ログイン中の`user` -->
                @if (!empty(Auth::guard('user')->user()) && strpos($now_route, 'admin') === false)
                    <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false" aria-haspopup="true" v-pre>
                        {{ Auth::guard('user')->user()->name }} <span class="caret"></span>
                    </a>
                    <ul class="dropdown-menu">
                        <li>
                    <a href="{{ route('logout') }}"
                    onclick="event.preventDefault();
                             document.getElementById('logout-form').submit();">
                    Logout</a>
                    <form id="logout-form" action="{{ route('logout') }}" method="POST" style="display: none;">
                        {{ csrf_field() }}
                    </form>
                <!-- ログイン中の`admin` -->
                @elseif (!empty(Auth::guard('admin')->user()) && strpos($now_route, 'admin') !== false)
                    <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false" aria-haspopup="true" v-pre>
                        {{ Auth::guard('admin')->user()->name }} <span class="caret"></span>
                    </a>
                    <ul class="dropdown-menu">
                        <li>
                    <a href="{{ route('admin.logout') }}"
                    onclick="event.preventDefault();
                             document.getElementById('logout-form').submit();">
                    Logout</a>
                    <form id="logout-form" action="{{ route('admin.logout') }}" method="POST" style="display: none;">
                        {{ csrf_field() }}
                    </form>
                @endif
                </li>
            </ul>
        </li>
    </ul>
~~略~~

Login.blade.php

resources/views/auth/login.blade.php
@extends('layouts.app')
<?php $now_route = \Route::currentRouteName(); ?>
@section('content')
~~略~~
    <div class="panel-body">
        <!-- 未ログインの`user` -->
        @if (is_null(Auth::guard('user')->user()) && strpos($now_route, 'admin') === false)
            <form class="form-horizontal" method="POST" action="{{ route('login') }}">
        <!-- 未ログインの`admin` -->
        @elseif (is_null(Auth::guard('admin')->user()) && strpos($now_route, 'admin') !== false)
            <form class="form-horizontal" method="POST" action="{{ route('admin.login') }}">
        @endif
            {{ csrf_field() }}
~~略~~
@endsection

Home.blade.php

resources/views/home.blade.php
<?php
$now_route = \Route::currentRouteName();
//ログイン者の属性条件選択の例
//ルート名からガード選択
$loginName = '';
if (strpos($now_route, 'admin') === false) {
    $loginName = Auth::guard('user')->user()->name;
} elseif (strpos($now_route, 'admin') !== false) {
    $loginName = Auth::guard('admin')->user()->name;
}
?>
@extends('layouts.app')
@section('content')
<div class="container">
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            <div class="panel panel-default">
                <div class="panel-heading">
                    {{ $loginName . 'さん' }} <!-- 使用例 -->
                </div>
                <div class="panel-body">
                    @if (session('status'))
                        <div class="alert alert-success">
                             {{ session('status') }}
                        </div>
                    @endif
                    You are logged in!
                </div>
            </div>
        </div>
    </div>
</div>
@endsection

いかがでしたでしょうか?
条件分岐のやり方を押さえることができれば改変・応用は簡単です。
少なくとも1つ機能を増やすためにファイル間を移動することは確実に減るでしょう。
改修デバッグ作業も同様です。
この記事は友人マルチ認証に苦しんでいたため書きました。
special thanks to uta & u.

LGTMお願いします!
ストックのついでにLGTMお願いします!
モチベーションがあがります!

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

Docker x Laravel めちゃくちゃ遅い Docker for Windows を爆速化する

@ucan-labさんのDocker x Laravel めちゃくちゃ遅い Docker for Mac を爆速化するの案4をWindows10で検証しました。

案4. ボリュームマウントを使う

vendorやnode_modulesのデータを名前付きボリュームに格納して、ホスト側とコンテナ側と分離して管理する案。
同期処理が発生しないので、その分速くなる。

docker-compose.ymlにボリュームマウントの設定を追加して、composerとnpmのインストールを比較します。この記事ではなぜ早くなるかは触れません。

結果

composer installnpm installの速度をそれぞれ比較しています。

$ time composer install
real    6m26.446s  -> 0m57.445s  # 6.7倍
user    0m9.375s   -> 0m3.035s
sys     0m51.148s  -> 0m1.544s

$ time npm install
real    1m31.764s  -> 0m22.720s  # 4.0倍
user    0m46.022s  -> 0m23.705s
sys     0m32.465s  -> 0m13.917s

Windows10環境では4~7倍速くなりました!
参照元のMacのように20倍とはいきませんでしたが、数行の追加だけで十分早くなって満足です!

環境

ホストOSの環境

  • Windows 10 Home バージョン2004(OSビルド 19041.508)
  • WSL2 (Ubuntu 20.04.1 LTS)
  • Docker version 19.03.13, build 4484c46d9d
  • docker-compose version 1.27.4, build 40524192

環境構築には下の記事が参考になります。
Windows Subsystem for Linux Installation Guide for Windows 10
Windows 10 Home で WSL 2 + Docker を使う | Qiita

コンテナ

Laravel + Nginx + MySQLの開発環境を使って検証します。
詳しくはブログで公開しています。

  • php (php-fpm) 7.4.1
    • composer 1.10.13
    • nodejs v12.18.4
    • npm 6.14.6
    • Laravel 8.8.0
  • mysql 8.0
  • nginx 1.19.2

composerとpackage.jsonは、プロジェクト作成からlaravel/jetstreamのInertiaをインストールしたところまでの状態です。

検証するdocker-compose.yml

コメントadd行の有無で速度を比較しています。

version: '3'

volumes: # add
  vendor-store: # add
  node_modules-store: # add

services:
  php:
    container_name: php
    build: ./docker/php
    volumes:
    - ./web:/var/www
    - vendor-store:/var/www/laravel/vendor # add
    - node_modules-store:/var/www/laravel/node_modules # add
    environment:
      TZ: Asia/Tokyo

  nginx:
    image: nginx
    container_name: nginx
    ports:
    - 80:80
    volumes:
    - ./web:/var/www
    - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
    depends_on:
    - php

  db:
    image: mysql:8.0
    container_name: db
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: database
      MYSQL_USER: docker
      MYSQL_PASSWORD: docker
      TZ: 'Asia/Tokyo'
    command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
    volumes:
    - ./docker/db/data:/var/lib/mysql
    - ./docker/db/my.cnf:/etc/mysql/conf.d/my.cnf
    - ./docker/db/sql:/docker-entrypoint-initdb.d
    ports:
    - 3306:3306

実行手順は参照元と同等です。パスを読み替えてください。

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

メールの送信元とは別のメアドを返信先に設定したい

自分が知らなかっただけかもだけどメモ。

あるメールに対して返信するとき、普通はFrom(送信元)のメアドが返信先に設定される。
これを変更したい場合、メールの送信元を変更したいと思いがちだけど
AWS SESから送信する場合などは、セキュリティ的な観点からメールの送信元を簡単には変えられない。
参考:制限緩和してサンドボックス外にいるSESから「Email address is not verified.」エラーが発生する | bbh

そんなときにのためのReplyTo(返信先)
ReplyToをヘッダに追加してあげると送信元とは別のメールを指定することができる。

以下はLaravelの例

Mail::send('emails.welcome', $data, function($message)
{
    $message->to('foo@example.com', 'John Smith')
        ->replyTo('reply@example.com', 'Reply Guy')
        ->subject('Welcome!');
});

参考:php - "Reply-to" field in Laravel mail is not working - Stack Overflow
参考:メール 7.x Laravel

そもそもメールヘッダにどんなものがあるか頭に入れておいた方が良さそう。後で読む。
メール系の知識 - Qiita

おしまい

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

ルーティングの基本(laravel,PHP)

web.php
//特定のHTTPメソッドに対応する場合

Route:○○('viewのパスを記入','コントローラー@アクションメソッド');

//複数のHTTPメソッドに対応する場合

Route::match(['〇〇','〇〇'],'viewのパスを記入','コントローラー@アクションメソッド');
//※['〇〇','〇〇']に指定した複数のメソッドを対応させることが可能

//全てのHTTPメソッドに対応する場合

Route::any('viewのパスを記入','コントローラー@アクションメソッド');

ルーティング情報をコントローラから取得する場合(ルートパラメーター)

web.php
#自動的に対応する値を引数に割り当ててる場合
Route::get('viewのパスを記入/{id}','コントローラ名@アクションメソッド');
#任意の値を引数に割り当てる場合
Route::get('viewのパスを記入/{id?}','コントローラ名@アクションメソッド');
#ルートパラメータを制限したい場合
Route::get('viewのパスを記入/{id}','コントローラ名@アクションメソッド')->where([id =>'[0-9],{2,3}'])
//[0-9]->0~9までの数値に対応
//{2,3} ->10桁から100桁の数値に対応
//定義済み関数のpreg_matchと同じ 
〇〇controller.php
#自動的に対応する値を引数に割り当ててる場合
class Controller extends Controller
{
    public function param(int $id){ 
        return 'id:'.$id;

    }

//.....
〇〇controller.php
#任意の値を引数に割り当てる場合
class Controller extends Controller
{
    public function param(int $id =任意の値){ 
        return 'id:'.$id;

    }

//.....
〇〇controller.php
#正規表現の場合
class Controller extends Controller
{
    public function param(int $id =任意の値){ 
    //※任意の値はルートパラメータで制約しているため従う必要がある
    //例:現在は[0~9],{2-3}に指定しているので 0〜9の数値で尚且つ100桁までの数値を定義する必要がある
     return 'id:'.$id;

    }

//.....

web.php
//可変長パラメータ
Route::get('viewのパスを記入{keywd?}','コントローラ@アクションメソッド')>where('keywd','.*')
//('keywd','.*') ->任意の文字が0文字~~+∞という意味
//可変長は長さが決まっていないことを挿す





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

brefphpを使って簡単にLaravelをサーバレス環境で動かす

はじめに

ここではbrefについてと、実際の使い方や使ってみた所感などをまとめてみようと思います。

brefphp とは?

PHPアプリケーションをAWS Lambdaに簡単にデプロイするための Composer パッケージです。
コマンド1つでサーバーからアプリケーションのデプロイまで行えます。

:information_source: 使い方

Step :one: serverless のインストール

bref は serverless コマンドを使用してAWS環境にデプロイを行います。
以下のコマンドでインストールしましょう。

npmの場合

npm install -g serverless

yarnの場合

yarn global add serverless

追加したら以下のコマンドでちゃんと実行できるか確認しましょう

$ serverless --version
Framework Core: 2.4.0
Plugin: 4.0.4
SDK: 2.3.2
Components: 3.2.1

Step :two: Laravelプロジェクトの作成 [公式]

今回はLaravelで使うため、プロジェクトを作成します。

Laravelインストーラーがない場合はインストールします

composer global require laravel/installer

プロジェクトを作成します。

laravel new brefphp-test

Step :three: brefphp パッケージのインストール [公式]

作成したLaravelプロジェクトのディレクトリに移動して、
brefphpをインストールします。

composer require bref/bref bref/laravel-bridge

デフォルトのサーバ構成設定ファイルを作成します。

php artisan vendor:publish --tag=serverless-config

Step :four: デプロイの準備

「アクセスキーID」と「シークレットアクセスキー」の作成

デプロイ前に、デプロイ先のサーバ(AWS)のアクセスキーとシークレットキーを使用します。
IAMのユーザー追加画面でテスト用ユーザーを作りましょう。

  1. ユーザー名を決めて、アクセスの種類の「プログラムによるアクセス」をチェックします。
    WS000000.jpg

  2. アクセス権限の設定です。「既存のポリシーを直接アタッチ」を選択して「AdministratorAccess」を選択します。
    名前の通り最強権限なので、発行されるキーは絶対に外部に漏らさないでください!
    WS000001.jpg

  3. タグはよしなに追加します。(自分は何もしません)
    WS000002.jpg

  4. ユーザーの追加完了です。
    「アクセスキーID」と「シークレットアクセスキー」をメモしておいてください。
    WS000004.jpg

プロファイルの追加

メモした「アクセスキーID」と「シークレットアクセスキー」をプロファイルに登録します。

$ aws configure --profile <プロファイル名>

AWS Access Key ID [None]: <アクセスキーID>
AWS Secret Access Key [None]: <シークレットアクセスキー>
Default region name [None]:
Default output format [None]:

すると、 ~/.aws/credentials (Windowsの場合は %USERPROFILE%/.aws/credentials) にプロファイルが登録されます。

/.aws/credentials
[<プロファイル名>]
aws_access_key_id = <アクセスキーID>
aws_secret_access_key = <シークレットアクセスキー>

Step :five: デプロイ

以下のコマンドでデプロイします。
<プロファイル名>は、先程(Step4)で登録した名前を指定してください。

$ serverless deploy -v --aws-profile=<プロファイル名>

Serverless: Packaging service...
Serverless: Excluding development dependencies...
Serverless: Creating Stack...
Serverless: Checking Stack create progress...
~~~~~~~[色々ログ出てきて]~~~~~~~
Serverless: Stack update finished...
Service Information
service: laravel
stage: dev
region: us-east-1
stack: laravel-dev
resources: 15
api keys:
  None
endpoints:
  ANY - https://xxxxxxxxxx.execute-api.us-east-1.amazonaws.com/dev
  ANY - https://xxxxxxxxxx.execute-api.us-east-1.amazonaws.com/dev/{proxy+}
functions:
  web: laravel-dev-web
  artisan: laravel-dev-artisan
layers:
  None

Stack Outputs
WebLambdaFunctionQualifiedArn: arn:aws:lambda:us-east-1:000000000000:function:laravel-dev-web:2
ArtisanLambdaFunctionQualifiedArn: arn:aws:lambda:us-east-1:000000000000:function:lara![WS000000.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/157186/369830d6-c723-975d-2b78-c94add355649.jpeg)
vel-dev-artisan:2
ServiceEndpoint: https://xxxxxxxxxx.execute-api.us-east-1.amazonaws.com/dev
ServerlessDeploymentBucketName: laravel-dev-serverlessdeploymentbucket-o2rnhi5yd9v6

生成されたエンドポイントにアクセスして、LaravelのWelcomeページが出てくれば成功です
Laravel.png

AWS Lambdaの関数にも追加されています。
WS000000.jpg

Step :six: 環境の削除

$ serverless remove コマンドで環境を削除できます。

$ serverless deploy -v --aws-profile=<プロファイル名>

Serverless: Getting all objects in S3 bucket...
Serverless: Removing objects in S3 bucket...
Serverless: Removing Stack...
Serverless: Checking Stack removal progress...
~~~~~~~[色々ログ出てきて]~~~~~~~
Serverless: Stack removal finished...
Serverless: Stack removal finished...

:desktop: ローカル環境の構築

Dockerでローカル環境を構築します。
すでにローカル用のイメージは用意されているので、すぐに立ち上げることができます。

Laravelプロジェクトと同じディレクトリに docker-compose.yml の作成

docker-compose.yml
version: "3.5"

services:
    web:
        image: bref/fpm-dev-gateway
        ports:
            - '8000:80'
        volumes:
            - .:/var/task
        links:
            - php
        environment:
            HANDLER: public/index.php
            DOCUMENT_ROOT: public
    php:
        image: bref/php-74-fpm-dev
        volumes:
            - .:/var/task:ro

docker-compose up -d でコンテナを起動します。1

http://localhost:8000 にアクセスするとLaravelのWelcomeページが表示されます。

:moneybag: 料金について

ローカル環境には料金はかかりません。
AWSにデプロイした際に以下のサービスを利用するため、料金が発生します。

  1. Lambda
  2. API Gateway
  3. S3
  4. CloudFormation

所感

個人開発で使って便利だったので、会社のプロジェクトでも導入してみました。
LambdaやAPI Gatewayによるいろいろな制限があったりして、思うように行かなかった部分もありますが、なんとかサービスもリリースしているような状態です。

EC2に比べてLambdaやAPI Gatewayの料金は基本的にトラフィック依存なので、
アクセス数のそんなにないサービスでは、かなりのコスト削減になりました。

:warning: 発生した問題とその対策

実際にプロジェクトに導入した際に発生した問題と、それについての対策を記述します。
もし似たような問題が発生した場合は参考になればと思います。

POSTで10MBを超えるファイルをアップロードできない

API GatewayのPOSTリクエストサイズの最大が10MBのため、大容量のファイルをPOSTできません。
最終的にS3にアップロードする予定だったので、S3でPresigned URL2を発行して、それに対しアップロードするようにしました。

6MBを超えるデータを返せない

またもやAPI Gatewayの制約により、レスポンスの最大は6MBです。
(まぁ、6MBなんて超えることなんて稀ですが…)
こちらも一度S3にアップロードしてPresigned URLを生成し、
フロントエンドから直接S3のURLを参照するようにしました。

APIのタイムアウトの最長が29秒

API Gatewayの制約上、29秒でタイムアウトしてしまいます。
なので、重い処理はAmazon SQSに投げて処理するようにしました。

PR

brefのSlackコミュニティに日本語チャンネルができました。
一緒にbrefについて語りましょう?


  1. 初回のみイメージをビルドするため時間がかかります。 

  2. 一時的に有効なURLを発行して直接S3にアップロードできるURL 

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

laravel ディレクティブについてのまとめ

laravel ディレクティブについて

bladeテンプレート(view)の中で利用できる命令のこと

○○.php
@foreach(連想配列as変数)
//PHPのforeachと同じ
@if条件式
//phpのifと同じ
@unless(変数)
//falseの場合に出力
@iseet(変数)
//trueの場合に出力
@empty(変数)
//変数が存在しない場合のみ(null)の時に出力
@switch
//phpのswitchと同じ
@for
//phpのfor文と同じ
@break
//phpのbreak文と同じ
@loop
//ちょっと特殊 ループ変数と呼ばれる ※わかりづらいので下記に例あり
//index:インデックス番号(0スタート)
//iteration:繰り返し数(1スタート)
//remaining:残っている要素数
//count:配列の総数
//first:最初の項目->>>配列の先頭の時には1を返す
//last:最後の項目 ->>>配列の最後尾の時には1を返す
//even:偶数回目か
//odd:奇数回目か
//depth:入れ子レベル
//parent:親のループ変数(ネストした入れ子の場合)
@forelse
//処理
@empty 
//配列が空の場合の処理
//配列が空の場合の出力を設定できる
//※データの表示によって振り分けるのに@ifディレクティブよりも@forelseの方がおすすめ
@php
//<?phpと同じだが使用は例外的とのこと
@yield(name,[,default])
//name テンプレートからプレイスホルダー(空)の変数を受け取る時に使用

//①
@section(name)
//default
 @show
//②
@section()
@parent
//default
//名前が示す通りにコンテンツのセクションを定義※上記の様に複数の定義方法がある

//default-> 規程のコンテンツ(アクション変数とか)
@each(path,データ,仮変数,配列が空の時に実行)


※※loopディレクティブの例

controller.php
    public function foreach_loop()
    {
        return view('view.foreach_loop', [
            'weeks' => [ '月', '火', '水', '木', '金', '土', '日' ]
        ]);

    }

foreach_loop.php
<tr>
  <th></th>
  <th>index</th>
  <th>iteration</th>
  <th>count</th>
  <th>first</th>
  <th>last</th>
  <th>even</th>
  <th>odd</th>
  <th>depth</th>
</tr>
@foreach ($weeks as $week)
  <tr>
    <td>{{ $week }}</td>
    <td>{{ $loop->index }}</td>
    <td>{{ $loop->iteration }}</td>
    <td>{{ $loop->count }}</td>
    <td>{{ $loop->first }}</td>
    <td>{{ $loop->last }}</td>
    <td>{{ $loop->even }}</td>
    <td>{{ $loop->odd }}</td>
    <td>{{ $loop->depth }}</td>
  </tr>
@endforeach
</body>
</html>

スクリーンショット 2020-10-08 19.12.28.png

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

「暗記」ダメ!!!!!!!!! 絶対!!!!!!!!

暗記ってダメなの?

学習をしていく中で1度は耳にする

「暗記」はダメ

といった論調があると思います

最初に結論を言っておくと私はこの記事で
暗記を全て否定するのではなく、拾ってくる情報リソースの多くで頻出している「単語」や「概念」は暗記しましょうね。と伝えたいです。

 私の背景

半年前の私は

・HTMLって何
・PHP何それ弱そう
・プログラミング=ホームページを作る事でしょ?

といったようにプログラミングに関してほとんど無知の状態でした。
今では半年間毎日1日8時間の学習を継続しているので、そんなふざけた状態ではないですが、当時は間違いなく全くの初学者でした。

私は初学者だった当時スクールに通うことはせずネットのPHP教材を購入し独学をはじめました。

少し話がそれますが、この半年でオンラインなどの交流会でスクールを卒業された方の話しを10人前後聞いてきたのですが、その方々の満足度は大変高い印象でした。ただし、接頭辞的な感じで、「挫折しない為には」いいですね。といった言い回しをされる方が多い印象でした笑

私も半年間独学をしてきた経験と周りの卒業された方の意見を合わせて考えると時間効率を求めるならスクールは大いにありだと思います。

スクールを通う段階としてはプロゲートで5つくらいの言語を一通りやってみてからでいいのかな〜といった印象です。

お金に余裕があって少しでも一人でやる自信がないと思っている方は即決でスクールを選んだ方が効率は絶対にいいです(こんな事言ってますがスクールの回し者ではありません笑。なんならエンジニアyoutuerみたいに一回くらい企業案件やってみたいです。この動画はテックアカ、、、、?)

さて本題に戻ります。

私はスクールには通いませんでしたがネットで教材を購入しそれを独学しました。その教材の中には「暗記してください」などとは書かれて言いませんでしたが、重要なポイントとして取り上げられているTipsはたくさんありました。

要するに何が言いたいかと言うと

単語レベルの理解はもちろん、多くの人が共通して主立って「重要」と言っている事は四の五の言わず暗記した方が後の開発効率がスムーズになる。

と言うのが私の意見です。

そんなの当たり前だろ。。記事にすることじゃないよね。。と思われるかもしれませんが

初学者の方で
・「暗記」をひとまとめにして「悪」と捉えている
・「暗記」って本当にダメなのか疑心暗鬼になっている

方は少なくないと思い、この記事を書きました。

少なからず私が学習初期の段階では色んな情報に触れて暗記する事に意味はないと一括りにしてしまっていました。

暗記しなくてもいい事

大きく分けると3つ程あるかと思います。
※前提として忘れないで頂きたいのはこれは学習して半年程度且つ実務未経験者の意見です?

1. コードの書き方を暗記する
  私が考えるに暗記してはいけないと情報発信されている方の本質的部分はここだと思います。
  ここは私が細かく言うまでもないですが、効率が悪く、キリがないですよね。笑
  これをやってしまっている方がいたら今すぐにその習慣を辞めて、コードを書いて覚えましょう!
  無心で書き続けていればいつの間にか覚えます。必ずです。

2. 開発環境の構築の仕方
  これはキリがないとか効率が悪いとか言うより初学者のうちにここを重点的に覚えようとすると、挫折率が上がってしまうかと思います。
  サーバーやネットワークの知識が必要となってくるので初学者の段階は
 「そう言うものを使っているんだな」程度の理解でいいのではないでしょうか。

3. 関数を全て覚えようとする
  これもコードを暗記するに近いですが、仮に全て覚えても一生使わないものも出てくる可能性があり且つ効率が悪いからです。
  経験上、使用頻度の高い関数はコードを書いて入れば勝手に覚えます。つまり使用頻度が高い=重要度の高い関数と言う認識で良いかと。

暗記した方がいい事

さて、今度は逆に暗記した方がいい事について少しみていきましょう。
冒頭でも述べましたが、暗記をした方が良い内容は 拾ってくる情報リソースの多くで頻出している「単語」や「概念」の事でしたね。

では具体的にはどう言った単語や概念でしょうか。
私の経験から「早めに覚えておいてよかった」「ここは早めに深く覚えておけばよかった」点から解説します。
※ここからはさらに個人的主観が強くなりますでご了承ください
以下の内応は一応、PHPを対象としていますの
if文/繰り返し文/関数/引数/戻り値/変数
と言ったどのプログラミング言語でも共通する基礎の部分は除きます

ざっくりですが以下2点の理解をまずは「暗記」する事を私はお勧めします。

1.$GETと$POST

2.データベースは何をしているか

詳しくは次の段落で書いていきます。

$GETと$POST

 [なぜこれを覚えておいた方が良いのか]

 それはPHP言語でCRUDを実装する時に超頻出の概念だからです。
 (CRUDとは、システムに必要な4つの主要機能である「Create(生成)」「Read(読み取り)」「Update(更新)」「Delete(削除)」の頭文字を並べた用語です。)
 CRUDはWEBアプリ制作する上で基本的な考え方になります。

 PHPとよく比較されるプログラミング言語が、JavaScriptです。この両者はスクリプト言語でも、動作については全く異なります。
 JavaScriptはHTMLやCSS、画像と同じようにブラウザを表示しているPCにファイルをダウンロードしてから実行し動作するのに対し
 PHPはWebサーバ上にファイルを置いて、以下の順で実行されます。

 1.ブラウザを見ているユーザがクリックなど何かの操作をする
 2.その動作を受けたプログラムがサーバで動作する
 3.動作結果をレスポンスとして、インターネット経由で送り、ブラウザ上にHTMLを表示する
 
このようにPHPのような言語は、サーバサイドのプログラミング言語と呼ばれ、PHPはサーバー側で動くプログラミング言語でこの全体の処理の中でも、$_GETと$_POSTは超頻出です。つまりこの2つの処理が何をしているのかを「暗記」する事はPHPを早く上達する上では効率が良いと言えます。
 

 GETやPOSTについてもっと詳しく知りたいと言う方はこちらの書籍を読んでみるのもいいかと思います。
 HTTP通信についての理解が深まりクライアントとサーバーが裏でどんな事をやっているかのイメージがつくかと思います。
www.amazon.co.jp/dp/4774142042

データベースは何をしているか

データベースを扱うアプリケーションでは「CRUD」のアクションが基本となります。
つまり、データベースに対して行うアクションは、

・データベースにデータを「新規登録」する、
・そのデータを「読み出す」、
・そのデータを「変更し上書き」登録する、
・そのデータを「削除」する、

という、「基本この4つしか無い」ということです。

つまりこの流れのイメージを意識的に暗記する事でコードを書いている時に、今何やっているかの把握ができ結果として開発効率が上がると考えます。

[補足]
個人的にはSQL文法も暗記しておいた方が効率が良いのではと思っています。これも超頻出なので。笑

最後に

まとめとして、頻出する単語や概念、その周りの流れは覚えてしまった方が結果的に効率が上がると言う事です。

本記事とは少しずれますが、有名な方の発言を鵜呑みにするのではなく、その意見を一回自分の頭に持ち込んで、処理して自分なりの答えを導き出すと言う事も重要です。この「脳に対する意識的な習慣」ができていると、エラー時にもイライラしなくなると思います。(エラーでイライラしてしまう人は他責思考が強い人だと思う)
この事は自戒を含めて伝えたいなと思いました。

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

「暗記」ダメ!!!! 絶対!!!!それって本当ですか?

暗記ってダメなの?

学習をしていく中で1度は耳にする

「暗記」はダメ

といった論調があると思います

最初に結論を言っておくと私はこの記事で
暗記を全て否定するのではなく、拾ってくる情報リソースの多くで頻出している「単語」や「概念」は暗記しましょうね。と伝えたいです。

私の背景

半年前の私は

・HTMLって何
・PHP何それ弱そう
・プログラミング=ホームページを作る事でしょ?

といったようにプログラミングに関してほとんど無知の状態でした。
今では半年間毎日1日8時間の学習を継続しているので、そんなふざけた状態ではないですが、当時は間違いなく全くの初学者でした。

私は初学者だった当時スクールに通うことはせずネットのPHP教材を購入し独学をはじめました。

少し話がそれますが、この半年でオンラインなどの交流会でスクールを卒業された方の話しを10人前後聞いてきたのですが、その方々の満足度は大変高い印象でした。ただし、接頭辞的な感じで、「挫折しない為には」いいですね。といった言い回しをされる方が多い印象でした笑

私も半年間独学をしてきた経験と周りの卒業された方の意見を合わせて考えると時間効率を求めるならスクールは大いにありだと思います。
スクールを通う段階としてはプロゲートで5つくらいの言語を一通りやってみてからでいいのかな〜といった印象です。
お金に余裕があって少しでも一人でやる自信がないと思っている方は即決でスクールを選んだ方が効率は絶対にいいです(こんな事言ってますがスクールの回し者ではありません笑。なんならエンジニアyoutuerみたいに一回くらい企業案件やってみたいです。この動画はテックアカ、、、、?)

さて本題に戻ります。

私はスクールには通いませんでしたがネットで教材を購入しそれを独学しました。その教材の中には「暗記してください」などとは書かれて言いませんでしたが、重要なポイントとして取り上げられているTipsはたくさんありました。

要するに何が言いたいかと言うと

単語レベルの理解はもちろん、多くの人が共通して主立って「重要」と言っている事は四の五の言わず暗記した方が後の開発効率がスムーズになる。

と言うのが私の意見です。

そんなの当たり前だろ。。記事にすることじゃないよね。。と思われるかもしれませんが

初学者の方で
・「暗記」をひとまとめにして「悪」と捉えている
・「暗記」って本当にダメなのか疑心暗鬼になっている

方は少なくないと思い、この記事を書きました。

少なからず私が学習初期の段階では色んな情報に触れて
「暗記は効率悪いんだ」と一括りにしてしまっていました。

暗記しなくてもいい事

もちろん暗記する方が圧倒的に効率が悪くなることもあると思います。
そこで、大きく分けてみると3つに分類できるかなと思います。
※前提として忘れないで頂きたいのはこれは学習して半年程度且つ実務未経験者の意見です?また、PHPやLaravel以外の言語に関しては詳しくないのでご了承ください。笑

1. コードの書き方を暗記する
  私が考えるに暗記してはいけないと情報発信されている方の本質的部分はここだと思います。
  ここは私が細かく言うまでもないですが、効率が悪く、キリがないですよね。笑
  これをやってしまっている方がいたら今すぐにその習慣を辞めて、コードを書いて覚えましょう!
  無心で書き続けていればいつの間にか覚えます。必ずです。

2. 開発環境の構築の仕方
  これはキリがないとか効率が悪いとか言うより初学者のうちにここを重点的に覚えようとすると、挫折率が上がってしまうかと思います。
  サーバーやネットワークの知識が必要となってくるので初学者の段階は
 「そう言うものを使っているんだな」程度の理解でいいのではないでしょうか。

3. 関数を全て覚えようとする
  これもコードを暗記するに近いですが、仮に全て覚えても一生使わないものも出てくる可能性があり且つ効率が悪いからです。
  経験上、使用頻度の高い関数はコードを書いて入れば勝手に覚えます。つまり使用頻度が高い=重要度の高い関数と言う認識で良いかと。

暗記した方がいい事

さて、今度は逆に暗記した方がいい事について少しみていきましょう。
冒頭でも述べましたが、暗記をした方が良い内容は 拾ってくる情報リソースの多くで頻出している「単語」や「概念」の事でしたね。

では具体的にはどう言った単語や概念でしょうか。
私の経験から「早めに覚えておいてよかった」「ここは早めに深く覚えておけばよかった」点から解説します。
※ここからはさらに個人的主観が強くなりますでご了承ください
以下の内応は一応、PHPを対象としていますの
if文/繰り返し文/関数/引数/戻り値/変数
と言ったどのプログラミング言語でも共通する基礎の部分は除きます

ざっくりですが以下2点の理解をまずは「暗記」する事を私はお勧めします。

1.$GETと$POST

2.データベースは何をしているか

詳しくは次の段落で書いていきます。

$GETと$POST

 [なぜこれを覚えておいた方が良いのか]

 それはPHP言語でCRUDを実装する時に超頻出の概念だからです。
 (CRUDとは、システムに必要な4つの主要機能である「Create(生成)」「Read(読み取り)」「Update(更新)」「Delete(削除)」の頭文字を並べた用語です。)
 CRUDはWEBアプリ制作する上で基本的な考え方になります。

 PHPとよく比較されるプログラミング言語が、JavaScriptです。この両者はスクリプト言語でも、動作については全く異なります。
 JavaScriptはHTMLやCSS、画像と同じようにブラウザを表示しているPCにファイルをダウンロードしてから実行し動作するのに対し
 PHPはWebサーバ上にファイルを置いて、以下の順で実行されます。

 1.ブラウザを見ているユーザがクリックなど何かの操作をする
 2.その動作を受けたプログラムがサーバで動作する
 3.動作結果をレスポンスとして、インターネット経由で送り、ブラウザ上にHTMLを表示する
 
このようにPHPのような言語は、サーバサイドのプログラミング言語と呼ばれ、PHPはサーバー側で動くプログラミング言語でこの全体の処理の中でも、$_GETと$_POSTは超頻出です。つまりこの2つの処理が何をしているのかを「暗記」する事はPHPを早く上達する上では効率が良いと言えます。
 

 GETやPOSTについてもっと詳しく知りたいと言う方はこちらの書籍を読んでみるのもいいかと思います。
 HTTP通信についての理解が深まりクライアントとサーバーが裏でどんな事をやっているかのイメージがつくかと思います。
www.amazon.co.jp/dp/4774142042

データベースは何をしているか

データベースを扱うアプリケーションでは「CRUD」のアクションが基本となります。
つまり、データベースに対して行うアクションは、

・データベースにデータを「新規登録」する、
・そのデータを「読み出す」、
・そのデータを「変更し上書き」登録する、
・そのデータを「削除」する、

という、「基本この4つしか無い」ということです。

つまりこの流れのイメージを意識的に暗記する事でコードを書いている時に、今何やっているかの把握ができ結果として開発効率が上がると考えます。

[補足]
個人的にはSQL文法も暗記しておいた方が効率が良いのではと思っています。これも超頻出なので。笑

最後に

まとめとして、頻出する単語や概念、その周りの流れは覚えてしまった方が結果的に効率が上がると言う事です。

本記事とは少しずれますが、有名な方の発言を鵜呑みにするのではなく、その意見を一回自分の頭に持ち込んで、処理して自分なりの答えを導き出すと言う事も重要です。この「脳に対する意識的な習慣」ができていると、エラー時にもイライラしなくなると思います。(エラーでイライラしてしまう人は他責思考が強い人だと思う)
この事は自戒を含めて伝えたいなと思いました。

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