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

Laravelでクラフトビールまとめサイト作ってみた。TechPitの教材をアレンジしました。

はじめに

プログラミング学習を初めて4か月がたちました。

最近、といってもかれこれ1か月弱前ですが、Laravelでのポートフォリオ作成を終えました。

せっかくなので、この記事で紹介させていただこうと思います。

CRAFTBERRS~アプリ紹介~


こんな感じのビールまとめサイトになっております。

・トップページ

・レビュー投稿ページ

・レビュー詳細ページ

・レビュー編集ページ

・プロフィールページ

・ユーザー一覧ページ(プロフィール画像のアップロード機能は未実装)

・検索機能(これはIPAで絞り込んだケース)

・エラーページ

・一応レスポンシブ対応

以下がリンクになります。

https://craftbeers.site/

作り終えた所感


細かいこと上げればキリがなく、改善できる部分も、本当であればユーザー編集機能や並び替え機能など実装したい機能もまだまだあります。

ただ、デプロイでひと段落させてしまったのがよくなかった。

やっぱり誰にも使われないサービスに時間割いても。。。って考えが付きまとってあまり改修する気にもならなくなってしまいました。泣

あと実は、Xserverにデプロイしているのですが、ローカル環境だとアクセスできるのに、本番環境だと編集・削除のページに飛べず、現状はエラーページにリダイレクトされてしまいます。ここら辺も未だに原因が正直掴めておらず。

教本や学習サイトでも、これ以上に踏み込んだ内容の教材が少なく、なかなか苦戦している状態です。(言い訳すみません。)

(英語での公式ドキュメントや動画学習などで、スキルアップしながら改修していくのがいいんだろうなとは思っています。)

おわりに


なんかネガティブな所感になってしまいましたが、とはいえ、LaravelでオリジナルのWebアプリを自作&デプロイまで持って行けたことは1つ自信に繋がりました。

今後は、引き続きLaravelの学習からのVue.jsなどのフロンドエンドフレームワークとの連携、またPythonでのデータ分析にも興味があるため、そっち方面の学習もしてみようかなと思っています。(高校・大学と音楽一筋でまともに英語や数学の勉強をしてこなかったことを今になって後悔してます。目指せ人生大逆転。笑)

あとは、誰かと共同してWebアプリ開発をしてみたいなとか妄想してます。求む同志!!笑
(実際、転職活動なり共同制作できたら未経験エンジニアにとって有利に働くんじゃないかなって思ってるので気になった方いましたらTwitterなりでご連絡ください(土下座)。そうじゃなくてもプログラミングスクール通ったりしたわけでもないので、エンジニア界隈の繋がりも少なく、気軽にお声がけいただけますと幸いです。泣いて喜びます(土下座)。)

拙い記事でしたが、読んでいただきましてありがとうございました。おしまい。

追記

このポートフォリオの参考にした教材は以下です。
TechPitはポートフォリオ制作にもってこいの学習サイトで、僕も愛用しております。ありがとうございました!!

Laravel6とAWSで作るブックレビューサイト
https://www.techpit.jp/p/laravel6-aws


Techpit(学び放題コースだと月額2980円でいろいろ作れちゃいます◎)
https://www.techpit.jp/courses/
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravelでクラフトビールまとめサイト作ってみた。

はじめに

プログラミング学習を初めて4か月がたちました。

最近、といってもかれこれ1か月弱前ですが、Laravelでのポートフォリオ作成を終えました。

せっかくなので、この記事で紹介させていただこうと思います。

CRAFTBERRS~アプリ紹介~


こんな感じのビールまとめサイトになっております。

・トップページ

・レビュー投稿ページ

・レビュー詳細ページ

・レビュー編集ページ

・プロフィールページ

・ユーザー一覧ページ(プロフィール画像のアップロード機能は未実装)

・検索機能(これはIPAで絞り込んだケース)

・エラーページ

・一応レスポンシブ対応

以下がリンクになります。

https://craftbeers.site/

作り終えた所感


細かいこと上げればキリがなく、改善できる部分も、本当であればユーザー編集機能や並び替え機能など実装したい機能もまだまだあります。

ただ、デプロイでひと段落させてしまったのがよくなかった。

やっぱり誰にも使われないサービスに時間割いても。。。って考えが付きまとってあまり改修する気にもならなくなってしまいました。泣

あと実は、Xserverにデプロイしているのですが、ローカル環境だとアクセスできるのに、本番環境だと編集・削除のページに飛べず、現状はエラーページにリダイレクトされてしまいます。ここら辺も未だに原因が正直掴めておらず。

教本や学習サイトでも、これ以上に踏み込んだ内容の教材が少なく、なかなか苦戦している状態です。(言い訳すみません。)

(英語での公式ドキュメントや動画学習などで、スキルアップしながら改修していくのがいいんだろうなとは思っています。)

おわりに


なんかネガティブな所感になってしまいましたが、とはいえ、LaravelでオリジナルのWebアプリを自作&デプロイまで持って行けたことは1つ自信に繋がりました。

今後は、引き続きLaravelの学習からのVue.jsなどのフロンドエンドフレームワークとの連携、またPythonでのデータ分析にも興味があるため、そっち方面の学習もしてみようかなと思っています。(高校・大学と音楽一筋でまともに英語や数学の勉強をしてこなかったことを今になって後悔してます。目指せ人生大逆転。笑)

あとは、誰かと共同してWebアプリ開発をしてみたいなとか妄想してます。求む同志!!笑
(実際、転職活動なり共同制作できたら未経験エンジニアにとって有利に働くんじゃないかなって思ってるので気になった方いましたらTwitterなりでご連絡ください(土下座)。そうじゃなくてもプログラミングスクール通ったりしたわけでもないので、エンジニア界隈の繋がりも少なく、気軽にお声がけいただけますと幸いです。泣いて喜びます(土下座)。)

拙い記事でしたが、読んでいただきましてありがとうございました。おしまい。

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

DDD的なLaravelで実装するブログCMS#1

目的

昔はよくやってたのに最近ブログとかQiitaでアウトプットしてないなぁと思ったのでアウトプットしたいと思います。
お題はドメイン駆動設計です。
これからのアウトプットの拠点としたいブログ型CMS構築を進めていく形式で具体的なコード一緒に考え方を書いていきたいと思います。
DDDそのものについての説明はweb上にたくさん資料があるので省きまして、実際に実装に落とす時にどうするかという点で誰かの参考になれば良いなという感じで書いていきます。

DB設計

DDDとはあまり関係が無いですが、DB設計する時にはまずはパクれる(参考にできる)設計が無いか、ということ考えるようにしています。
今回ならブログなのでwordpressのDB設計が参考になります。
自分で考えてると0から色んなこと考えなきゃいけなくてめんどくさいので、基本的にはつくりたいものに近いもので有名なオープンソースを探して参考にすると良いです。

データベース構造 - WordPress Codex 日本語版

postsテーブル、commentsテーブルをつくる

↑の設計を参考に必要なカラムだけ定義します。
そんなたくさんデータ入らないためインデックスは省略します。

