Laravel・PHP入門

PHPer初心者

【環境構築】【AWS / Laravel】Amazon Linux2 + Laravelで環境構築

割とつまづいたのでメモ。

構築する環境

更新

$ sudo su // 更新するので権限変更
# yum update // 全部アップデート

日付設定

# cp /usr/share/zoneinfo/Japan /etc/localtime
# yum install ntp
# vi /etc/sysconfig/clock

ZONE="UTC"
UTC=true

ZONE="Asia/Tokyo"
UTC=false

# vi /etc/sysconfig/ntpd

OPTIONS="-g"

OPTIONS="-g -x"

# systemctl restart ntpd.service
# date
2018年 7月 15日 日曜日 21:02:54 JST // 現在時刻が出ればok

Apacheをインストールする

# yum install httpd
# /usr/sbin/httpd -v

Server version: Apache/2.4.33 ()
Server built: Jury 15 2018 21:37:52 // インストールできればok

# systemctl start httpd.service // CentOS7でcommand変わったので注意
# systemctl stop httpd.service

Apache設定

// オリジナルコピー
# cp /etc/httpd/conf/httpd.conf /etc/httpd/conf/httpd.conf.`date +%Y%m%d`

// httpd.confをいじります
# vi /etc/httpd/conf/httpd.conf

## ドキュメントルート
DocumentRoot "/var/www/html"

DocumentRoot "/var/www/sample/public" // 今回もしsampleというディレクトリ名なら

## アクセス上書き

AllowOverride None

AllowOverride All

## Apacheのバージョン秘匿
(下の方に追加)
# Hide Apache Version
ServerTokens Prod

#service httpd configtest // 編集後テスト
Syntax OK // OKが出ればok

PHPインストール

# amazon-linux-extras install php7.2 // AWS公式の通り
# php -v // 7.2が出てくるはず
# yum -y install php-devel php-pdo php-mbstring php-mcrypt php-mysqlnd php-xml php-gd php-opcache php-pecl-zip
// PHPに必要なパッケージ色々はyumでインストール

Composerインストール

# curl -sS https://getcomposer.org/installer | php
# mv composer.phar /usr/bin/composer // パスが通る場所へ移動
# composer -v
めっちゃComposer!!って出ればok

Gitインストール

# yum install git
# git --version
git version 2.7.5 // 出ればok

npmとnodeとnvmとyarnインストール

# curl --silent --location https://rpm.nodesource.com/setup_8.x | bash -
# yum install nodejs npm
# npm -v
# node -v
# curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash
# source ~/.nvm/nvm.sh // パスを通す
# nvm install 6.* // nodeが6系しかいうこと聞いてくれないので6系へ合わせる
// nodeとnvmのインストール順変えても良いかも

# sudo wget https://dl.yarnpkg.com/rpm/yarn.repo -O /etc/yum.repos.d/yarn.repo
# sudo yum install yarn
# yarn --version

Githubへ接続

# cd ~/.ssh
# ssh-keygen -t rsa -C sample@aaa.jp(enter 3回) // 自分のGithubアカウントアドレス
# vim ~/.ssh/config

Host github.com
HostName github.com
IdentityFile ~/.ssh/id_rsa
User Githubのアカウント名

# cat ~/.ssh/id_rsa.pub
※ ブラウザからgihubのSSH keysに追加
# cd /var/www/
# git clone git@github.com:sample/aa.git // 既存リポジトリをクローンする

リポジトリから色々インストールと権限

# cd sample/
# composer install
# yarn install
# yarn run dev
# chmod -R 777 storage
# chmod -R 777 bootstrap/cache

起動する

# systemctl restart sysstat.service // Apache
# cp .env.example .env
# php artisan key:generate

これで環境構築は完了です!

あとはAWSのアドレスへアクセスすればアクセスできるはず

【PHPUnit】【Laravel】定数ファイル管理

やりたいこと

  • 定数管理ファイルの場所変更
  • テストの時も定数管理

定数ファイルの場所を変更したい

