20200514のlaravelに関する記事は6件です。

LaravelのPHPUnitでWithFakerなどのTraitが動かない

当初以下のようなコードを書いていたのだが、

namespace Tests\Unit\Repositories;

use PHPUnit\Framework\TestCase;
use App\Models\User;
use App\Constants;
use App\Repositories\PgSql\UserRepository;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;

class UserRepositoryTest extends TestCase
{
    use WithFaker, RefreshDatabase;

    protected function setUp(): void
    {
        parent::setUp();
    }

    // expected 1 user is found, not others.
    public function testFindUserByAuthInfo()
    {
        $repo = new UserRepository();
        // findable
        $user = factory(User::class)->create([
            'id' => $this->faker->uuid,
            'password' => password_hash($this->faker->password(), PASSWORD_BCRYPT),
            'account_id' => 1,
            'email' => $this->faker->email,
        ]);

実行すると

1) Tests\Unit\Repositories\UserRepositoryTest::testFindUserByAuthInfo
Trying to get property 'uuid' of non-object

と$this->fakerでFakerがインスタンス化できていない模様

散々調べた挙げ句、結局
use PHPUnit\Framework\TestCase;

use Tests\TestCase;
にしたら直ったというお話。

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

laravelのルートモデルバインディング

役割

ルートとモデルの結びつけを自動的に行ってくれる。

参考例

web.php
Route::get('/user/{user}/show', 'UserController@show');
UserController.php
public function show(User $user)
{
   return $user->name;
}

このようにweb.phpで定めたURL/user/{user}/showの{user}と
コントローラーの引数に定めた$userが一致している場合、
URLの{}の中身をIDと見なしそれに一致するモデルクラスのインスタンスを自動的に作成してくれる。

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

【Laravel】Composer requireでエラー(Installation failed, reverting ./composer.json to its original content.)が出るけどrequireしたい!

composer requireしてみる

今回私はlarevel uiをインストールしたかった。

composer require laravel/ui

スクリーンショット 2020-05-14 14.45.55.png

エラーで乙。

原因

今入れようとしたパッケージとすでに入っているパッケージがそれぞれ同じパッケージの違うバージョンに依存してしまっているよう?

解決法

このようにバージョン指定にアスタリスクをつけて、依存関係が解決されるバージョンが存在するのを祈る。

composer require laravel/ui:0.*

0から試していく。

スクリーンショット 2020-05-14 14.49.31.png

違うバージョンの時は上の画像のようなエラーが出るが、順次数字を足しながら試していくと合うバージョンが見つかり、インストールできる。

スクリーンショット 2020-05-14 14.50.42.png

成功っ!!
私の時は、

composer require laravel/ui:1.*

これで成功しました?

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

LaravelとVueでSPAを作るときにTypescriptとpugを使う設定をする

LaravelVue.jsTypescriptpugSPAを作ったときのメモ。

docker --version
Docker version 19.03.8, build afacb8b

扱ったDockerのバージョンは19.03.8。

Fig.1
project
├── db
├── web
├── Dockerfile
├── docker-compose.yml
└── .env

以下の手順で Fig.1 のような構成のレポジトリを作り、webディレクトリの中にLaravelをインストールする。

レポジトリと各ファイルを作成

mkdir project_name && cd $_ && touch {docker-compose.yml,Dockerfile,.env}

プロジェクトのディレクトリを作成し( mkdir project_name )、作成したディレクトリに移動し( cd $_ ) 1docker-compose.yml, Dockerfile, .env ファイルを作成する( touch {docker-compose.yml,Dockerfile,.env} )。

この時点で Fig.2 の構成になる。

Fig.2
project_name
├── Dockerfile
├── docker-compose.yml
└── .env

各ファイルは以下の内容で書く。

docker-compose.yml

docker-compose.yml
version: '3'
services:
  web:
    build: .
    container_name: ${PROJECT}-web
    ports:
      - 80:80
      - 3000:3000
    volumes:
      - ./web:/var/www/html/${PROJECT}
    depends_on:
      - db
  db:
    image: mysql:8
    container_name: ${PROJECT}-mysql
    restart: always
    environment:
      MYSQL_DATABASE: ${PROJECT}
      MYSQL_USER: ${DB_USER}
      MYSQL_PASSWORD: ${DB_PASSWORD}
      MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
      TZ: ${TZ}
    ports:
      - 3306:3306
    volumes:
      - ./db:/var/lib/mysql

Dockerfile

Dockerfile
FROM php:7.4-fpm

COPY --from=node:12
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
RUN apt-get update \
  && apt-get install -y wget git zip unzip vim libpq-dev \
  && : 'Install PHP Extensions' \
  && docker-php-ext-install pdo_mysql pdo_pgsql \

WORKDIR /var/www/html/project_name

マルチステージビルド2Node.jsComposerDocker公式イメージ を利用する。

.env

.env
PROJECT=project_name
DB_USER=user_name
DB_PASSWORD=password
TZ=Asia/Tokyo

コンテナを起動

docker-compose up -d

この時点で Fig.1 の構成になる。

コンテナに入る

docker-compose exec web bash

コンテナの中ではcomposernpmが使える。

# composer --version
Composer version 1.10.6 2020-05-06 10:28:10

# node --version
v12.16.3

# npm --version
6.14.5

Laravelをインストール

# composer create-project --prefer-dist laravel/laravel .

// バージョンを指定する場合 (e.g. Laravel6 を指定する場合)
# composer create-project --prefer-dist laravel/laravel . "6.*"

Laravelの設定

web/config/app.php

app.php
<?php

return [

    // 他の設定

    'timezone' => 'Asia/Tokyo',
    'locale' => 'ja',

    // 他の設定
];

設定値を変更。

web/.env

.env
// 他の設定
DB_CONNECTION=mysql
DB_HOST=db
DB_PORT=3306
DB_DATABASE=project_name
DB_USERNAME=user_name
DB_PASSWORD=password
// 他の設定

データベースに接続するための情報を入れる。
MySQLに接続する場合はDB_CONNECTION=mysql
DB_HOSTdocker-compose.ymlservicesで設定したdbとする。
他の設定も .env で設定したものと同じ。

パッケージをインストール

# npm i
# npm i vue vue-router pug pug-plain-loader --save-dev  
# npm i -g typescript
# tsc --init

typescriptをグローバルにインストールするとtscコマンドが使えるようになり、

# tsc --version
Version 3.8.3

tsc --initとするとtsconfig.jsonが生成される。3
tsc --initgit init と混同して tsc init としないように注意。4

ファイルを編集

web/webpack.mix.js

webpack.mix.js
const mix = require('laravel-mix')

/*
 |--------------------------------------------------------------------------
 | Mix Asset Management
 |--------------------------------------------------------------------------
 |
 | Mix provides a clean, fluent API for defining some Webpack build steps
 | for your Laravel application. By default, we are compiling the Sass
 | file for the application as well as bundling up all the JS files.
 |
 */

mix
.webpackConfig({
  module: {
    rules: [{
      test: /\.pug$/,
      oneOf: [
        {
          resourceQuery: /^\?vue/,
          use: ['pug-plain-loader']
        },
        {
          use: ['raw-loader', 'pug-plain-loader']
        }
      ]
    }]
  }
})
.browserSync({
  proxy: '0.0.0.0:80',
  open: false,
  files: [
    'resources/**/*',
    'public/**/*'
  ]
})
.ts('resources/ts/app.ts', 'public/js/app.js')
.sass('resources/sass/app.scss', 'public/css')
.version()

pugを扱うための設定も記載する。5
BrowserSyncの設定を記入。6 7
mix.js() と書かれていた部分を mix.ts() 変えるだけ。8 あとは扱うファイルの変更に従って引数のファイルもjsからtsに変更する。

web/resources/ts/app.ts

app.ts
import Vue from 'vue'
import router from './router'
import App from './App.vue'
new Vue({
  el: '#app',
  router,
  components: { App },
  template: '<App />'
})

web/resources/js/app.jsweb/resources/ts/app.ts に書き換える。
ここで App.vuerouter.ts を読み込む。

web/resources/ts/App.vue

App.vue
<template lang="pug">
div
  main
    RouterView
</template>

ルートコンポーネント。
ここで Vue Router が提供する RouterView9 を使う。

web/resources/ts/router.ts

router.ts
import Vue from 'vue'
import VueRouter from 'vue-router'
import Foo from './pages/Foo.vue'
import Bar from './pages/Bar.vue'

Vue.use(VueRouter)

const routes: any = [{
    path: '/foo',
    component: Foo
  },
  {
    path: '/bar',
    component: Bar
  }
}]