$ php artisan make:migration create_posts_table --create=posts
create_posts_table.php
    public function up()
    {
        Schema::create('posts', function (Blueprint $table) {
            $table
                ->bigIncrements('id')
                ->unsigned()
                ->comment('投稿ID(保存順に自動採番)');
            $table
                ->string('post_name', 200)
                ->comment('投稿スラッグ');
            $table
                ->string('post_title', 200)
                ->comment('タイトル');
            $table
                ->longText('post_content')
                ->comment('本文');
            $table
                ->string('post_status', 20)
                ->default('publish')
                ->comment('publish: 公開 private: 非公開');
            $table
                ->string('post_type', 20)
                ->default('post')
                ->comment('post: 投稿 page: ページ');
            $table
                ->dateTime('post_date')
                ->comment('投稿日時');
            $table
                ->dateTime('post_modified')
                ->comment('更新日時');
        });
    }
create_comments_table.php
    public function up()
    {
        Schema::create('comments', function (Blueprint $table) {
            $table
                ->bigIncrements('comment_id')
                ->unsigned()
                ->comment('コメントID(投稿順に自動採番)');

            $table
                ->unsignedBigInteger('comment_post_id')
                ->comment('コメントが属する投稿ID');
            $table
                ->foreign('comment_post_id')
                ->references('id')
                ->on('posts');

            $table
                ->ipAddress('comment_author_ip')
                ->comment('コメント投稿者の IPアドレス');

            $table
                ->longText('comment_content')
                ->comment('コメント内容');

            $table
                ->string('comment_agent', 255)
                ->comment('コメント投稿者のユーザエージェント');

            $table
                ->dateTime('comment_date')
                ->comment('コメント投稿日時');
        });
    }
$ php artisan migrate

スクリーンショット 2020-03-08 18.18.00.png

出来ました。

実装

独自に切り出したディレクトリ配下に実装を入れていきます。

スクリーンショット 2020-03-08 19.07.07.png

フレームワークのコードと自分のコードが混らないようにしてつくっていきます。
考え方としてはフレームワークを土台としてその上に乗って開発してしまうのではなく、しっかりフレームワークと分離した場所に展開する自分のコードの中から必要な時にフレームワークのリソースを活用していく感じです。(Laravelはこれがやりやすいです)

レイヤードアーキテクチャ

レイヤードアーキテクチャをめちゃくちゃ雑に説明するとこんな感じで層を分けてドメインをくっきりさせるということをやる分け方です。上は下に依存していいけど下は上に依存しないようにします。

  • UserInterface: ユーザに情報を表示するところ。ユーザや外部システムの入力を解釈する責任をもつ。
  • Application: ソフトウェアが行うことになっている仕事を定義するところ。ここにはいっぱいコード書かない。やるべきことを調整するだけ。
  • Domain: ビジネスの概念が集中するとか言われてもピンとこないやつ。上手にDDDできてるとここの中に置くモデルにそのアプリケーション特有の仕様がギュッと集まって幸せになれる。
  • Infrastructure:DBとやりとりしてドメインモデルを永続化したり、取り出したデータをドメインモデルに変換して返したりするところ。

上からいった方がイメージしやすいんじゃないか説があるので上からいきます。

ユーザインターフェイス層

ユーザに情報を表示したり入力を解釈したりするやつ。
Laravelでviewファイルはデフォルトではresources/views/配下に置きますが、config/view.phpで変更できます。
この層でif文が多いとロジックが漏れ出してます。
テンプレートをいじるHTMLコーダーにとってわかりやすくていじりやすくなってれば良い状態と言えるでしょう。

例えば↓こんな感じです

bad.php
<p>
@if($user->gender == 'men')
  私は男です
@elseif($user->gender == 'women')
  私は女です
@endif
</p>
good.php
<p>{{ $user->sayGender() }}</p>

前者はviewにロジックが書いてありますが後者ではロジックがUserモデルのsayGender関数に隠れてます。
後者の方がフロント係が触りやすいですね。

以下、初期設定〜投稿フォームの実装です。