今回の場合はbootstrap下へ作成したい。

bootstrap下でautoload.phpを作成する。

bootstrap/autoload.php

<?php

/*
|--------------------------------------------------------------------------
| Register The Composer Auto Loader
|--------------------------------------------------------------------------
|
| Composer provides a convenient, automatically generated class loader
| for our application. We just need to utilize it! We'll require it
| into the script here so that we do not have to worry about the
| loading of any our classes "manually". Feels great to relax.
|
*/
require __DIR__.'/../vendor/autoload.php';

$filelist = glob(__DIR__ . '/constants/*.php');
foreach ($filelist as $file) {
    if (is_file($file)) {
        require_once $file;
    }
}
/*
|--------------------------------------------------------------------------
| Include The Compiled Class File
|--------------------------------------------------------------------------
|
| To dramatically increase your application's performance, you may use a
| compiled class file which contains all of the classes commonly used
| by a request. The Artisan "optimize" is used to create this file.
|
*/
$compiledPath = __DIR__.'/cache/compiled.php';
if (file_exists($compiledPath)) {
    require $compiledPath;
}
オートローダー呼び出し元ソース変更

通常はindex.phpでオートローダーを呼び出すのでこちらも変更
public/index.php

変更前:require __DIR__.'/../vendor/autoload.php';
変更後:require __DIR__.'/../bootstrap/autoload.php';
定数ファイルの作成

bootstrap下に早速作成する
定数なのでconstantsディレクトリを作成

bootstrap/constants/common.php

<?php
const FLAG_ON = 1;
const FLAG_OFF = 0;

フラグ作ってみました。

アプリケーションで使用

Post呼び出しの時に、表示するもの、しないものを分けてみます
例えばshow_flagカラムを追加し、flagがonの場合のみ表示したい

app/Repositories/Post.php

<?php
//  一部抜粋
    public function getAllPosts()
    {
        return $this->post_model
            ->where('show_flag', FLAG_ON) // ここで定数使用
            ->get();
    }

これでflagがonのpostのみがかえるようになりましたね

いざテスト

エラーが出る

./vendor/bin/phpunit tests/Feature/PostsTest.php

f:id:fresh_engineer:20180712230841p:plain

storage下のlogをみると、FLAG_ONなんて定数知らねーよ!!!!って
怒られます。。。

テストは指定している定数ファイルを読み込んでくれません。
なので読み込んでくれるようにベースのテストクラスで呼び出してあげます

ついでにベースのテストクラスも作る

<?php

namespace Tests;

use Illuminate\Foundation\Testing\TestCase as BaseTestCase;

abstract class TestCase extends BaseTestCase
{
    use CreatesApplication;

    public function setUp()
    {
        parent::setUp();
        $this->readConstants();
    }

    /**
     * テスト用に定数ファイル読み込み
     */
    private function readConstants()
    {
        $file_list = glob('./bootstrap/constants/*.php'); // 定数ファイルを全部取得
        foreach ($file_list as $file) {
            if (is_file($file)) {
                require_once $file; // 各ファイル1度だけ読み込む
            }
        }
    }
}

こうして読み込んであげると、、、

./vendor/bin/phpunit tests/Feature/PostsTest.php


f:id:fresh_engineer:20180712231106p:plain

テスト通過!

これで定数も使いながらテストが実行できるようになりました。

以上

【Laravel】【PHPUnit】コレクションや配列のテスト

今日はLaravelでよく出てくるCollectionデータのテストコードを書いていて
ハマったのでまとめます。


サンプルはこちら。
Post一覧取得APIのテストコード · aihara005/laravelprot@ba2e4b8 · GitHub
PHPUnitテスト by aihara005 · Pull Request #3 · aihara005/laravelprot · GitHub

PHPUnitの準備

まずはローカルでphpunitを使うための準備。
$ vi .env

APP_URL = 自分のURL
php artisan serveで立ち上げてる時は
http://127.0.0.1:8000

サンプルテストを作る