const router = new VueRouter({
  mode: 'history',
  routes
})

export default router

ルーティングの定義の設定。
History モード 10にすることでURLがハッシュなしで設定できる。

web/resources/ts/pages/Foo.vue

Foo.vue
<template lang="pug">
  .foo
    h1 Foo
</template>

web/resources/ts/pages/Bar.vue

Bar.vue
<template lang="pug">
  .bar
    h1 Bar
</template>

web/routes/web.php

web.php
<?php

Route::get('/{any?}', function () {
    return view('index');
})->where('any', '.+');

web/resources/views/index.blade.php

index.blade.php
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>project_name</title>
    <script src="{{ mix('js/app.js') }}" defer></script>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.min.css">
  </head>
  <body>
    <div id="app"></div>
  </body>
</html>

web/vue-shim.d.ts

vue-shim.d.ts
declare module "*.vue" {
    import Vue from "vue";
    export default Vue;
}

Typescript: IDE reports TS2307: Cannot find module error for Vue components imports とエラーが出たので作成する。11

サーバーを起動

# php artisan serve --host 0.0.0.0 --port 80

ビルド

# npm run watch-poll

http://localhost:3000 にアクセスしてブラウザで確認する。

参考

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

Laravel 画像をアップロードして表示する

目的

  • アプリケーションに画像をアップロードして別画面で表示する方法をまとめる