composer.json
...
   "autoload": {
        "psr-4": {
            "App\\": "app/",
            "Blog\\": "packages/Blog/"
        },
...
config/view.php
...
    'paths' => [
//        resource_path('views'),
        base_path('packages/Blog/UserInterface/Blade'),
    ],
...
app/Providers/RouteServiceProvider.php
...
    protected $namespace = 'Blog\Application\Http\Controllers';
...
    protected function mapWebRoutes()
    {
        Route::middleware('web')
             ->namespace($this->namespace)
             ->group(base_path('packages/Blog/UserInterface/Routes/web.php'));
    }
...

そういえば認証つけないと誰でも投稿できるんですが、一旦気にしないことにします。
(次回以降のお題としたいと思います)

スクリーンショット 2020-03-08 21.02.15.png

web.php
<?php

use Illuminate\Support\Facades\Route;

Route::prefix('blog')->group(function () {
    Route::resource('posts', 'PostController');
});

スクリーンショット 2020-03-14 14.50.57.png

スクリーンショット 2020-03-08 21.20.50.png

アプリケーション層

この層は「どんな仕事をするのかだけ書いて薄くシンプルに保つ」を気をつけて書きましょう。
「誰が」「何を」するのか主語述語をハッキリとわかりやすく表現したシングルメソッドのUseCaseクラスを書き、入出力のインターフェイスとしてValueObjectを利用します。

PostController.php
<?php
namespace Blog\Application\Http\Controllers;

use Blog\Application\UseCase\AuthorPublishPost;
use Blog\Application\UseCase\UserGetNewPosts;
use Blog\Domain\Object\Post\PostContent;
use Blog\Domain\Object\Post\PostName;
use Blog\Domain\Object\Post\PostTitle;
use Illuminate\Http\Request;

class PostController extends BlogController
{
    public function create()
    {
        return view('Post.create');
    }

    public function index(UserGetNewPosts $userGetNewPosts)
    {
        $posts = ($userGetNewPosts)();
        return view('Post.index', compact('posts'));
    }

    public function store(Request $request, AuthorPublishPost $authorPublishPost)
    {
        $name = PostName::of($request->input('name'));
        $title = PostTitle::of($request->input('title'));
        $content = PostContent::of($request->input('content'));
        ($authorPublishPost)($name, $title, $content);
        return redirect()->route('posts.index');
    }
}
UserGetNewPosts.php
<?php


namespace Blog\Application\UseCase;


use Blog\Infrastructure\Repositories\PostRepository;

class UserGetNewPosts
{
    /** @var PostRepository */
    private $postRepo;

    public function __construct(PostRepository $postRepo)
    {
        $this->postRepo = $postRepo;
    }

    public function __invoke()
    {
        $posts = $this->postRepo->all();
        return $posts;
    }
}

油断するとバリデーション処理とかレスポンスつくる処理だけでも結構行数増えてしまうところです。
今はやりませんが投稿処理にバリデーションを付けたくなったらFormRequestを継承したPostFormRequestを実装してその中でバリデーションやらを処理します。

何でもかんでもUseCaseとかServiceクラスとして実装してカオスと化したクラス墓場みたいなのよく見ますが、そうはならないようにしましょう。
実装したいものの役割、責任をしっかりイメージしてどこに何を置いてどんな仕事をさせるのか。
これをしっかり考えて整理していけば自然とドメイン層に重要な情報が集中して書けば書くほど後の実装が楽になっていきます。

ドメイン層

↑で実行していたValueObjectの生成とPostEntityの生成について。
EntityもValueObjectも原則constructerをprivateにして守り、どこでも自由にインスタンス生成されるのを防ぎます。

こんな感じ。

PostName.php
<?php
namespace Blog\Domain\Object\Post;

use Blog\Domain\Exceptions\TooLongStringException;
use Blog\Domain\Object\ValueObject;

final class PostName extends ValueObject
{
    /** @var string */
    protected $value;
    /** @var int  */
    private const MAX_STRING_NUM = 200;

    private function __construct() {}

    /**
     * @param string $name
     * @return PostName
     * @throws TooLongStringException
     */
    public static function of(string $name):PostName
    {
        if (self::MAX_STRING_NUM < mb_strlen($name)) {
            throw new TooLongStringException();
        }
        $postName = new PostName();
        $postName->value = $name;
        return $postName;
    }
}

↑PostNameという値の仕様がクラスで表現されています。

MVC的な文脈で言われるFatControllerやFatModel(Fat=コード量多い)の問題って大体適当にサービスクラス増やしたりして結局どっかがしわ寄せ食らって終わるみたいなイメージがありますが、DDDでは

  • ControllerはHTTPリクエスト検査し、ValueObjectを作成して適切なUseCase,Serviceに渡し得た値をレスポンスするだけ
  • ModelはModel本来の仕様に集中し、値の仕様はValueObjectに逃し、データのIOはRepositoryが行う

↑こうするのでControllerもModelも太らずにすみます。
全ての値をValueObjectにする必要は無いと思いますが、Modelが本質的な仕様の実装に集中するために非常に重要な手段なのでめんどくさがらずに丁寧に実装することをおすすめします。

AuthorPublishPost.php
<?php
namespace Blog\Application\UseCase;

use Blog\Domain\Object\Post\PostContent;
use Blog\Domain\Object\Post\PostEntity;
use Blog\Domain\Object\Post\PostName;
use Blog\Domain\Object\Post\PostTitle;
use Blog\Infrastructure\Repositories\PostRepository;

class AuthorPublishPost
{
    /** @var PostRepository */
    private $postRepo;

    public function __construct(PostRepository $postRepo)
    {
        $this->postRepo = $postRepo;
    }

    public function __invoke(PostName $postName, PostTitle $postTitle, PostContent $postContent)
    {
        $postEntity = PostEntity::newPost($postName, $postTitle, $postContent);
        $this->postRepo->store($postEntity);
    }
}

PostEntity.php
<?php
namespace Blog\Domain\Object\Post;

final class PostEntity
{
    /** @var PostId */
    private $id;
    /** @var PostName */
    private $postName;
    /** @var PostTitle */
    private $postTitle;
    /** @var PostContent */
    private $postContent;
    /** @var PostStatus */
    private $postStatus;
    /** @var PostType */
    private $postType;
    /** @var PostDate */
    private $postDate;
    /** @var PostModified */
    private $postModified;

    private function __construct() {}

    public static function of
    (
        PostId $postId,
        PostName $postName,
        PostTitle $postTitle,
        PostContent $postContent,
        PostStatus $postStatus,
        PostType $postType,
        PostDate $postDate,
        PostModified $postModified
    ):PostEntity
    {
        $postEntity = new PostEntity();
        $postEntity->id = $postId;
        $postEntity->postName = $postName;
        $postEntity->postTitle = $postTitle;
        $postEntity->postContent = $postContent;
        $postEntity->postStatus = $postStatus;
        $postEntity->postType = $postType;
        $postEntity->postDate = $postDate;
        $postEntity->postModified = $postModified;
        return $postEntity;
    }

    public static function newPost(PostName $postName, PostTitle $postTitle, PostContent $postContent):PostEntity
    {
        $postEntity = new PostEntity();
        $postEntity->postName = $postName;
        $postEntity->postTitle = $postTitle;
        $postEntity->postContent = $postContent;
        return $postEntity;
    }

    public function id():PostId
    {
        return $this->id;
    }

    public function postName():PostName
    {
        return $this->postName;
    }

    public function postTitle():PostTitle
    {
        return $this->postTitle;
    }

    public function postContent():PostContent
    {
        return $this->postContent;
    }
}

インフラ層

上位のレイヤを支える一般的な技術的機能を提供する

とエバンス本には書いてあります。
つまりドメインモデルをインスタンス化するためにストレージからデータを取り出したり、逆にアプリケーションの実行するユースケースがEntityに対して加えた状態変化をストレージで永続化したりする時に利用する一般的な技術的機能についての実装がここに入るということで、MySQLやRedisなどのIOを実装します。

ここで複雑な実装が入ってしまうとドメインが扱うべきビジネスロジックが漏れてるってことになるので良くないみたいに言われています。

1つのEntityを表現したい時にテーブル設計にもよりますがjoinしたい時はままあるのでjoinは許容して良いと思います。
ただ値に関してcaseやif、REPLACEで値を置き換えてしまうような処理は、あとで変えたくなった時のことを考えるとValueObjectなどで吸収した方が変更コストが少なくて幸せそうです。

PostRepository.php
<?php
namespace Blog\Infrastructure\Repositories;

use Blog\Domain\Object\Post\PostContent;
use Blog\Domain\Object\Post\PostDate;
use Blog\Domain\Object\Post\PostEntity;
use Blog\Domain\Object\Post\PostId;
use Blog\Domain\Object\Post\PostModified;
use Blog\Domain\Object\Post\PostName;
use Blog\Domain\Object\Post\PostStatus;
use Blog\Domain\Object\Post\PostTitle;
use Blog\Domain\Object\Post\PostType;
use Blog\Infrastructure\Eloquents\PostEloquent;
use Illuminate\Support\Collection;

class PostRepository
{
    /** @var PostEloquent */
    private $postElo;

    public function __construct(PostEloquent $postElo)
    {
        $this->postElo = $postElo;
    }

    public function store(PostEntity $postEntity)
    {
        $postElo = new PostEloquent();
        $postElo->post_name = $postEntity->postName();
        $postElo->post_title = $postEntity->postTitle();
        $postElo->post_content = $postEntity->postContent();
        $postElo->save();
    }

    public function all():Collection
    {
        $posts = $this->postElo::query()
            ->orderByDesc('post_date')
            ->get()
            ->map(function($post){
                return PostEntity::of(
                    PostId::of($post->id),
                    PostName::of($post->post_name),
                    PostTitle::of($post->post_title),
                    PostContent::of($post->post_content),
                    PostStatus::of($post->post_status),
                    PostType::of($post->post_type),
                    PostDate::of($post->post_date),
                    PostModified::of($post->post_modified)
                );
            });
        return $posts;
    }
}

投稿一覧の実装

UserInterface層に戻って、リポジトリから取り出したEntityで投稿一覧を実装します。

テストデータ欲しい

SeederとFactoryを使ってテストデータを生成します。

https://readouble.com/laravel/7.x/ja/seeding.html

$ php artisan make:seeder PostsTableSeeder
PostsTableSeeder.php
<?php

use Illuminate\Database\Seeder;
use Blog\Infrastructure\Eloquents\PostEloquent;

class PostsTableSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        factory(PostEloquent::class, 50)->create();
    }
}
PostFactory.php
<?php

/** @var \Illuminate\Database\Eloquent\Factory $factory */

use Blog\Infrastructure\Eloquents\PostEloquent;
use Faker\Generator as Faker;

/*
|--------------------------------------------------------------------------
| Model Factories
|--------------------------------------------------------------------------
|
| This directory should contain each of the model factory definitions for
| your application. Factories provide a convenient way to generate new
| model instances for testing / seeding your application's database.
|
*/