早速簡単なテストを作って通過するかチェックします。
前回の記事でちょうどGETリクエストでレスポンスを返すAPIを作成していたので
それを使って200レスポンスがかえるかテストします。

/tests/Feature/ExampleTest.php

<?php

namespace Tests\Feature;

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

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

        $response->assertStatus(200);
    }
}

サンプルテストを実行する

$ ./vendor/bin/phpunit tests/Feature/ExampleTest.php //コマンドでphpunit叩く


f:id:fresh_engineer:20180712002447p:plain

成功しました!

コレクションのテストを作る

それでは前回作成したpostsのAPIについて、
postsコレクションがjsonで返却されるので
テストを作ってみます。

tests/Feature/PostsTest.php

<?php

namespace Tests\Feature;

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

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

        $response->assertStatus(200)
                ->assertJsonStructure([ // Json形式を指定
                    'data' => [
                        // コレクション系は * でキーを指定すればok
                        '*' => [ 
                            'id',
                            'title',
                            'body',
                             // リレーションも1対多なのでネストした状態で * でキーを指定すればok
                            'comments' => [
                                '*' => [
                                    'id',
                                    'post_id',
                                    'body'
                                ]
                            ]
                        ]
                    ]
                ]);
    }
}

「*」 を使う形式でokでした・・・!

テストを実行する

$ ./vendor/bin/phpunit tests/Feature/PostsTest.php

f:id:fresh_engineer:20180712003836p:plain

コレクションなどでモデルが配列になって返ってくるタイプはこれで解決しそうです。
結構はまりました。。。

エラー

失敗パターンもちゃんと指摘してくれます。
例えば上記のpost_idをpost_aaaidなどに変換すると

f:id:fresh_engineer:20180712004115p:plain

そんなidないよって怒ってくれますね。素敵です。



以上

【Laravel】APIリソースを使う(Json/API)

LaravelのAPIリソースを使ってとても便利だと思ったのでまとめ。

https://readouble.com/laravel/5.5/ja/eloquent-resources.html

APIリソースとは(日本訳ドキュメント引用)

API構築時、Eloquentモデルと、アプリケーションユーザーに対して実際に返信するJSONリスポンスとの間に、
トランスレーション層を設置することが必要となります。
Laravelのリソースクラスは、モデルやモデルコレクションを記述しやすく簡単に、JSONへと変換してくれます。

ちなみにLaravel5.5で登場したそうです。最高です。

実装するもの

  • /posts でPost一覧を取得するAPIで返却するリソース
  • /posts/{id}でIDが1のPostを取得するAPIで返却するリソース

完成形

  • 一覧

f:id:fresh_engineer:20180706235357p:plain

  • ID指定

f:id:fresh_engineer:20180706235431p:plain

こんな感じです。

前準備

  • 環境構築(Laravelプロジェクト)
  • Controllerの作成
  • Modelの作成
  • Route通す
  • DBにPostとCommentを準備

用意したデータ

  • postsテーブル

f:id:fresh_engineer:20180707001326p:plain

  • commentsテーブル

f:id:fresh_engineer:20180707001353p:plain

ディレクトリ構成

App
┗Http
  ┝Controllers
    ┝BaseController.php
    ┝PostController.php
    ┗CommentController.php
  ┝Resources
    ┝BaseResource.php
    ┝Post.php
    ┗Comment.php
  ┝Models
    ┝BaseModel.php
    ┝Post.php
    ┗Comment.php
  ┝Repositories
    ┝BasePost.php
    ┝Post.php
    ┗Comment.php
  ┗Services
    ┝BaseService.php
    ┝Post.php
    ┗Comment.php

深くなりましたが
APIリソースに深く関わるのは
・取得するデータのロジックを記載するRepository
インスタンス化するService
・レスポンスを定義するResourceクラス
この3つです。

イメージを明確にするために、補足でController/ Route/ Modelは画像のみ貼っておきます。

Route

f:id:fresh_engineer:20180707000006p:plain

Controller

f:id:fresh_engineer:20180707000018p:plain