環境

  • ハードウェア環境
項目 情報
OS macOS Catalina(10.15.3)
ハードウェア MacBook Pro (16-inch ,2019)
プロセッサ 2.6 GHz 6コアIntel Core i7
メモリ 16 GB 2667 MHz DDR4
グラフィックス AMD Radeon Pro 5300M 4 GB Intel UHD Graphics 630 1536 MB
  • ソフトウェア環境
項目 情報 備考
PHP バージョン 7.4.3 Homwbrewを用いて導入
Laravel バージョン 7.0.8 commposerを用いて導入
MySQLバージョン 8.0.19 for osx10.13 on x86_64 Homwbrewを用いて導入

事前情報

  • 下記の方法、またはそれに準ずる方法で認証機能のついたLaravelアプリが存在すること。
  • 既存のマイグレーションファイルがマイグレートされていること。
  • ログインユーザ毎に別々の画像のアップロードと表示をすることができる様に実装する。(他のログインユーザがアップロードした画像は表示されない)

概要

  1. テーブルの作成
  2. ルーティングの記載
  3. コントローラの記載
  4. ビューの記載
  5. 確認

詳細

  1. テーブルの作成

    1. アプリ名ディレクトリで下記コマンドを実行してモデルファイルとマイグレーションファイルを同時に作成する。

      $ php artisan make:model Image --migration;
      
    2. 下記にファイルが作成された事を確認する。

      • アプリ名ディレクトリ/app/Image.php
      • アプリ名ディレクトリ/database/migrations/YYYY_MM_DD_XXXXXX_create_images_table.php
    3. アプリ名ディレクトリで下記コマンドを実行してマイグレーションファイルを開く。

      $ vi database/migrations/YYYY_MM_DD_XXXXXX_create_images_table.php
      
    4. 開いたマイグレーションファイルを下記の様に記載する。

      アプリ名ディレクトリ/database/migrations/YYYY_MM_DD_XXXXXX_create_images_table.php
      <?php
      
      use Illuminate\Database\Migrations\Migration;
      use Illuminate\Database\Schema\Blueprint;
      use Illuminate\Support\Facades\Schema;
      
      class CreateImagesTable extends Migration
      {
          /**
           * Run the migrations.
           *
           * @return void
           */
          public function up()
          {
              Schema::create('images', function (Blueprint $table) {
                  $table->id();
                  //下記を追記する
                  $table->foreignId('user_id');
                  $table->string('file_name');
                  //上記までを追記する
                  $table->timestamps();
              });
          }
      
          /**
           * Reverse the migrations.
           *
           * @return void
           */
          public function down()
          {
              Schema::dropIfExists('images');
          }
      }
      
    5. アプリ名ディレクトリで下記コマンドを実行してマイグレーションを行う。

      $ php artisan migrate
      
  2. ルーティングの記載

    1. アプリ名ディレクトリで下記コマンドを実行してルーティングファイルを開く。

      $ vi routes/web.php
      
    2. 開いたルーティングファイルを下記の様に修正する。

      アプリ名ディレクトリ/routes/web.php
      <?php
      
      use Illuminate\Support\Facades\Route;
      
      /*
      |--------------------------------------------------------------------------
      | Web Routes
      |--------------------------------------------------------------------------
      |
      | Here is where you can register web routes for your application. These
      | routes are loaded by the RouteServiceProvider within a group which
      | contains the "web" middleware group. Now create something great!
      |
      */
      
      Route::get('/', function () {
          return view('welcome');
      });
      
      Auth::routes();
      
      Route::get('/home', 'HomeController@index')->name('home');
      
      //下記を追記
      //画像をアップロードするページ
      Route::get('/upload', 'ImageController@input');
      //画像を保存したり画像名をDBに格納する部分
      Route::post('/upload', 'ImageController@upload');
      //保存した画像を表示するページ
      Route::get('/output', 'ImageController@output');
      //上記までを追記
      
  3. コントローラの記載

    1. アプリ名ディレクトリで下記コマンドを実行してコントローラファイルを作成する。

      $ php artisan make:controller ImageController
      
    2. 下記のコントローラファイルが作成される。

      • アプリ名ディレクトリ/app/Http/Controllers/ImageCotroller.php
    3. アプリ名ディレクトリで下記コマンドを実行してコントローラファイルを開く。

      vi app/Http/Controllers/ImageCotroller.php
      
    4. 開いたコントローラファイルを下記の様に修正する。

      アプリ名ディレクトリ/app/Http/Controllers/ImageCotroller.php
      <?php
      
      namespace App\Http\Controllers;
      //下記を追加する
      use Illuminate\Support\Facades\Auth;
      use Illuminate\Http\Request;
      //下記を追加する
      use App\Image;
      
      class ImageController extends Controller
      {
          //下記を追加する
          public function input()
          {
              return view('image.input');
          }
      
          public function upload(Request $request)
          {
              $this->validate($request, [
                  'file' => [
                      // 必須
                      'required',
                      // アップロードされたファイルであること
                      'file',
                      // 画像ファイルであること
                      'image',
                      // MIMEタイプを指定
                      'mimes:jpeg,png',
                  ]
              ]);
      
              if ($request->file('file')->isValid([])) {
                  $path = $request->file->store('public');
      
                  $file_name = basename($path);
                  $user_id = Auth::id();
                  $new_image_data = new Image();
                  $new_image_data->user_id = $user_id;
                  $new_image_data->file_name = $file_name;
      
                  $new_image_data->save();
      
                  return redirect('/output');
              } else {
                  return redirect()
                      ->back()
                      ->withInput()
                      ->withErrors();
              }
          }
      
          public function output() {
              $user_id = Auth::id();
              $user_images = Image::whereUser_id($user_id)->get();
              return view('image.output', ['user_images' => $user_images]);
          }
          //上記までを追記
      }
      
  4. ビューの記載

    1. アプリ名ディレクトリで下記コマンドを実行してビューファイルを格納するディレクトリを作成する。

      $ mkdir resources/views/image
      
    2. アプリ名ディレクトリで下記コマンドを実行してビューファイルを作成する。

      $ touch resources/views/image/input.blade.php
      $ touch resources/views/image/output.blade.php
      
    3. アプリ名ディレクトリで下記コマンドを実行して画像をアップロードするビューファイルを開く。

      $ vi resources/views/image/input.blade.php
      
    4. 開いたビューファイルを下記の様に記載する。

      アプリ名ディレクトリ/resources/views/image/input.blade.php
      @extends('layouts.app')
      
      @section('content')
      <!-- エラーメッセージ。なければ表示しない -->
      @if ($errors->any())
      <ul>
          @foreach($errors->all() as $error)
          <li>{{ $error }}</li>
          @endforeach
      </ul>
      @endif
      
      <!-- フォーム -->
      <form action="/upload" method="POST" enctype="multipart/form-data">
          @csrf
      
          <label for="photo">画像ファイル:</label>
          <input type="file" class="form-control" name="file">
          <br>
          <input type="submit">
      </form>
      @endsection
      
    5. アプリ名ディレクトリで下記コマンドを実行して画像をアップロードするビューファイルを開く。

      $ vi resources/views/image/output.blade.php
      
    6. 開いたビューファイルを下記の様に記載する。

      アプリ名ディレクトリ/resources/views/image/output.blade.php
      @extends('layouts.app')
      
      @section('content')
          <a href="/upload">画像のアップロードに戻る</a>
          <br>
          @foreach ($user_images as $user_image)
              <img src="{{ asset('storage/' . $user_image['file_name']) }}">
              <br>
          @endforeach
      @endsection
      
  5. 確認

    1. アプリ名ディレクトリで下記コマンドを実行してローカルサーバを起動する。

      $ php artisan serve
      
    2. 下記にアクセスする。

    3. 画面右上の 「LOGIN」もしくは「REGISTER」からログインもしくは新規登録を行う。

      Laravel.png

    4. 下記にアクセスする。

    5. ブラウザ上で下記の様に表示される事を確認する。

      Laravel.png

    6. 「ファイルを選択」をクリックして任意の画像ファイルを開き、「送信」をクリックする。

    7. 下記の様に送信した画像が表示される事を確認する。

      Laravel.png

    8. 同アプリで現在ログインしているユーザとは別にユーザを作成しログインを行い、先とは違う画像をアップロードして先の画像とは別の画像表示される事を確認する。

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

Laravel areaやregionは予約語になっている?

POSTでデータを送る時に
nameにareaやregionを含んだものにすると
無視されることがあるのだが、なんでだろう。

要調査や。

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