$factory->define(PostEloquent::class, function (Faker $faker) {
    return [
        'post_name' => $faker->slug,
        'post_title' => $faker->title,
        'post_content' => $faker->realText(),
    ];
});
$ composer dump-autoload
$ php artisan db:seed --class=PostsTableSeeder

スクリーンショット 2020-03-09 23.29.05.png

入りました。

投稿一覧HTML↓
スクリーンショット 2020-03-14 14.49.27.png

Post/index.php
@extends('Layouts.blog')

@section('content')
    <div class="uk-grid" data-ukgrid>
        <div class="uk-width-2-3@m">
            <h4 class="uk-heading-line uk-text-bold"><span>Latest Posts</span></h4>
            @foreach($posts as $post)
                <article class="uk-section uk-section-small uk-padding-remove-top">
                    <header>
                        <h2 class="uk-margin-remove-adjacent uk-text-bold uk-margin-small-bottom">
                            <a title="Fusce facilisis tempus magna ac dignissim." class="uk-link-reset" href="#">
                                {{ $post->postName() }}
                            </a>
                        </h2>
                        <p class="uk-article-meta">Written on {{ $post->postDate()->diff() }}</p>
                    </header>
                    <p>{{ $post->postContent() }}</p>
                    <a href="#" title="Read More" class="uk-button uk-button-default uk-button-small">READ MORE</a>
                    <hr>
                </article>
            @endforeach
        </div>
        <div class="uk-width-1-3@m">
            <h4 class="uk-heading-line uk-text-bold"><span>About</span></h4>
            <div class="uk-tile uk-tile-small uk-tile-muted uk-border-rounded">
                Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
                tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
                quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
                consequat. Duis aute irure dolor in.
            </div>
        </div>
    </div>
@endsection

投稿個別ページの実装

マークダウンで投稿したいのでライブラリ調べました。

そしたら↓コレ

Laravel: There is a Markdown parser and you don’t know it

Laravelにはマークダウンパーサーがあるのに知られてない

だって、マークダウンでEmailを書けるじゃん!

確かに。
ということでインストールする必要ないので実装していきます。

PostContent.php
<?php


namespace Blog\Domain\Object\Post;


use Blog\Domain\Object\ValueObject;
use Illuminate\Mail\Markdown;

final class PostContent extends ValueObject
{
    /** @var PostContent */
    protected $value;

    public static function of(string $content): PostContent
    {
        $postContent = new PostContent();
        $postContent->value = $content;
        return $postContent;
    }

    public function __toString():string
    {
        return Markdown::parse($this->value)->toHtml();
    }
}

↑の記事の内容と少し違いますが、コード読んだらコレで十分なのがわかったのでコレでいきます。

PostContentのValueObjectに実装しました。
普通にEloquentをモデルとして実装してるとこの実装はPostEloquentに入ることになると思うのですが、ValueObjectで実装しているとMarkdownクラスを誰が必要としているのか(ないし依存しているのか)が明確になります。
その分、PostEntityは記述が減って、自身が複数もつValueObjectの集合でしか表現できないより重要な仕様を表現することに集中することができます。

## h2だよ

>引用だよ

- リスト
- リスト
- リスト

### h3だよ

うぎゃああああああああ

スクリーンショット 2020-03-14 19.51.33.png

リリース

DDD関係ないけどherokuにデプロイしてドメイン当てて公開するとこまでやりたいと思います。

Getting Started with Laravel on Heroku

Laravelはログファイルをstorageディレクトリの下に吐くんですが、herokuは仕様的にデプロイしたアプリケーションがファイルシステムへ書き込めないようになっているのでその辺の設定を書き換える必要があります。