Model

※PostにひもづくCommentも取得したいのでリレーション定義
f:id:fresh_engineer:20180707000457p:plain

リソースに渡すモデルを取得

今回はRepositoryクラスに実装します。
f:id:fresh_engineer:20180707000057p:plain

リソースの作成

php artisan make:resource PostResource

まずはリソースクラスを作成します。

  • Postリソース

今回はPost一覧を求められた場合、
Postのもつid,title,body,とそのPostにひもづくCommentを取得したい。
渡したい情報をそれぞれキー(クラスにより自由です)、
そして渡したモデルの誰がそのデータを持っているか渡してあげます。

CommentはPostと1対多の関係、つまりは1Postが複数のCommentを持ちうるので
Commentリソースについてcollectionメソッドを用います。

このように、APIリソースはそれらのリレーションで紐付く情報も
プロパティから呼び出して別のリソースを整形して同時に返却することができます。

<?php
namespace App\Http\Resources;

use App\Http\Resources\Comment as CommentResource;
use Illuminate\Http\Resources\Json\Resource;

class Post extends Resource
{
    public function toArray($request)
    {
        return [
            'id' => $this->id,
            'title' => $this->title,
            'body' => $this->body,
            'comments' => CommentResource::collection($this->comments)
        ];
    }
}
  • Commentリソース

コメントではid,post_id,bodyを返却したいのでそれぞれ定義して返します。

<?php
namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\Resource;

class Comment extends Resource
{
    public function toArray($request)
    {
        return [
            'id' => $this->id,
            'post_id' => $this->post_id,
            'body' => $this->body
        ];
    }
}

リソースをインスタンス化する

リソースを実際に使用するときは、DBから取得したデータを
引数として渡しつつ、インスタンス化します。

リソースが1つの時は newでインスタンス化すれば良いですが、
複数のコレクションの場合はcollectionメソッドを用います。

<?php
namespace App\Services;

use App\Http\Resources\Post as PostResource;
use App\Repositories\Post as PostRepository;

class Post extends BaseService
{
    private $post_repository;

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

    /**
     * 全てのPostを取得し成型してJsonで返す
     *
     * @return mixed
     */
    public function getAllPosts()
    {
         return PostResource::collection($this->post_repository->getAllPosts());
    }

    /**
     * IDからPostを取得し成型してJsonで返す
     *
     * @param int $id
     * @return mixed
     */
    public function getPostById(int $id)
    {
        return new PostResource($this->post_repository->getPostById($id));
    }
}


これで、URLを叩くと
f:id:fresh_engineer:20180706235431p:plain
f:id:fresh_engineer:20180706235357p:plain
データが返ってきましたね!

リソースはいくつも階層重ねることもできるので、
ドメイン的な整形の仕方にももってこいですね。
積極的に使っていきたいです

以上

【Linux】パーミッション設定についての基本

Permission Deniedよく引っかかりますよね。
詳しく紹介している記事はたくさんあるので
最低限ざっくりわかればと思います。

なんとなく使ってたchmod 777 〜ファイル名が今日解決したのでメモ。

パーミッションを確認する

ls -l ディレクトリ名

f:id:fresh_engineer:20180704233655p:plain

9個d、w、r、- などが並んでいますが、
これは1 + 3つずつに分解できます。

例えば

drwxr-xr-x の場合。

d / rwx / r-x / r-x

これに分けることができます。

初めのdはディレクトリかどうか。

その次は3つずつ、権限のことを示しています。
権限はざっくり3種類。

r 読み込み
w 書き込み
x 実行

順番はそのファイルやディレクトリの所有関係によります。
なので、10個並んでいた連番は下記のようなイメージですね。

ファイルの種類 / 所有ユーザの権限 / 所有グループの権限 / その他のユーザの権限

権限を付与する

そしてここまでわかればchmodで与えてあげるだけです。

例えば

chmod -R 777 ディレクトリ名

例えばこれはディレクトリ配下になんでもできる権限を与えています。

777は、先ほどの3種類のユーザの権限を
順番に指定しています。

rwx 4 + 2 + 1 = 7
rw- 4 + 2 + 0 = 6
r-x 4 + 0 + 1 = 5
r-- 4 + 0 + 0 = 4
-wx 0 + 2 + 1 = 3
-w- 0 + 2 + 0 = 2
--x 0 + 0 + 1 = 1
全てを許可しない 0 + 0 + 0 = 0

今日とてもスッキリしました!
ざっくり理解したい人はこれで使えると思います。

細かい内容はググってください

以上

【メモ】非エンジニアの課題発見力問題について

最近色々思うことがあったのでメモ。

背景

弊社は優秀な営業やマーケターが多い。
けど現実として非効率な作業が多すぎる
それが業務工数を圧迫している。

要因

対応力と受容力が高すぎ

頭の回転が早く、いい人が多い。
今あるモノでどう解決するかを考えるのはめちゃくちゃ得意だけど、
・それは本質的な問題か?
・今ないもの(他の人や他事業部リソース)を使った解決方法はないか?
を考える人が少ない。

システムだとだいたいのことが「難しそう」

メール送信やAPI連携はエンジニア目線では全然難しくないことなのに
「これは難しいんだろうなあ」と知らないが故に思ってしまう。
できることとできないこと、それに必要な時間を知らないことが問題。

目標は短期売上であり業務効率化ではない

極端な言い方をしましたが、結局いつも目線は短期売上であり
意外と長期やチームの売上には目を向けづらい。
(短期売上の達成が自分の目標であり、
業務的にも忙しいので当然かなとも思っています。)

問題を問題だと言える場とタイミングが少ない

営業はものすごく差し込みや早期対応が必要な業務が多く
これって問題かもなと思ったときにそれを記憶したりメモしたりすることもなく
そのまま忘れてしまうことが多いのではないかなと。

エンジニア忙しそうにしすぎ

どの会社もエンジニアにはタスクが積み重なっていて
忙しそうというか喫緊の課題ではないがやらないといけないことは無限にあるなと思います。
忙しくはないけど暇はない人が多いのかと。

でも実際は(例えば弊社は)MTGの時間なんていつでもとってもらっていいし
例えば議題にあがってない潜在的な問題のほうが本当は優先順位が高いのかもしれないし
このあたりを非エンジニアが感じられておらず、エンジニアと会話できない問題があるんじゃないかなと。

このあたりは日常の会話やコミニュケーションから解決できるといいですね。

結局問題は現場にある

今まで記載したことも、別にエンジニアが解決すればよいのですが
現場に一番問題が転がっているので、非エンジニアが課題発見できると
より良い仕組みができるかなと思います。


解決手法

要因から解決できそうか試したいこと

企画済みの仕様設計をやってもらい爆速プロトタイプを返す

これは今スモールスタートしていることですが
「これがしたい」のだけれど、「どうやって実現するか」
の手段をヒントを渡しながら、設計してもらってみています。
「システムで意外と実現できる・これは難しい」を知ってもらうためです。

ヒントを渡すことで、あ、そんな手段もできるんだを広げてもらい
SlackのAPIと連携ってすぐできると思うよ、
プロト作ってみるね、ほらできるんだよね(本当に作るならこのくらいの時間はかかるけれど)
で原体験として「本当にできるんだ」を体験してもらう。
エンジニアだったらこれを自分で作ることができるけれど
非エンジニアはそれができないので疑似体験で持ってもらうことが大事かなと思っています。

逆にシステムではなく業務フロー改善など、
システムを使わず解決できることも設計を業務フローから行うことで
仕組み化したいなあと思っています。

週次の問題提案 & 投票MTGを設定する

あるエンジニアさんからヒントをいただいたので、
習慣的に週1とかで少人数から課題とその投票をやりたいなと思っています。
そうすることで、あ、これ来週のMTGで提案しよう
これこないだ言ってた箇所だ、本当だ、面倒だな、問題だなと
他の人の問題認識から、問題認識の視野を広げてもらうことができればいいなと思っています。