config/logging.php
<?php
return [
    'default' => env('LOG_CHANNEL', 'stack'),
    'channels' => [
        'stack' => [
            'driver' => 'stack',
            'channels' => ['single'],
        ],
        'single' => [
            'driver' => 'errorlog',
            'level' => 'debug',
        ],

MySQL設定

$ heroku addons:create cleardb:ignite
$ heroku config:get CLEARDB_DATABASE_URL
mysql://****
$ heroku config:set \
DB_CONNECTION=mysql \
DB_HOST=**** \
DB_DATABASE=**** \
DB_USERNAME=**** \
DB_PASSWORD=**** \
$ heroku run php artisan migrate

Custom Domain

参考資料
https://medium.com/@david.gagne/set-up-a-custom-domain-for-your-heroku-application-using-google-domains-guaranteed-a2b2ff934f97

完成

https://www.ta9to.com/blog/posts

おわり

コードも書いて文章も書いてリリースまでできて満足です。
2020年はアウトプットするぞー!

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

Laravelでテストしてみる

概要

前回作った環境をテストする

環境

Laravel 7.0.8
Valet 2.8.1

Laravelの構造

テストをする前に前回のおさらいを踏まえて、構造を整理

MVC

Model、View、Controllerにプログラムの役割を分割した設計手法を採用

 Model
  データ処理全般、DBとの受け渡し:app/

 View
  ユーザーインターフェス、画面関連:resources/views/

 Controller
  全体の制御、モデルとビューをコントロール:app/Http/Controllers/

MVCのフォルダだけを表示すると、

.
├── app
│   └── Http
│      └── app/Http/Controllers
└── resources
    └── views

ただし、Modelについては、どのフォルダに配置してもよい

modelsディレクトリはどこにある?

Laravelを学習し始めるとき、多くの開発者はmodelsディレクトリが存在しないことに戸惑います。しかし、意図的にこのディレクトリを用意していません。多くの別々の人達にとって、その意味合いはさまざまなため、"models"という言葉の定義は曖昧であることに私達は気づきました。ある開発者たちはすべてのビジネスロジックを総称してアプリケーションの「モデル」と呼び、一方で別の人達はリレーショナルデータベースに関連するクラスを「モデル」として参照しています。
このため、私達はEloquentモデルをデフォルトではappディレクトリ下へ設置することを選択し、開発者自分が選んだどこか別の場所へ設置してもらうことにしました

https://readouble.com/laravel/6.x/ja/structure.html

Webサイトを開いてからの処理の流れは、ざっと以下の流れ

ユーザーからのリクエスト
 │
ルーティング
 │
コントローラー
 │
 ├── ビュー 
 │
モデル
 │
データベース

詳しくてわかりやすい解説は https://miyabi-lab.space/blog/22

前回は、モデルは触らずに使わずにルーティングで設定したコントローラーからビューを表示させた。今回は、モデルからデータベースの読み書きを行う。

====
MVC参考
https://www.ritolab.com/entry/48
====

テストもご一緒に

テストは先に書いてもいいし後でもいいけれど、テストも書きながら、
サイト作りを進めます。

PHPUnit

Laravelに用意されているテスト用フレームワークPHPUnitを使います。

.
└── tests
    ├── Feature
    │   └── ExampleTest.php
    └── Unit
        └── ExampleTest.php|    

テストには一つのメソッドを対象とするユニットテストと、コードを広く対象とした機能(Feature)テストがあります。testsディレクトリにそれぞれのディレクトリがあり、サンプルがあるので見てみると、

ExampleTest.php
<?php

namespace Tests\Feature;

use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class ExampleTest extends TestCase
{
    /**
     * A basic test example.
     *
     * @return void
     */
    public function testBasicTest()
    {
        $response = $this->get('/');

        $response->assertStatus(200);
    }
}

これを流用できそうですが、artisan コマンドでテストが作れるので試します。

$ php artisan make:test UserTest
Test created successfully.

中身はサンプルとほぼ一緒でした。

UserTest.php
<?php

namespace Tests\Feature;

use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Tests\TestCase;

class UserTest extends TestCase
{
    /**
     * A basic feature test example.
     *
     * @return void
     */
    public function testExample()
    {
        $response = $this->get('/');

        $response->assertStatus(200);
    }
}

これを以下を満たすように変更します。

 サイトが正常に表示:
  HTTP レスポンスステータスコードが200
  画面に「Hello World」の文字列がある

UserTest.php
//del
    public function testExample()
    {
        $response = $this->get('/');

//add
    public function testRespose()
    {
        $response = $this->get('/user');

    public function testText()
    {
        $text = $this->get('/user');

        $text->assertSeeText("Hello World");
    }

で早速実行してみる

$ php vendor/bin/phpunit tests/Feature/UserTest.php 
PHPUnit 8.5.2 by Sebastian Bergmann and contributors.

..                                                                  2 / 2 (100%)

Time: 788 ms, Memory: 18.00 MB

OK (2 tests, 2 assertions)

OKを確認。2つのテストで2つの検証が成功したという意味。ちなみにテストが失敗すると

DIR/blog/vendor/laravel/framework/src/Illuminate/Testing/TestResponse.php:432
DIR/blog/tests/Feature/UserTest.php:27

FAILURES!
Tests: 2, Assertions: 2, Failures: 2.

参考
https://readouble.com/laravel/6.x/ja/testing.html

次回は、データベースを使う簡単なサイトを作ります。

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

【Laradock環境構築】Dockerインストール〜Laravelデフォルトページ表示まで②

はじめに

こちらの記事では、Laradockの環境構築として、
Dockerのインストール〜Laravelのデフォルトページ表示までを載せていきます。
※本記事はパート①の続きになります。

【Laradock環境構築】Dockerインストール〜Laravelデフォルトページ表示まで①
https://qiita.com/y-aimi/items/4fc3c65f85a103685238

前提条件

パート①でDockerのインストールが終わっている状態

プロジェクト用のディレクトリを作成

開発するアプリケーション用のディレクトリを作成します。

本記事ではecsiteとします。

以下のコマンドを実行。

//mkdirでディレクトリを作成。cdでecsiteのディレクトリに移動
$ mkdir ecsite
$ cd ecsite

ちなみに、どこでこのコマンドを実行すればいいの?という方は、

// ~ はルートディレクトリを表している
$ cd ~

でルートディレクトに移動すれば、下記の場所にecsiteというフォルダができるので
そちらで問題ないかと思います。

image.png

リポジトリのクローンを作成

LaradockのGithubのリポジトリをクローンします。
クローンしたらlaradockディレクトリに移動します。

以下のコマンドを実行。

$ git clone https://github.com/Laradock/laradock.git
$ cd laradock

試しに、
https://github.com/Laradock/laradock.git
をクリックしてGithubを見てみてください。

ここのクローンを先程作ったecsiteのディレクトリに作っているよー
ということですね!
そして、そのディレクトリに移動したということです。

Laradockの設定ファイル準備

Laradockのenv-example.envとしてコピーします。

/ecsite/laradock/で以下のコマンドを実行してください。

$ cp env-example .env

(cp はコピーという意味です。まんまですね。)

以下のコマンドを実行し、/ecsite/laradock/直下に.envファイルがあることを確認。

$ ls

次に作成した.envファイルをVimを使って編集していきます。
(Vimを使えば、いちいちフォルダを探して、ファイルを探して開いて編集・・・
をしなくてもターミナル上で編集できるのでラクです!)

/ecsite/laradock/で以下のコマンドを実行。

$ vi .env

するとターミナルでこんな画面がでます。

image.png

この画面は/ecsite/laradock/.envの編集画面です。

この画面上で i を押します。

image.png

下部に-- INSERT --と編集できるモードに切り替わるので、
この状態でファイルを編集していきます。

/ecsite/laradock/.envを以下のように編集してください。

### Paths #################################################

# Point to the path of your applications code on your host

# 次の行を編集
APP_CODE_PATH_HOST=../ecsite

# Point to where the `APP_CODE_PATH_HOST` should be in the container
APP_CODE_PATH_CONTAINER=/var/www

APP_CODE_PATH_HOSTの値が、
Laradockで動かすウェブアプリのディレクトリのパスになります。
(つまり、Laradockで動かす時にどのフォルダを使うの?それの場所をここに書いてね。ということです。)

次にescキーを押してコマンドモードに移行し、:wqを押し、
enterキーでファイルへの変更を保存し終了。
(":w"は保存、"q"は終了のVimコマンド→合わせて":wq"コマンドというわけですね)

次にウェブアプリのディレクトリを作っておきます。

以下のコマンドを実行。

$ mkdir ../ecsite

これで、現在のディレクトリは下記のようになっているかと思います。

ecsite
├── ecsite ←今作ったウェブアプリ用のディレクトリ
└── laradock ←序盤にクローンしたlaradock.gitのクローン

mysqlの認証方法の設定

mysqlのバージョンによっては、認証方法がデフォルトでは
なくなってしまっていることがあるので、
※変更の必要ない人は必要ないです。
(ちなみに私も変更しなくても良かったです。)

/ecsite/laradock/ディレクトリ内で以下のコマンドを実行し、vimを起動。

$ vi mysql/my.cnf

先程と同じように、iを押してINSERTモードに切り替え、
/ecsite/laradock/mysql/my.cnfを以下のように編集。

# The MySQL  Client configuration file.
# 
# For explanations see
# http://dev.mysql.com/doc/mysql/en/server-system-variables.html

[mysql]

[mysqld]
sql-mode="STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION"
character-set-server=utf8

# この行を追加(この文が元々ある人もいるかも?)
default_authentication_plugin=mysql_native_password

escキーを押してコマンドモードに移行し、
:wqを入力しenterキーでファイルの変更を保存し終了。

これでmysqlの準備は終了です。

Laradockのコンテナ起動

Laradockを使ってあらかじめ用意されている、
ウェブサーバー(nginx)とデータベースサーバー(mysql)のコンテナを起動します。

/ecsite/laradock/ディレクトリ内で以下のコマンドを実行します。

$ docker-compose up -d nginx mysql

そして、下記のように全部"done"になれば無事起動されています。

image.png

これで、ローカルのウェブサーバーとデータベースが起動しました!

workspaceコンテナのパッケージアップデート

つぎにworkspaceコンテナに入り、パッケージのアップデートをしておきます。

workspaceコンテナは開発に必要なツール等がインストールされているコンテナらしいです。
(Laradockのコンテナを起動すると自動的にworkspaceコンテナも起動します)

以下のコマンドでパッケージをアップデート。

$ docker exec -it laradock_workspace_1 bash
root@hoge:/var/www# apt-get update

(root@hogeの"hoge"は個人で違うかと思います。)

Laravelのセットアップ

最後にlaravelのセットアップをします。
workspaceコンテナに入ったまま、Laravelをインストール。

//こちらを参考にプロジェクト名を入れて実行
root@hoge:/var/www# composer create-project laravel/laravel [プロジェクト名]

//実例①
root@hoge:/var/www# composer create-project laravel/laravel ECsite

//実例②:laravelのバージョンを指定する際はこちらを参考に
root@hoge:/var/www# composer create-project laravel/laravel ECsite "5.8.*"

動作確認

下記のURLでLaravelのデフォルトページが表示されれば環境構築成功です!

http://localhost/

image.png

エラー多発した!!

この環境構築、個人個人によって色んなエラーが出ることが多いです。
(エラーで苦戦して、やっぱLaradock使うのやめよう...と思った人もいるはず)

ちなみに、個人的にあるあるなのが、
Nginx 404not found
でデフォルトページが表示されないエラー。

image.png

おそらく原因は、/ecsite/laradock/.envで編集したこちらが正しくない可能性が高いです。
例えば、ディレクトリの構成を変えていたり、置く場所を変えていたりすると、
ここも変えなければいけません。

重要!

あ、エラーになってしまった!

よし、これを修正したら大丈夫なはず!!

...え、また同じエラー??

...え、しかも何かエラー増えてる?

.........わからん。

............オワタ。詰んだ。

となった方いませんか?
僕がまさにこの状態になって抜け出せなかったので、対処法を!!

以下のコマンドで、コンテナを再起動!!

$ docker-compose stop
$ docker-compose up -d nginx mysql

そしたら、エラー解消しました。
エラー箇所を正しく修正したとしても、再起動しないとエラーのままだったりするので、
困ったら再起動してみましょう。
それでもエラーが出るなら、何か修正点があるかと思いますので、
ボス戦の攻略法を探すような感じで、ググりましょう!

まとめ

環境構築って一番の壁だと思います。

わからないことだらけですし、これができないとその後の開発が何もできないし...

でも、個人的にはこの環境構築に苦戦して乗り越えると、
ただ開発するだけでは得られない知識が得られるので、
良い経験ができているなーと感じてます。

開発中のエラーがボス戦だとしたら、
環境構築のエラーはシークレットボス戦みたいな感じですかね!笑

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

Laravelのサービスプロバイダのキャッシュについてのエラー

作成したサービスプロバイダを削除した際にエラーが出る。

状況

FormComponentServiceProviderというサービスプロバイダを作成し、config/app.phpへ追加した後、不要になったため削除。

下記エラーが出る。

In ProviderRepository.php line 208:

  Class 'App\Providers\FormComponentServiceProvider' not found

config/app.phpでの定義を削除し、キャッシュクリアしてみるが同様のエラーが出る。

$ php artisan config:cache

In Application.php line 670:

  Class 'App\Providers\FormComponentServiceProvider' not found

原因・対処

bootstrap/cache/にキャッシュが残っていたため。

それらを削除し、composer dump-autoloadを行うことで解決。

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

DB::select で作られる中途半端な Array を完全な Array にする

DB::select を使ったときは以下ように、配列の中にオブジェクトが存在します。

>>> $a = DB::select("select id, name from companies limit 2");
=> [
     {#4090
       +"id": 1,
       +"name": "Hoge",
     },
     {#4091
       +"id": 2,
       +"name": "Piyo",
     },
   ]

これを完全な配列にする方法は2つあります。

方法1

>>> json_decode(json_encode($a), true);
=> [
     [
       "id" => 1,
       "name" => "Hoge",
     ],
     [
       "id" => 2,
       "name" => "Piyo",
     ],
   ]

方法2

>>> foreach($a as &$v){$v = collect($v)->toArray();}
>>> $a;
=> [
     [
       "id" => 1,
       "name" => "Hoge",
     ],
     [
       "id" => 2,
       "name" => "Piyo",
     ],
   ]

以上です。

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

【初心者向け】Laravelのデータベース設定でつまずいた話

はじめに

MAMPを使用してLaravelの環境を構築しようとした際にDB接続の設定でつまずいたため、その内容と解決した方法をまとめます。  

対象読者

初めてLaravelでwebアプリを作ろうとしている初心者の方。

LaravelのDB設定がうまくいかない方。 

開発環境

・mac book pro(Mojave) 
・MAMP(version5.7)
・MySQL
・Composer(version1.9.1)
・Laravel(ver5.8.3)

エラーにハマった経緯

もともとXAMPPを使用してLaravelのアプリを開発していました。
しかし、macで開発をする場合はMAMPを使用した方がベターであるとの話を聞いて、 これを機にMAMPを使おうと思いXAMPPの環境からMAMPの環境にアプリを移行しようとしたのですが、SQLSTATE[HY000] [2002] No such file or directoryのエラーが出てDBに接続できなくなりました。

移行する際にやったこと(失敗例)

XAMPPで環境を作った際、筆者はWEBサーバーもDBサーバーもよくわかっていませんでした。
調べたところ.envと/config/database.phpあたりがどうやらDB接続の設定ファイルらしいとわかり、見よう見まねで何とか接続することができました。

で、MAMPに移行するに当たって、久々にDB接続の設定ファイルを見た所、とりあえず、.envと/config/database.phpのそれらしいところをMAMPに合わせて修正すれば良さそうな気がしたのでやってみました。

MAMPのアプリを立ち上げてサーバーを起動させるとスタートページに飛ぶのでページ内にあるMySQLの設定を参照します。
スクリーンショット 2020-03-13 23.48.34.png

DB_HOST=localhost
DB_PORT=8889
DB_DATABASE=database_name
DB_USERNAME=root
DB_PASSWORD=root

/config/database.phpの中身は先頭に*をつけた項目のみ変更しました。

database.php
      'mysql' => [
            'driver' => 'mysql',
            'url' => env('DATABASE_URL'),
            *'host' => env('DB_HOST', 'localhost'),
            *'port' => env('DB_PORT', '8889'),
            *'database' => env('DB_DATABASE', 'database_name'),
            *'username' => env('DB_USERNAME', 'root'),
            *'password' => env('DB_PASSWORD', 'root'),
            *'unix_socket' => env('DB_SOCKET', '/Applications/MAMP/tmp/mysql.sock'),
            'charset' => 'utf8mb4',
            'collation' => 'utf8mb4_unicode_ci',
            'prefix' => '',
            'prefix_indexes' => true,
            'strict' => true,
            'engine' => null,
            'options' => extension_loaded('pdo_mysql') ? array_filter([
                PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
            ]) : [],
        ],

このように設定してコマンドラインから以下のコマンドを実行したところエラー発生

$php artisan migrate
エラー内容
 Illuminate\Database\QueryException  : SQLSTATE[HY000] [2002] No such file or directory

エラーをみた感じどこかのpathが違うのかなと思いエラー内容を検索したところ、どうやら'unix_socket' => env('DB_SOCKET', '/Applications/MAMP/tmp/mysql.sock')の部分が関係ありそうとわかりました。
そう言えばXAMPPを使った時には/config/database.phpのこの部分をいじった覚えがなかったので、この記述について調べてみると、どうやらMAMPを使ってLaravelからDBに接続するにはTCP接続とUNIXドメインソケットを使用する方法の2通りがあるらしいということがわかりました。
【参考】Laravel5でデータベース接続にUNIXドメインソケットを使う

一応TCP接続が一般的ということでUNIXドメインソケットを使用するよりは簡単そうだと感じ、ひとまずUNIXドメインソケットを使用する方法は保留にしておくことにしました。
よくわからないものは書かない方が良いということで'unix_socket' => env('DB_SOCKET', '/Applications/MAMP/tmp/mysql.sock')の部分を削除し、またTCP接続をする場合にはDB_HOSTを localhostではなく127.0.0.1に変更する必要があるという記事を見つけて.env、/config/database.php共に修正をしました。

【参考】MySQLでlocalhostと127.0.0.1の違い

サーバーを再起動してから、再度以下のコマンドを実行したところ同じエラーが発生

$php artisan migrate
エラー内容
 Illuminate\Database\QueryException  : SQLSTATE[HY000] [2002] No such file or directory

修正した設定は絶対に正しいはずだったのでこうなってしまうとどこが違うかの検討もつかずお手上げでした。

解決方法

筆者は全く知らなかったのですが、どうやらLaravelではApacheを再起動した場合でも内部のキャッシュが残ってしまいプログラムを変更してもうまく反映してくれないことがあるそうです。

【参考】Laravel キャッシュクリア系コマンドなど

そこでコマンドラインから以下のコマンドを実行してキャッシュのクリアを行いました。

php artisan cache:clear
php artisan config:cache

.envファイルと/config/database.phpは以下のように記述

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=8889
DB_DATABASE=database_name
DB_USERNAME=root
DB_PASSWORD=root
database.php
   'mysql' => [
            'driver' => 'mysql',
            'url' => env('DATABASE_URL'),
            'host' => env('DB_HOST', '127.0.0.1'),
            'port' => env('DB_PORT', '8889'),
            'database' => env('DB_DATABASE', 'database_name'),
            'username' => env('DB_USERNAME', 'root'),
            'password' => env('DB_PASSWORD', 'root'),
            'unix_socket' => env('DB_SOCKET', ''),
            'charset' => 'utf8mb4',
            'collation' => 'utf8mb4_unicode_ci',
            'prefix' => '',
            'prefix_indexes' => true,
            'strict' => true,
            'engine' => null,
            'options' => extension_loaded('pdo_mysql') ? array_filter([
                PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
            ]) : [],
        ],

DB接続の確認をするために以下のコマンドを打つとエラーが消えて実行することができたことから、DB接続が確認できました。

php artisan migrate

補足

以上の方法でDB接続をすることには成功したのですが、せっかくなので先ほど保留にしたUNIX_ドメインソケットを使用する方法にも挑戦しました。

UNIX_ドメインソケットを使用したDB接続(エラー編)  

.envファイルと/config/database.phpのDB_HOST127.0.0.1localhostに変更して、/config/database.phpのDB_SOCKETの部分を先の/Applications/MAMP/tmp/mysql.sockに設定をしました。
以下設定ファイル

DB_CONNECTION=mysql
DB_HOST=localhost
DB_PORT=8889
DB_DATABASE=database_name
DB_USERNAME=root
DB_PASSWORD=root
database.php
       'mysql' => [
            'driver' => 'mysql',
            'url' => env('DATABASE_URL'),
            'host' => env('DB_HOST', 'localhost'),
            'port' => env('DB_PORT', '8889'),
            'database' => env('DB_DATABASE', 'database_name'),
            'username' => env('DB_USERNAME', 'root'),
            'password' => env('DB_PASSWORD', 'root'),
            'unix_socket' => env('DB_SOCKET', '/Applications/MAMP/tmp/mysql/mysql.sock
            '),
            'charset' => 'utf8mb4',
            'collation' => 'utf8mb4_unicode_ci',
            'prefix' => '',
            'prefix_indexes' => true,
            'strict' => true,
            'engine' => null,
            'options' => extension_loaded('pdo_mysql') ? array_filter([
                PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
            ]) : [],
        ],

このように設定ファイルを変更し、キャッシュをクリアしてサーバーを立ち上げ直し以下のコマンドを実行してDB接続ができているかを試したところまたしてもエラーが発生。
(DBを作り直すコマンドなので実行には注意)

php artisan migrate:refresh
 Illuminate\Database\QueryException  : SQLSTATE[HY000] [2002] No such file or directory

またこのエラーかということで詰みました。今回も変なところは見当たらないと思っていたのですが、ネットにあがっている記事を色々と見ていたところこのような記事を発見しました。

【参考】Laravelの.envファイルと、config/database.phpファイルについてのメモ

筆者は今まで設定ファイルの中のそれっぽい記述に飛びついて書いていたため全く意識してなかったのですが、config/database.phpのmysqlの設定部分は連想配列になっており、env()という関数に引数として.envファイルで設定した環境変数を渡す形のプログラムとなっています。また、env()の第二引数ではデフォルト値を渡しているそうです。

筆者は今までLaravelのDB接続設定で.envとconfig/database.phpの違いがよくわからないまま、どうしてDB接続の設定ファイルが二つもあるのかという風に思っていましたが、これに気づいて少し納得しました。
とはいえ実際に試してみないと曖昧なままなので、これを踏まえて先ほど成功したTCP接続で実験してみることにしました。

env関数の実験(TCP接続)

config/database.phpがenv()により.envで設定した環境変数の値を取得し、env()の第二引数はデフォルト値であるということは、.envさえ設定していればconfig/database.phpのenv関数の第二引数には何も渡さなくていいんじゃないかという予想を元に.envとconfig/database.phpを変更してみました。

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=8889
DB_DATABASE=database_name
DB_USERNAME=root
DB_PASSWORD=root
database.php
    'mysql' => [
            'driver' => 'mysql',
            'url' => env('DATABASE_URL'),
            'host' => env('DB_HOST', ''),
            'port' => env('DB_PORT', ''),
            'database' => env('DB_DATABASE', ''),
            'username' => env('DB_USERNAME', ''),
            'password' => env('DB_PASSWORD', ''),
            'unix_socket' => env('DB_SOCKET', ''),
            'charset' => 'utf8mb4',
            'collation' => 'utf8mb4_unicode_ci',
            'prefix' => '',
            'prefix_indexes' => true,
            'strict' => true,
            'engine' => null,
            'options' => extension_loaded('pdo_mysql') ? array_filter([
                PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
            ]) : [],
        ],

上記のように設定ファイルを変更して以下のようにコマンドを打ってキャッシュを削除します。

php artisan cache:clear
php artisan config:cache

サーバーを再起動してから、以下のコマンドを打つと実行できるようになり、DB接続が確認できました。

php artisan migrate:refresh

UNIX_ドメインソケットを使用したDB接続(解決編) 

要するに.envファイル内の記述がLaravelのDB接続の設定ファイルとしてはメインだということがわかったのですが、よくよく考えてみるとunix_socketに関する記述がデフォルトでは.envファイルの方に書かれていませんでした。
そこで試しに以下の一文を.envファイルに追加しました。

DB_SOCKET=/Applications/MAMP/tmp/mysql/mysql.sock

上の記述を追加した後の.envファイルの設定は以下のようになります。

DB_CONNECTION=mysql
DB_HOST=localhost
DB_SOCKET=/Applications/MAMP/tmp/mysql/mysql.sock
DB_PORT=8889
DB_DATABASE=database_name
DB_USERNAME=root
DB_PASSWORD=root

/config/database.phpについては変更なしのままです。

database.php
 'mysql' => [
            'driver' => 'mysql',
            'url' => env('DATABASE_URL'),
            'host' => env('DB_HOST', ''),
            'port' => env('DB_PORT', ''),
            'database' => env('DB_DATABASE', ''),
            'username' => env('DB_USERNAME', ''),
            'password' => env('DB_PASSWORD', ''),
            'unix_socket' => env('DB_SOCKET', ''),
            'charset' => 'utf8mb4',
            'collation' => 'utf8mb4_unicode_ci',
            'prefix' => '',
            'prefix_indexes' => true,
            'strict' => true,
            'engine' => null,
            'options' => extension_loaded('pdo_mysql') ? array_filter([
                PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
            ]) : [],
        ],

このように設定したら、再度キャッシュをクリアするコマンドを打ちます。

php artisan cache:clear
php artisan config:cache

サーバーを再起動して、以下のコマンドを打つと実行できたことから、DB接続が確認できました。

php artisan migrate:refresh

まとめ

本記事ではMAMPを使用したLaravelのDB接続についてエラーを解決するために色々試してみました。

長くなったので本記事のトピックをまとめます。

  1. MAMPを使う場合LaravelのDB接続方法にはTCP接続とUNIX_SOCKETを使用した接続がある
  2. Laravelではキャッシュをクリアしないと設定の変更が反映されないことがある
  3. TCP接続を使う際はDB_HOSTを127.0.0.1とする
  4. UNIX_SOCKETを使用して接続する際はDB_HOSTをlocalhostとし、DB_SOCKETを設定する
  5. config/database.phpで使われているenv関数は.envで設定した環境変数を取得する関数である
  6. UNIX_SOCKETを使用して接続する際は.envにDB_SOCKETを設定する文を追加する

終わりに

今まで、あまり内容を理解せずに行っていたLaravelのDB接続設定ですが、今回しっかりと向き合えたおかげで曖昧にしていた部分がよくわかりました。
また、今回はMAMPを使用しておりますが、XAMPPや他の方法でも同じように設定できるのかはわからなかったので後々実験してみようと思います。
本記事を作成する中で色々と試し理解したつもりではありますが、まだまだ理解の浅い部分や間違った解釈をしている部分があるかも知れません。そのような部分があった場合はご指摘いただけると幸いです。

また、初心者の方を対象にした記事になっていますが、記事を作成した筆者もまた、合間の時間を使って独学で学んでいる初心者です。筆者の話をすると、現在webプログラマーを目指して就職活動中ですが、未経験歓迎と書いてありながらも現場で働いている社員の方は即戦力になる人が欲しいと思っているのが本音なのか、どんなに熱心に準備をして望んでも興味なさそうに面接をされて落とされることもありました。
ただ、それはそれで仕方ないと筆者は割り切るようにしています。笑
しんどいことや辛いこともたくさんありますが、頑張っていきましょう!

参考サイト一覧

本記事の中で参考にさせていただいた記事を一度リンクを貼ったものも含めて再度掲載します。

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

HerokuでLaravel+MySQLのプロジェクトをマイグレーションする時に詰まったこと

$ heroku config | grep CLEARDB_DATABASE_URL

上記で表示されたDATABASE_URLを参考に環境変数を設定

$ heroku config:set DB_DATABASE=[データベース名]
$ heroku config:set DB_HOST=[ホスト名]
$ heroku config:set DB_USERNAME=[ユーザー名]
$ heroku config:set DB_PASSWORD=[パスワード]

マイグレーションを実行

$ heroku run php artisan migrate

下記のエラーが表示された
環境変数を確認しても間違いはなかった

SQLSTATE[HY000] [2002] No such file or directory 

調べたところ、unix_socketはlocalhost内で通信を行う際に使うみたいなので、config/database.phpファイル内のunix_socketのパスを削除。

config/database.php
'unix_socket' => env('DB_SOCKET', 'root'),
config/database.php
'unix_socket' => env('DB_SOCKET', ''),

無事にMysqlに接続できた

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

がっつり開発するほどじゃないけどちょっとLaravelいじりたい時の環境構築

Laravel使ってるところに放り込まれたので軽く予習するために環境を作ったメモ。

macOS Catalina v10.15.3
Homebrew v2.2.9

Composerインストール

▶︎ brew install composer
▶︎ composer -V
Composer version 1.9.3

PHPインストール

MacにプリインストールされているPHPを使ってると、このあとうまくいかなかったのでついでにPHPも入れる。
どのみち、公式Homesteadを使わないならPHP >= 7.2.5じゃないとだめって書いてあるのでアップデートの必要はあったっぽいが詳しくはわからない。

▶︎ brew search php
==> Formulae
brew-php-switcher      php-cs-fixer           phplint                phpstan
php                    php@7.2                phpmd                  phpunit
php-code-sniffer       php@7.3                phpmyadmin

brew install phpしたらv7.4.3が入った。

Laravelインストール

▶︎ composer require "laravel/installer"
▶︎ laravel new ディレクトリ名

もしくは

▶︎ composer create-project laravel/laravel ディレクトリ名

(どっちの方がいいとかあるのだろうか?)

バージョン確認

▶︎ php artisan -V
Laravel Framework 7.0.8

Hello World

コントローラー

▶︎ php artisan make:controller SampleController
Controller created successfully.
app/Http/Controllers/SampleController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class SampleController extends Controller
{
    public function sampleFunction()
    {
        $hello = 'Hello';
        return view('sample', ['h' => $hello, 'w' => 'World']);
    }
}

ビュー

resources/views/sample.blade.php
<h1>{{ $h }} {{ $w }}</h1>

ルーティング

routes/web.php
<?php

use Illuminate\Support\Facades\Route;

Route::get('/','SampleController@sampleFunction');

ローカルサーバー起動

▶︎ php artisan serve
Laravel development server started: http://127.0.0.1:8000

HelloWorld

http://127.0.0.1:8000にアクセスするとこんな感じ。

TODO

  • Bladeテンプレート
  • artisanコマンド
  • データベース関連
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Laradock環境構築】Dockerインストール〜Laravelデフォルトページ表示まで①

はじめに

こちらの記事では、Laradockの環境構築として、
Dockerのインストール〜Laravelのデフォルトページ表示までを載せていきます。
このページでは、パート①ということで、Dockerのインストール方法を載せていきます。
(Mac版しか載せていません)

次回のパート②はこちら↓
https://qiita.com/y-aimi/items/a6b3ee863ec67c8d4b97

Dockerインストール

下記リンクからインストールできます。
https://hub.docker.com/editions/community/docker-ce-desktop-mac

image.png

Sign Upをクリック

image.png

全て入力し、Sign Upをクリック
(プロフィール登録などが出ますが、今回は必要ないので無視)
すると、登録したメールアドレスに確認のメールが届いているのでチェック。

image.png

[Verify email address]をクリック。
すると、Sign Inの画面が表示されるのでSign Inします。

image.png

image.png

Docker.dmg がインストールされたかと思いますので、こちらを開く。
image.png
上記のような画面が出るので、左のクジラのイラストをApplicationsにドラッグ&ドロップ。
(このような画面が出なくてもApplicationに入れれば大丈夫です。)

アプリケーションのDockerを起動。
すると、初回は下記のアラートが出ます。

image.png

これは、
「ネットからインストールしたアプリだから確認のためにパスワード教えてくれない?」
ということです。

問題なければOKをクリック。
そのままMacのパスワードを入力。

すると、このような画面が表示されるので、Sing Inします。
image.png
[Docker Desktop is now up and running!] に変われば大丈夫です。
image.png

無事起動されているかのチェックは画面の上にこののマークがあれば大丈夫です。
image.png
(クジラさんがきちんとコンテナを積んでくれていますね...!!)

まとめ

これで、Dockerのインストールが無事終わりました!
次回は、エラーが起きまくって困ったLaradockの環境構築に行きたいと思います。

次へ

Laradock環境構築】Dockerインストール〜Laravelデフォルトページ表示まで②
https://qiita.com/y-aimi/items/a6b3ee863ec67c8d4b97

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