そして現実的にすべての問題を解決するリソースはないので
どうやってシステム側が優先順位をつけていて、
なぜ自分の上げた課題の優先順位が下がってしまうのか
納得できるような透明性が実現できればベストかなと思っています。

エンジニアと非エンジニアのコミニュケーションもっととる

事業部側以外のエンジニアってディレクターを通して会話することが多く
エンジニアに直接コミニュケーションを取れることが少ないかなと思います。
だから余計に「忙しそう」って思われやすいけど実はそうでもなかったりする。
あと私はまだまだなんですけど、、エンジニアって問題解決のプロだと思っていて
業務フロー改善とかも相談すればできるかもしれないし、
逆にエンジニアは営業の会話から業務を知って
もっとここってこうしたほうが良かったんじゃないか、
機能に意味がないんじゃないかとか考えられるかもしれないなと。

あくまでエンジニアも非エンジニアもその事業をユーザさんへ提供するための存在で
手段が営業だったりシステムエンジニアだったりするだけですよね
もっと事業目線でお互い会話できれば視座あがるかなって思います。


とりあえず弊社で今あげた解決方法をやってみてまた報告したいなと思います。


以上

【ぼやき】なぜエンジニアになったのか、これから何がしたいのか

最近よく話すことを言語化しておきたいなとおもったので。
昔とあんまり変わってないようで変わったかな。

今とこれからやりたいこと

エンジニアとしてエンジニア文化に貢献していきたいです。
あとは適切な努力家が報われる社会をつくりたいです。

その目標に対して自分が何をできるかは模索中でして、
例えばエンジニアがもっと働きやすい環境をつくることだったり、
業務の自動化だったり、エンジニアの評価制度を整えるだったり、
エンジニア教育でエンジニアを増やすことだったり、OSSへのコミットだったり、
エンジニア向けのサービスだったり。
いろんな手段の中で自分の得意分野とやりたいことができれば嬉しいです。

今はエンジニアとしての経験が浅すぎるので、
エンジニアに貢献するならエンジニアとしてしっかりものづくりを学ぶことを重視しています。

エンジニアになったきっかけ

rails new blog

キャリアアドバイザー時代、
railsの環境構築を社内のエンジニアさんに教わっていました。
rails new blog と叩いたとき
沢山のディレクトリとファイルができていることに驚きました。
そしてこれが無料と聞いて衝撃を受けました。

営業って売上へのインパクトは正直めちゃくちゃでかいし、
おもしろいとも思うのですが
意外と知識やノウハウは記憶ベースだったり、
アナログに蓄積されているんですよね。

それが、エンジニア界隈は全く違う。当然ですが全てがデジタルで
かつ皆が使える武器を、損得勘定だけでなく
皆がより良くしようとOSSが進化し続けてるんですよね。
それって本当にすごいなあと。それは、ものすごく業界としてもスキルも圧倒的な速さで進化していくだろうなと。

そして何よりすごいのは、エンジニアにとってそれらは全部当たり前で。
これが文化になっている。
この規模の文化は、他で再構築するよりも飛び込んだほうが圧倒的に早いなと思い
エンジニアになりたいな思いました。

「なれる」って言われたから

前の記事にも書いたんですが、知り合いになれると言われたから(笑)
ばかみたいに、あ、なれるんだって思ってしまったことが
本当になったきっかけです。

「エンジニアにならないの?」
「なりたいとは思うけど、なれるのかな、とも思う」
「え、なれるよ」
「だって俺がエンジニアになったの25歳だし」
「同い年だし」
「なれる」

この言葉のおかげです。感謝

ざっくり経歴と今やっていること

エンジニア専門のキャリアアドバイザーとして
300人と1対1面談

OSSに感動し
PHPエンジニア(Laravel)として7ヶ月目。
今は新規サービスのサービス設計や
関係者の業務フローの改善、
アジャイルで設計やAPIの実装などをしています。


最近自己紹介するならこんな感じです。

以上