20200710のPHPに関する記事は19件です。

PHPでlike検索かける方法

likeを使った検索方法

誤った方法

   $lists = $db->prepare('SELECT * FROM example WHERE like "%?%" ;');
    $lists -> execute(array($_SESSION['key']));
}

これだと、%も?もエスケープされていないので、期待した値が得られない

正しい方法

      $lists = $db->prepare('SELECT * FROM example WHERE  like ? ;');
    $lists -> execute(array('%'.$_SESSION['key'].'%'));
}

つまり、「%」ごと挿入すると考えることが重要であると分かった。

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

【超初心者用】MacでphpMyAdminからアクセスできない時の対処法

ターミナルからはログインできるのに!

ターミナルからmysql起動してログイン。

起動
$ mysql.server start
ログイン
$ mysql -u root -p

phpMyAdminからログインしよう!
http://localhost/phpmyadmin/
image.png

ユーザ名:root
パスワード:(mysql -u root -pの後に入力するパスワード)

するとエラーが出てきました。

mysqli_real_connect(): The server requested authentication method unknown to the client [caching_sha2_password]

これともうひとつ出てきましたが、これを調べて対処したら解決したので、残っていません。

どうやらMySQLにアクセスして修正する必要があるらしいです。

ターミナルに戻ってmysqlにアクセス

$ mysql -u root -p

パスワードを入力して入ると

mysql>

という表示がされるので、この状態で次を入力すると解決しました

解決法

mysql> ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '(mysql -u root -pで入力するパスワード)';

とりあえずこれで解決しました。

原因はなんだったのか?

不明です。分かる方教えてください!

やっとこれでphpのローカル環境ができました。
ここまでくるのに2日もかかりました。

途中nginxに寄り道してしまい、結局うまくいかずApacheでやることにしてもなお道に迷った生まれて数秒並の子羊が書きました。

これから立派な羊になれるように勉強していきます。

参考にしたサイト

https://toaruhetare.net/9105
https://teratail.com/questions/29659

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

PHPで動的な変数名に値を設定する

$arr = ['a', 'b', 'c'];
$test1 = '';
$test2 = '';
$test3 = '';
for($idx = 0; count($arr) > $idx; $idx++) {
    ${'test' . ($idx + 1)} = $arr[$idx];
    // $this->{'test' . ($idx + 1)} = $arr[$idx];とするとクラスのプロパティも行ける
}
// $test1 = 'a'
// $test2 = 'b'
// $test3 = 'c'
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

変数と関数のネーミング

変数・関数のネーミング

今更ですが変数・関数のネーミングについてリーダブルコードを元にまとめました。
上から順番に重要だと感じている順です。

リーダブルコード 4 章

一貫性

「同じデータ」は同じ変数名にしましょう。
(プロジェクト単位で良いです)

// a.php
$studentname = 'yamada';
// b.php
$username = 'tanaka';

↓↓↓

// a.php
$studentname = 'yamada';
// b.php
$studentname = 'tanaka';

リーダブルコード 8 章

説明変数

「処理」(の結果)を説明する変数

if (substr($str, 0, strcspn($str,'(')) === 'root') {... }

// ↓↓↓

$username = substr($str, 0, strcspn($str,'('))
if ($username === 'root') {... }

要約変数

状態とか、式を端的に説明する変数

if ($user->plan === 'gold') {... }

// ↓↓↓

$isGoldPlan = $user->plan === 'gold';
if ($isGoldPlan) {... }

リーダブルコード 3 章

誤解されない変数名

ニアイコール、とにかく詳しく書いてね

リーダブルコード 9 章

変数のスコープを考慮した名前にしましょう!

こんなクラスがあったとして、

class User
{
    private $id;

    function getUserId()
    {
        return $this->id;
    }
}

getUserId は、使われるときに冗長に見える

// user と UserId で user がかぶっている
$user->getUserId();

↓↓↓

// 関数に user がなくても、user id ってだいたい分かる
$user->getId();

ただし!!!

変数に入れるときはきちんと説明を入れて上げる必要がある。

// (id はきっと order.id とか、 admin.id とかいろいろあるから)
$userid  = $user->getId();
$orderid = $order->getId();

定数名

定数名が適当だと..

define('STATUS', 20);

ユーザーのステータス? 注文のステータス? 管理者のステータス?
↓↓↓

define('USER_STATUS', 20);

定数はより詳細な名前にしましょう!

その他

変数で説明するより、関数で説明したほうがわかりやすい(完結)です

$isGoldPlan = $user->plan === GOLD_PLAN;
if ($isGoldPlan) {... }

if ($user->isGoldPlan()) {... }

if ($user->isPlan(GOLD_PLAN)) {... }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PHP 関数の戻り値とは?

はじめに

これは初心者エンジニアがフルスタックエンジニアを目指す備忘録である:point_up:

目次

⑴ 戻り値とは
⑵ 戻り値がない場合
⑶ 戻り値がある場合と戻り値がない場合の違い

⑴戻り値とは

前回投稿した sum関数を使って説明していきたいと思う。
コードは以下になる。

<?php
// 1〜$max までを足して結果を返す関数
function sum($max) {
    $result = 0;

    // $i は1から始まり、$max より大きくなるまでループする
    for($i = 1; $i <= $max; $i++ ){
        $result += $i;
    }

    return $result;
}

// 関数を実行
echo sum();
?>

今回で言うと戻り値と言うのは

return $result;

の部分になる。

これは return のあとに書かれた$resultが、関数が実行された結果として出力している意味となる。

つまりこの return のあとに書かれた値を 戻り値 と呼び
sum関数の結果が returnされて $resultに入っていくというイメージになる。

⑵ 戻り値がない場合

ちなみに今回実装したsum関数は戻り値があるが、
例えば、

<?php
// 1から100までを順番に表示する関数
function print_number(){

    for($i = 0; $i < 100; $i++){
        echo $i;
    }
}
?>

のように、返り値のない関数もある。
これには意味があるので次で紹介していく

⑶戻り値ある場合と戻り値がない場合の違い

戻り値がある場合と戻り値がない場合の違いについて説明していきたいと思う。

どちらとも関数の結果を処理する点は同じである。

⇩ 唯一の違いは

リターンで戻り値を受け取って表示させるかどうかである

⇩ では、リターンの意味はどの様な所に意味があるのか

▶︎ 戻り値がある場合
戻り値がある関数は、関数内で処理した結果を返すことができる。その為受け取った結果をさらに計算したり、文字列とくっつけたり、することができる。

▶︎ 戻り値がない場合
戻り値がない関数は関数内で処理した結果を返すことができない。

正直これだけの事だということですね。
うん。簡単です。

以上で終了です。

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

APIを使用して検索した首都の天気を表示させる

はじめに

今回この記事を書く背景として、工場勤務からit企業へ転職し普段の業務でAPIを使用するので、自分が勉強した内容のアウトプットとなります。
ちなみに、転職して4ヶ月目になりますが、まだポンコツなのでこれからも記事を量産していくので、良かったらご指摘等あればご教示お願いします。

環境

ローカルサーバー:MAMP
OS:Mac
エディタ:VScode

APIとは

Application Programming Interface(アプリケーションプログラミングインタフェース)。
公開しているソフトウェアを他からをもってきてガッチャンこするイメージ。
外部のソフトウェアを使用する事により、効率的に開発が行えます。

今回のお天気APIを使用する手順

①APIを公開しているサイト(今回は下記URL)に登録。
https://openweathermap.org/

②ヘッダーにある「API」から「Current Weather Data」の「Subscribe」から無料枠を選んで、「APIkeys」からAPIkeyを発行する。

---ココからはエディタで作業します---

③APIkey+URLを使用しサイトのAPI(中身はjson形式のデータ)を取得

④jsonデータをエンコードし、検索した地域によって天気などを表示させる

APIkeyとは?

ざっくりいうと、キーなのでセキュリティに関わるものですね。
APIkeyは発行する事により、ユーザーを認証し、ある一定の条件をクリアしたユーザーのみにAPIを使う権限を与えるような感じ。

実践

index.php
<?php

    $weather = "";
    $error = "";

    //配列にcityがあるかの確認//
    if (array_key_exists('city', $_GET)) {
      $url_get=file_get_contents("https://api.openweathermap.org/data/2.5/weather?q=".$_GET['city'].",&appid=発行したAPIkey");
      $dateArrer=json_decode($url_get,true);
      $weather=$_GET['city']."の天気:".$dateArrer['weather'][0]['main'].",".$dateArrer['weather'][0]['description'];

    }


?>


<!DOCTYPE html>
<html lang="en">
  <head>
    <!-- Required meta tags always come first -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta http-equiv="x-ua-compatible" content="ie=edge">

      <title>Weather Scraper</title>
    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.2/css/bootstrap.min.css" integrity="sha384-y3tfxAZXuh4HwSYylfB+J125MxIs6mR5FOHamPBG064zB+AFeWH94NdvaCBm8qnd" crossorigin="anonymous">

      <style type="text/css">

      html { 
          background: url(background.jpeg) no-repeat center center fixed; 
          -webkit-background-size: cover;
          -moz-background-size: cover;
          -o-background-size: cover;
          background-size: cover;
          }

          body {

              background: none;

          }

          .container {

              text-align: center;
              margin-top: 100px;
              width: 450px;

          }

          input {

              margin: 20px 0;

          }

          #weather {

              margin-top:15px;

          }

      </style>

  </head>
  <body>

      <div class="container">

          <h1>What's The Weather?</h1>



          <form>
  <fieldset class="form-group">
    <label for="city">Enter the name of a city.</label>
    <input type="text" class="form-control" name="city" id="city" placeholder="Eg. London, Tokyo" value = "<?php 

      if (array_key_exists('city', $_GET)) {

      echo $_GET['city']; 

      }

      ?>">
  </fieldset>

  <button type="submit" class="btn btn-primary">Submit</button>
</form>

          <div id="weather"><?php 

              if ($weather) {

                  echo '<div class="alert alert-success" role="alert">
  '.$weather.'
</div>';

              } else if ($error) {

                  echo '<div class="alert alert-danger" role="alert">
  '.$error.'
</div>';

              }

              ?></div>
      </div>

    <!-- jQuery first, then Bootstrap JS. -->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.2/js/bootstrap.min.js" integrity="sha384-vZ2WRJMwsjRMW/8U7i6PWi6AlO1L79snBrmgiDpgIWJ82z8eA5lenwvxbMV1PAh7" crossorigin="anonymous"></script>
  </body>
</html>

デバッグ

デバッグは下記を使用しましょう。
print_r();
var_dump();
echoは詳細まで出力してくれないので、上記2つを使いましょう。
実際にデバックしてみましょう。

index.php
<?php

    $weather = "";
    $error = "";

    if (array_key_exists('city', $_GET)) {
      $url_get=file_get_contents("https://api.openweathermap.org/data/2.5/weather?q=".$_GET['city'].",&appid=発行したAPIkey");

      print_r($url_get);//←ここ
      $dateArrer=json_decode($url_get,true);
      $weather=$_GET['city']."の天気:".$dateArrer['weather'][0]['main'].",".$dateArrer['weather'][0]['description'];

    }


?>

結果.
{"coord":{"lon":139.69,"lat":35.69},"weather":[{"id":803,"main":"Clouds","description":"broken clouds","icon":"04d"}],"base":"stations","main":{"temp":300.86,"feels_like":304.4,"temp_min":299.15,"temp_max":302.04,"pressure":1010,"humidity":88},"visibility":10000,"wind":{"speed":4.6,"deg":190},"clouds":{"all":75},"dt":1594364963,"sys":{"type":1,"id":8077,"country":"JP","sunrise":1594323209,"sunset":1594375158},"timezone":32400,"id":1850144,"name":"Tokyo","cod":200}

このハッシュで囲まれてるデータがJSON形式のデータとなります。
PHPでJSONデータをそのまま扱う事ができないので、json_decodeで
JSONデータを配列に変換します。

$dateArrer=json_decode($url_get,true);

結果

index.php
print_r($dateArrer);
Array ( [coord] => Array ( [lon] => 139.69 [lat] => 35.69 ) [weather] => Array ( [0] => Array ( [id] => 803 [main] => Clouds [description] => broken clouds [icon] => 04d ) ) [base] => stations [main] => Array ( [temp] => 300.86 [feels_like] => 301.97 [temp_min] => 299.82 [temp_max] => 301.48 [pressure] => 1010 [humidity] => 83 ) [visibility] => 10000 [wind] => Array ( [speed] => 7.2 [deg] => 170 ) [clouds] => Array ( [all] => 75 ) [dt] => 1594365866 [sys] => Array ( [type] => 1 [id] => 8063 [country] => JP [sunrise] => 1594323209 [sunset] => 1594375158 ) [timezone] => 32400 [id] => 1850144 [name] => Tokyo [cod] => 200 )

見事json_decode()で配列化に成功しました。
あとは欲しい情報をここから取ってくるだけです。

index.php
$weather=$_GET['city']."の天気:".$dateArrer['weather'][0]['main'].",".$dateArrer['weather'][0]['description'];
//$dateArrerの中の
//[weather]の[0]の[main]で天気が表示できます。

まとめ

今回はお天気APIを使用して、検索した首都の天気を表示させました。
JSONについて詳しく知りたい方は下記URLを閲覧してみてください。
https://reffect.co.jp/html/what_is_json

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

PHPでデータサイズを単位付きに変換する(KB・MBなど)

function byte_format($size = 0, $units=array('byte','KB','MB','GB','TB')) {
    for ($i = 0; 1024 < $size; $i++) {
        $size /= 1024;
    }
    return round($size) . ' ' . $units[$i];
}

これでどうでしょう?

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

PHP 関数とは?一緒にやってみましょう!!

最初に

これは初心者からフルスタックエンジニアを目指す男の備忘録である:point_up:

目次

⑴ 関数とは?
⑵ 関数で覚えておきたい3つのこと
⑶ ユーザ定義関数の基本的な書き方
⑷ 実際に関数を実行

⑴ 関数とは?

あるデータが返される(IN):point_left:
それに応じて
あるデータを返す(OUT)機能のこと:point_right:

2つに分けることができる
▶︎ 内部(ビルトイン)関数
 phpにデフォルトで用意されている関数。

▶︎ ユーザ定義関数
 独自に作成した関数

実際に使っていくことになるのは「ユーザ定義関数」になるかと思います。

⑵ 関数で覚えておきたい3つのこと

▶︎ 引数
 関数に渡されるデータのこと

▶︎ 仮引数
 関数に渡す際に変数のような箱を設置してあげるデータのこと

▶︎ 返り値(戻り値)
 関数から返ってくるデータのこと

⑶ ユーザ定義関数の基本的な書き方

▶︎ 関数を定義
 function 関数名(引数) {
    return 返り値;
}

↑ だけでは定義しただけなので実行を行う

▶︎ 関数を実行
  関数名(引数); 

これが基本的な書き方になる。
しっかりここを頭に入れておこう!

⑷実際に関数を実行

環境構築が面倒な方は、Paiza を使用することをおすすめ
URL: https://paiza.io/ja/projects/new

実戦に入る前にこれだけは注意。

※ 関数一つに一つの機能のみを持たせる
何故ならば、わかりやすくするためです。一つの関数にたくさんあったら訳が分からなくなってしまいますからね。

sum 関数を作ってみる
お題は「1〜10までを足した値を返す関数」です。

<?php
// 1〜10 までを足した値を返す関数
function sum(){
  
   // $result は結果を保存する変数    
    $result = 0;
   
   // $i は 1から始まり $max より大きくなるまでループする
    $for($i = 1; $i <=10; $i++){
       
   // $result に $i を順番に足していく
    $result += $i;
    }

    return $result;
}

?>

定義しました!
実際に実行してみます。

何も表示されない。。

何故なら、「関数を定義しただけ」だからです。
関数は定義しただけでなk、実行することで初めて呼び出すことが可能です。

それでは実際に呼び出してみたいと思います。

先ほどのコードに以下を入力

// 関数を実行する
echo sum();

もう一度実行

$ php sum.php
55

表示できました。٩( ᐛ )و
これは1から10までを足した結果が表示された訳です。

しかしこの関数では味気がない。。
1から10まで計算してくれる関数なんて使う要素が見当たらないです。

そしたら少し高性能にしてみたいと思います。

ここで使用するのは上記で説明した「仮関数」です。
実際にコードを書いてみます。

<?php
// 1〜$max までを足して結果を返す関数
function sum($max) {
    $result = 0;

    // $i は1から始まり、$max より大きくなるまでループする
    for($i = 1; $i <= $max; $i++ ){
        $result += $i;
    }

    return $result;
}

// 関数を実行
echo sum();
?>

できました٩( ᐛ )و
今回は sum 関数には仮引数の $max を設定したので、
幾つの値までを足すかを教えてあげる為に、実行するときに
$maxの値を教えておきます。

echo sum(100);

実行してみます。

$ php sum .php
5050
$

1から100までを足した値を計算することができました。٩( ᐛ )و

これで任務完了
楽しく学習それが
プログラミングを学ぶ醍醐味!!!

ではまた!

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

CarbonとCarbonImmutableのsetTestNowは別

テストのときに便利なsetTestNow()ですが、Carbon::setTestNow()CarbonImmutable::setTestNow()はそれぞれ効果が独立しています。

別の時刻に設定したいことはないと思うのですが、そういうものなようです。
CarbonImmutableにリファクタしたときにテストを直し忘れたのでメモ。

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

LaravelのGateでロール毎に権限を分ける

今回設定するrole

今回はレベル0が管理者でなんでも出来るユーザー。あとは1-4まで分けようと思います。
調査の段階なので、管理者と一般ユーザーとしてレベル4が分かれているのを確認できれば良しとします。
ちなみにプロジェクト名はappとしています。各ファイルのパスの最初に出てくるところがプロジェクトの名前になってますね。

開発環境

Laradockです。
PHP 7.4, MySQL 8.0, Laravel 6 で実行
構築は以下の手順で実施。
バージョンはそれぞれ自分が使いたい環境に合わせる。
https://qiita.com/ryuseino/items/e0e3a77245635b7cc101

カラム追加用のマイグレーションファイルを作成

今回はユーザーテーブルにroleを追加して、それを使ってアクセス出来るページを制御してみます。
まずはファイルを作成。

php artisan make:migration add_column_role_users_table --table=users

出来たファイル編集

app/database/migrations/2020_07_08_103224_add_column_role_users_table.php
    public function up()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->tinyInteger('role')->default(4)->after('password')->index('index_role')->comment('ロール');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->dropColumn('role');
        });
    }

ファイル編集が終わったらmigrate実行してカラムを追加しておきます。

 php artisan migrate

既存のファイルの編集

今回は管理者のみが見れるadmin-onlyと一般ユーザーでも見れるuser-higherを追加。

app/app/Providers/AuthServiceProvider.php
    protected $policies = [
        'App\Model' => 'App\Policies\ModelPolicy',
    ];

    /**
     * Register any authentication / authorization services.
     *
     * @return void
     */
    public function boot()
    {
        $this->registerPolicies();

        // adminに許可
        Gate::define('admin-only', function ($user) {
            return ($user->role == 0);
        });
        // 一般ユーザに許可
        Gate::define('user-higher', function ($user) {
            return ($user->role <= 5);
        });
    }

admin用のページ作成

今回は通常のHomeを複製してからファイル名やクラス名、読み込むviewなど変更します。
作ったファイルのパスは以下。中身は省略。基本的にhomeとなってたところをadminにしただけです。
viewの方は表示される文字列を変えておくと分かりやすくていいかも知れません。

app/app/Http/Controllers/AdminController.php
app/resources/views/admin.blade.php

管理者だけ見れる文字列をテンプレートに追加

ページ毎の制御ではなく、ページの内容も分けることが出来ます。
今回はHomeの方で管理者だけに表示されるメッセージを追加。

app/resources/views/home.blade.php
@extends('layouts.app')

@section('content')
    <div class="container">
        <div class="row justify-content-center">
            <div class="col-md-8">
                <div class="card">
                    <div class="card-header">Dashboard</div>

                    <div class="card-body">
                        @if (session('status'))
                            <div class="alert alert-success" role="alert">
                                {{ session('status') }}
                            </div>
                        @endif

                        You are logged in!
                        @can('admin-only')
                            <div class="alert alert-dark" role="alert">
                                管理者だけですよ
                            </div>
                        @endcan
                    </div>
                </div>
            </div>
        </div>
    </div>
@endsection

@can@endcanの間が管理者のみ表示されるメッセージですね。

ユーザーのroleを設定して確認

2つユーザー登録し、roleを片方は0(管理者)にして、もう片方は4(デフォルトのユーザーレベル)に設定。
その後それぞれのユーザーでログインします。

localhost/home にアクセスした場合

一般ユーザー -> デフォルトのホーム画面が出る
管理者 -> 追加で管理者用の文字列が出る

localhost/admin にアクセスした場合

一般ユーザー -> アクセス出来ない (403の画面)
管理者 -> アクセス出来る

参考にしたページ

以下のページが大変分かりやすかったです。
https://www.ritolab.com/entry/56

こちらはもう少し細かいところも書いてありますね。
https://readouble.com/laravel/6.x/ja/authorization.html

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

Slim3 Framework×slim-skeleton不使用×twigでプロジェクトを作成する(4.PDO使用)

はじめに

Slim3 Framework×slim-skeleton不使用×twigでプロジェクトを作成する
(3. LoggingとController)
の続きです。

前提

下記記事で構築した環境を前提とします。

  • Windows10にVagrantをを入れてCentOS7をインストールしよう(123456)
  • ローカルでLAMP環境を構築しよう(01234
  • CentOS7にComposerをインストールしよう

  • 私家版 Slim Framework チュートリアル (123456)
    @nunulkさんのチュートリアルを一通り。
    ここで作成したDBを使いまわします。

  • Slim3 Framework×slim-skeleton不使用×twigでプロジェクトを作成する(123

手順

1. 専用のユーザーを作成
2. プロジェクトディレクトリを作成・slim3インストール
3. 各種設定
4. DocumentRootを変更&表示確認
5. Twigを使ってみよう
6. Loggingしてみよう
7. Controllerを作成しよう
8. PDOを使用してデータベースに接続しよう
9. @nunulkさんのチュートリアルで作成したチケット管理システムをtwigを使って再現しよう

やってみよう

今回の記事では、手順8を行います。

8. PDOを使用してデータベースに接続しよう

settings.phpに設定を追加

以下の記述を追加します。

config/settings.php
$settings['db'] = [
  'driver' => 'mysql',
  'host' => 'localhost',
  'user' => 'root',
  'pass' => 'P@ssw0rd',
  'dbname' => 'slim_tutorial',
  'charset' => 'utf8',
  'collection' => 'utf8_unicode_ci',
  'flags' => [
    PDO::ATTR_PERSISTENT => false,
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
  ],
];

$settings['renderer'] = [
  'template_path' => __DIR__ . '/../templates/',
];

container.phpに設定を追加

以下の記述を追加します。

config/container.php
$container['db'] = function (Container $container) {
    $settings = $container->get('settings');

    $host = $settings['db']['host'];
    $dbname = $settings['db']['dbname'];
    $username = $settings['db']['user'];
    $password = $settings['db']['pass'];

    $dsn = "mysql:host=$host;dbname=$dbname";

    $options = [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_PERSISTENT => false,
        PDO::ATTR_EMULATE_PREPARES => true,
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
    ];

    return new PDO($dsn, $username, $password, $options);
};

$container['renderer'] = function (Container $c) {
    $settings = $c->get('settings')['renderer'];
    return new \Slim\Views\PhpRenderer($settings['template_path']);
};

routes.phpにルートを追加

以下の記述を追加します。

configroutes.php
$app->get('/tickets', function (Request $request, Response $response) {
    $sql = 'SELECT * FROM tickets';
    $stmt = $this->db->query($sql);
    $tickets = [];
    while($row = $stmt->fetch()) {
        $tickets[] = $row;
    }
    $data = ['tickets' => $tickets];
    return $this->renderer->render($response, 'index.phtml', $data);
});

@nunulkさんのチュートリアルで作成したチケット管理システムのチケット一覧だけ表示してみる

さて、ここまででDBに接続する準備はできました。
早速@nunulkさんのチュートリアルで作成したチケット管理システムのチケット一覧を表示して、
DBに接続できるか試してみましょう。

templatesディレクトリの下にticketsディレクトリを作成し、
事前に作っておいたファイルを以下のコマンドでコピーしてきましょう。
コピー元のパスはご自分の環境に置き換えてください。

index.phtmlコピー
cp /home/slimuser/projects/slim/Tutorial-First-Application/templates/tickets/index.phtml /home/slimuser/projects/slim/SampleApplication/templates/tickets/index.phtml
header.phtmlコピー
cp /home/slimuser/projects/slim/Tutorial-First-Application/templates/header.phtml /home/slimuser/projects/slim/SampleApplication/templates/header.phtml
footer.phtmlコピー
cp /home/slimuser/projects/slim/Tutorial-First-Application/templates/footer.phtml /home/slimuser/projects/slim/SampleApplication/templates/footer.phtml
helpers.phpコピー
cp /home/slimuser/projects/slim/Tutorial-First-Application/src/helpers.php /home/slimuser/projects/slim/SampleApplication/src/helpers.php

composer.jsonには下記を追記します。

composer.json
    "autoload": {
      "psr-4": {
        "App\\":"src/"
      }
      ,"files":["src/helpers.php"] ←追記
    },

composer.jsonを編集したので、下記コマンドを実行します。

composer dump-autoload

動作確認

ブラウザで以下のURLを開いてください。
以下の画像のように表示されたらOKです。

http://192.168.33.90/tickets

ticketindex.png

ついでに先程表示したチケット一覧をtwig化してみよう

base.twigを作成

@nunulkさんのチュートリアルではheader.phtmlとfooter.phtmlを作成し、
各ファイルから呼び出していましたが、せっかくtwigを使用するのでアプローチを変えてみましょう。
templates/base.twigというファイルを作成し、以下のように記述してください。

templates/base.twig
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="utf-8"/>
  <title>チケット管理</title>
  <link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet" type="text/css">
</head>
<body>
<div class="container">
  <h1>チケット管理</h1>
  {% block content %}{% endblock %}
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0/js/bootstrap.min.js"></script>
</body>
</html>

templates/base.twigという共通のテンプレートを作成し、
それぞれのファイルからtemplates/base.twigを呼び出し、
{% block content %}~{% endblock %}の中にそれぞれのメインコンテンツを記述します。

header.phtmlとfooter.phtmlはもう使用しないので削除しておきましょう。

rm templates/header.phtml
rm templates/footer.phtml

index.phtmlをtwig化

index.phtmlの拡張子をtwigに変更します。

mv /home/slimuser/projects/slim/SampleApplication/templates/tickets/index.phtml /home/slimuser/projects/slim/SampleApplication/templates/tickets/index.twig

templates/tickets/index.twigを以下のように変更します。

templates/tickets/index.twig(変更前)
<?= $this->fetch('header.phtml') ?>
  <div class="card">
    <div class="card-body">
      <h2 class="card-title">チケット一覧</h2>
      <div class="card-text">
        <a href="/tickets/create">新規作成</a>
        <ul class="list-group">
          <?php foreach($tickets as $ticket): ?>
            <li class="list-group-item">
              <a href="/tickets/<?= $ticket['id'] ?>">
                <?= e($ticket['subject']) ?>
              </a>
            </li>
          <?php endforeach ?>
        </ul>
      </div>
    </div>
  </div>
<?= $this->fetch('footer.phtml') ?>
templates/tickets/index.twig(変更後)
{% extends 'base.twig' %}
{% block content %}
  <div class="card">
    <div class="card-body">
      <h2 class="card-title">チケット一覧</h2>
      <div class="card-text">
        <a href="/tickets/create">新規作成</a>
        <ul class="list-group">
          {% for ticket in tickets %}
            <li class="list-group-item">
              <a href="/tickets/{{ticket.id}}">
                {{ticket.subject|escape('html')}}
              </a>
            </li>
         {% endfor %}
        </ul>
      </div>
    </div>
  </div>
{% endblock %}

helpers.php削除

helpers.phpから、htmlspecialchars関数を呼び出すようにしていましたが、
twigではhtmlspecialchars関数を使わないので、helpers.phpを以下のコマンドで削除しましょう。

rm src/helpers.php

composer.jsonからもhelpers.phpの記述を削除します。

composer.json(変更前)
    "autoload": {
      "psr-4": {
        "App\\":"src/"
      }
      ,"files":["src/helpers.php"]
    },
composer.json(変更後)
    "autoload": {
      "psr-4": {
        "App\\":"src/"
      }
    },

composer.jsonを編集したので、下記コマンドを実行します。

composer dump-autoload

routes.phpのルートを修正

以下の記述になるように修正します。

configroutes.php
$app->get('/tickets', function (Request $request, Response $response) {
    $sql = 'SELECT * FROM tickets';
    $stmt = $this->db->query($sql);
    $tickets = [];
    while($row = $stmt->fetch()) {
        $tickets[] = $row;
    }
    $data = ['tickets' => $tickets];
    return $this->get(Twig::class)->render($response, 'tickets/index.twig', $data);
});

動作確認

ブラウザで以下のURLを開いてください。
先程のチケット一覧画面が表示されたらOKです。

http://192.168.33.90/tickets

twig文法解説

今回使用したtwigの文法を解説します。

継承(extends)

twigではHTML全体を記述したベーステンプレートを用意して、
子テンプレートで上書きできる部分を blockタグで定義することができます。
今回はベーステンプレートがtemplates/base.twigtemplates/tickets/index.twigが子テンプレートです。
子テンプレートでは以下のように記述することでベーステンプレートを継承します。

{% extends 'ベーステンプレート名' %}

blockタグは以下のように記述します。
子テンプレートでは、ベーステンプレートで記述した同名のブロック名を持つblockタグ内にメインコンテンツを記述します。

{% block ブロック名 %}{% endblock %}

for文

Twig でループを作るには for 〜 in を用います。
{% for key, value in users %} のようにしてキー名を取り出すことも出来ます

{% for ticket in tickets %}
  // 処理
{% endfor %}

このような書き方も。

{% for i in 0..10 %}
  // 処理
{% endfor %}

HTMLエスケープ

phpのhtmlspecialchars関数でやっていたことはtwigでは以下のように記述します。

{{ ticket.subject|escape }}
または
{{ ticket.subject|e }}

デフォルトでhtmlエスケープを行いますが、コンテクストに応じたエスケープをしたい場合は、以下のように記述します。

{{ ticket.subject|e('html') }}
{{ ticket.subject|e('js') }}
{{ ticket.subject|e('css') }}
など

参考サイト

Creating your first Slim 3 Framework Application
私家版 Slim Framework チュートリアル (123456)
[PHP]Twigテンプレートの実践的な構成と作り方
Twig テンプレート
escape

関連ページ

Windows10にVagrantをを入れてCentOS7をインストールしよう

1. VagrantインストールからVagrantfileを設置まで
2. 仮想マシンの操作
3. WinSCP、Tera Termに秘密鍵でログイン
4. WinSCP、Tera Termにrootユーザーでパスワードログイン
5. zip/unzipをインストール
6. Vagrantにて仮想環境を配布

ローカルでLAMP環境を構築しよう

0. 事前準備
1. Apacheをインストール
2. MySQLをインストール
3. PHPをインストール
4. ファイアウォールとか停止する

Composerをインストール

CentOS7にComposerをインストールしよう

PHP Slim3フレームワークのサンプルアプリを作ろう

2-1. First Application Walkthrough Getting Set Upまで

Apache

DocumentRootを変更しよう

Slim3 Framework×slim-skeleton不使用×twigでプロジェクトを作成する

1. プロジェクト作成~各種設定
2. DocumentRoot変更~Twigを使用
3. LoggingとController
4.PDO使用

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

隣接都道府県・隣接県を配列で(都道府県コード準拠)

都道府県コード(PrefCode)に則り隣接県を示した配列。

地続き

$AdjacentPrefectures = [
    1 => [],
    2 => [3, 5,],
    3 => [2, 4, 5,],
    4 => [3, 5, 6, 7,],
    5 => [2, 3, 4, 6,],
    6 => [4, 5, 7, 15,],
    7 => [4, 6, 8, 9, 10, 15,],
    8 => [7, 9, 10, 11,],
    9 => [7, 8, 10, 11,],
    10 => [8, 9, 11, 15, 20,],
    11 => [8, 9, 10, 12, 13, 19, 20],
    12 => [11, 13,],
    13 => [11, 12, 14, 19],
    14 => [13, 19, 22],
    15 => [6, 7, 10, 16, 20,],
    16 => [15, 17, 20, 21],
    17 => [16, 18, 21,],
    18 => [17, 21, 25, 26],
    19 => [11, 13, 14, 20, 22,],
    20 => [10, 11, 15, 16, 19, 21, 22, 23,],
    21 => [16, 17, 18, 20, 23, 24, 25,],
    22 => [14, 19, 20, 23,],
    23 => [20, 21, 22, 24,],
    24 => [21, 23, 25, 26, 29, 30,],
    25 => [18, 21, 24, 26,],
    26 => [18, 24, 25, 27, 28, 29,],
    27 => [26, 28, 29, 30,],
    28 => [26, 27, 31, 33,],
    29 => [24, 26, 27, 30,],
    30 => [24, 27, 29,],
    31 => [28, 32, 33, 34,],
    32 => [31, 34, 35,],
    33 => [28, 31, 34,],
    34 => [31, 32, 33, 35,],
    35 => [32, 34,],
    36 => [37, 38, 39,],
    37 => [36, 38,],
    38 => [36, 37, 39,],
    39 => [36, 38,],
    40 => [41, 43, 44,],
    41 => [40, 42],
    42 => [41,],
    43 => [40, 44, 45, 46,],
    44 => [40, 43, 45,],
    45 => [43, 44, 46, ],
    46 => [43, 45, ],
    47 => [],
];
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravel ログイン時に処理を加える。

Laravel 5.5
PHP 7

ログインと同時に処理を行いたいと思い、
調べたのでここに記したいと思います。

vendor/laravel/framework/src/Illuminate/Foundation/Auth/AuthenticatesUsers.phpに
ログイン処理のリダイレクト直前で実行される authenticated() メソッドが書かれていますが、
何も設定されていません。

vendor/laravel/framework/src/Illuminate/Foundation/Auth/AuthenticatesUsers.php
/**
 * The user has been authenticated.
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  mixed  $user
 * @return mixed
 */

protected function authenticated(Request $request, $user)
{
    //
}

これをオーバーライドする形で処理を実装します。
LoginContorollerに処理を実装します。
例、
user情報のtypeが0の人がログインした場合
typeを20に設定するという処理を追加。

Auth/LoginController.php
use App\User;

protected function authenticated(\Illuminate\Http\Request $request, $user)
{
    if ($user->authority == 0) {
        $user->authority = 20;
        $user->save();
}

$requestには、ログイン画面で入力した、メールアドレス(又は、ユーザーネーム)とパスワードが代入されています。
$userには、Userテーブルのユーザー情報が代入されています(ログインユーザーの情報)。
※この変数名は固定です。仮にcustomerテーブルにユーザー情報を保存していたとしてもデータは、$userに代入されます。

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

配列はそのまま出力できません

なんとなく
phpで遊んでた時、

 $Pokemon = ['ヒトカゲ', 'ゼニガメ', 'フシギダネ'];

 echo $Pokemon;

配列一個用意してそのまま出力しようとした時

Array to string conversion

エラーが出た。

どうやら配列をそのまま出力できないらしい。

var_dump関数とprint_r関数を使う

var_dump($Pokemon);

//もしくは

print_r($Pokemon);

これで配列の中身が全部出力
var_dumpの方がより詳細に出る。

  array(3) {
  [0]=>
  string(12) "ヒトカゲ"
  [1]=>
  string(12) "ゼニガメ"
  [2]=>
  string(15) "フシギダネ"
}

値だけ出したかったら、

 foreach( $Pokemon as $p)
 echo $p . " ";

//出力結果
//ヒトカゲ ゼニガメ フシギダネ 

お馴染みのforeach文でOK

点と点が線でつながった気分。

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

yahooショッピングの商品パラメーターをJSON化する為にした事。

あるWEBツールを作るためにYahooショッピングの商品パラメーターが必要になったので

一旦、パラメーターをJSON化して使用することに。

行ったこと。

  1. スクレイピング
  2. JSONファイルを生成処理
  3. 生成したJSONをobjectとして使用。

尚、スクレイピングしている先がHTMLの変更があった場合、変更が必要になります。

スクレイピング先URL:https://developer.yahoo.co.jp/webapi/shopping/editItem.html

スクレイピング+JSONファイルを生成処理
<?php
$html = file_get_contents("https://developer.yahoo.co.jp/webapi/shopping/editItem.html");
$dom = new DOMDocument();
$html = mb_convert_encoding($html, "HTML-ENTITIES", 'UTF-8');
@$dom->loadHTML($html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
$xpath = new DOMXPath($dom);

try {
    $i = 0;
    $cnt = 2;
    while (isset($xpath->query("//*[@id=\"catchBx\"]/table[1]/tr[$cnt]/td[1]")->item(0)->textContent)) {
        preg_match("/[a-z|A-Z|0-9|_]{1,}/", $xpath->query("//*[@id=\"catchBx\"]/table[1]/tr[$cnt]/td[1]")->item(0)->textContent, $parameter);
        $patterns = array('/(\\\は)/u','/["]{1,}/u',"/[\n]{0,}/u");
        $replacements = array('\\\\\\は','\\\\"',"");
        $obj[] =
            "       \"Field" . $i . "\":{\n".
            "           \"parameter\":\"" . $parameter[0] . "\",\n" .
            "           \"value\":\"" . $xpath->query("//*[@id=\"catchBx\"]/table[1]/tr[$cnt]/td[2]")->item(0)->textContent . "\",\n" .
            //" \"comment\":\"" . mb_strimwidth(preg_replace($patterns,$replacements,$xpath->query("//*[@id=\"catchBx\"]/table[1]/tr[$cnt]/td[3]")->item(0)->textContent),0,250,"...") ."\"\n".
            "           \"comment\":\"" . preg_replace($patterns,$replacements,$xpath->query("//*[@id=\"catchBx\"]/table[1]/tr[$cnt]/td[3]")->item(0)->textContent) ."\"\n".
            "       }";
        $cnt++;
        $i++;
    }
    $res["json"] = "[\n {\n" . implode(",\n", $obj)."   }\n]\n" ;

    var_dump(file_put_contents("yahoo-item-data.json",$res["json"]));
    //echo json_encode($res);
} catch (\Throwable $th) {
    echo '[{{"json":"not data"}}]';
}
生成したJSONをobjectとして使用
<?php
$item = file_get_contents("yahoo-item-data.json");
$obj = (object)json_decode($item);

foreach($obj->{0} as $key=>$val){
    print "<br><br>[Field:".$key."]<br>";
    print "parameter:".$val->parameter."<br>";
    print "value:".$val->value."<br>";
    print "comment:".$val->comment."<br><br>";
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

自社システムからTrelloに起票する機能を実装

この記事では以下について実装方法を説明します。
・自社システム内で特定の操作をしたときにTrelloにカードを生成

機能を実装するために「Trello API」を使用します。
使うまでの手順を優しく説明します。
ちなみにここで使うものは全て以下の公式仕様書に記載されています。
https://developer.atlassian.com/cloud/trello/rest/api-group-actions/

まず先立って、先日投稿した記事の1~5の設定を完了してください。
https://qiita.com/localinnovation/items/8bbe268cab1a06572bdc

1.投稿したい対象ボードのIDを取得します。
コマンドプロンプトやターミナルで以下のコマンドを実行しましょう。

curl "https://trello.com/1/members/[ユーザ名]/boards?key=[上記記事の3で表示されたキー]&token=[上記記事の5で表示されたトークン]&fields=name"

6.png
「Trelloへようこそ」「テスト」という2つのボードが表示されました。
ここでは例として「テスト」のボードにしましょう。
「テスト」のidをコピーしておきます。

2.ターゲットとなるボードは取得できましたがどのリストにカードを作成するかについて、ここからはPHPの処理で行ってきたいと思います。
(作成先リストが決まっている場合は飛ばしてください。)
curlでリスト取得API(Get Lists on a Board)を叩き、リストIDを取得します。

        // ボードID
        $boardID = [でコピーしたid];

        // API キー
        $trelloApiKey = [上記記事の3で表示されたキー];

        // APIトークン
        $trelloApiToken = [上記記事の5で表示されたトークン];

        // リストの取得
        $getUrl = '';
        $getUrl = "https://api.trello.com/1/boards/" . $boardID . '/' . 'lists?key=' . $trelloApiKey . '&token=' . $trelloApiToken . '&fields=name';

        // 実行
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $getUrl);
        curl_setopt($ch, CURLOPT_HEADER, false);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        $response = curl_exec($ch);
        curl_close($ch);

        // リスト情報を検証
        $decodeResponseArr = json_decode($response);
        foreach($decodeResponseArr as $key=>$value){
            // $value['name']にリストの名前、$value['id']にリストのIDが入っている
            $value = get_object_vars($value);
            if([何らかの条件]){
                // リストのIDを設定
                $listId = $value['id'];
                break;
            }
        }

3.次に追加するメンバーを取得します。
(メンバーが決まっている場合は飛ばしてください。)
curlでリスト取得API(Get the Members of a Board)を叩き、メンバーIDを取得します。

        // ボードID
        $boardID = [でコピーしたid];

        // API キー
        $trelloApiKey = [上記記事の3で表示されたキー];

        // APIトークン
        $trelloApiToken = [上記記事の5で表示されたトークン];

        // メンバーの取得
        $getUrl = '';
        $getUrl = "https://api.trello.com/1/boards/" . $boardID . '/' . 'members?key=' . $trelloApiKey . '&token=' . $trelloApiToken;

        // 実行
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $getUrl);
        curl_setopt($ch, CURLOPT_HEADER, false);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        $response = curl_exec($ch);
        curl_close($ch);

        // メンバー情報を検証
        $decodeResponseArr = json_decode($response);
        foreach($decodeResponseArr as $key=>$value){
            // $value['fullName']にメンバーの名前、$value['id']にメンバーのIDが入っている
            $value = get_object_vars($value);
            if([何らかの条件]){
                // メンバーのIDを設定(複数の場合はカンマ区切り)
                $members .= $value['id'] . ',';
            }
        }
        // 末尾のカンマを削除
        $members = rtrim($members, ",");

4.次に追加するラベルを取得します。
(ラベルが決まっている場合は飛ばしてください。)
curlでラベル取得API(Get Labels on a Board)を叩き、ラベルIDを取得します。

        // ボードID
        $boardID = [でコピーしたid];

        // API キー
        $trelloApiKey = [上記記事の3で表示されたキー];

        // APIトークン
        $trelloApiToken = [上記記事の5で表示されたトークン];

        // ラベルの取得
        $getUrl = '';
        $getUrl = "https://api.trello.com/1/boards/" . $boardID . '/' . 'labels?key=' . $trelloApiKey . '&token=' . $trelloApiToken;

        // 実行
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $getUrl);
        curl_setopt($ch, CURLOPT_HEADER, false);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        $response = curl_exec($ch);
        curl_close($ch);

        // ラベル情報を検証
        $decodeResponseArr = json_decode($response);
        foreach($decodeResponseArr as $key=>$value){
            // $value['name']にラベルの名前、$value['id']にラベルのIDが入っている
            $value = get_object_vars($value);
            if([何らかの条件]){
                // ラベルのIDを設定(複数の場合はカンマ区切り)
                $labels .= $value['id'] . ',';
            }
        }
        // 末尾のカンマを削除
        $labels = rtrim($labels, ",");

5.次にいよいよカードを投稿します。
curlでカード作成API(Create a new Card)を叩きます。

        // ボードID
        $boardID = [でコピーしたid];

        // API キー
        $trelloApiKey = [上記記事の3で表示されたキー];

        // APIトークン
        $trelloApiToken = [上記記事の5で表示されたトークン];

        // カードの投稿
        $postUrl = "https://trello.com/1/cards";

        // POSTするデータ
        $postData  = "key=" . $trelloApiKey;
        $postData .= "&token=" . $trelloApiToken;
        $postData .= "&idList=" . $listId; // 2で設定したリストID
        $postData .= "&name=" . urlencode([カードのタイトル]); 
        $postData .= "&desc=" . urlencode([カードの説明]);
        $postData .= "&due=" . urlencode([カードの期限]); // 2020-07-10 19:00:00 のフォーマット
        $postData .= "&idMembers=" . $members; // 3で設定したメンバーID
        $postData .= "&idLabels=" . $labels; // 4で設定したラベルID

        $postUrl = $postUrl . '?' . $postData;

        // 実行
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $postUrl);
        curl_setopt($ch, CURLOPT_HEADER, false);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_POST, true);
        $response = curl_exec($ch);
        $httpcode = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
        curl_close($ch);

これでパシッとカード投稿ができました。
僕は実装苦労しましたが上記コードを使えば超簡単です。

ぜひやってみてください!

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

テスト記事

この記事はテストです。

index.html
<html>
<body>
</body>
</html>

こんな感じで書けばいいんだね。

けっこういい感じ。

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

Laravel クエリビルダを駆使する

目的

  • クエリビルダを用いたDBのデータ取得方法とテーブル結合を用いたデータん取得方法をまとめる

実施環境

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

前提環境

  • 先に記載した実施環境が構築されていること。
  • 実施環境にて何かしらのLaravelアプリが作成されていること。
  • Laravelアプリ用のDBが作成され.envファイルに必要情報が記載され、マイグレーションなどが行えること。

前提情報

  • contentsテーブルとstatusesテーブルを新たに作成し、テーブル内に格納されているデータをクエリビルダを用いて取得する。
  • コードの解説は本記事の下部の「ミニ解説」にてちょっとだけ解説している。

読後感

  • contentsテーブルの内容をクエリビルダを用いて取得する。
  • contentsテーブルとstatusesテーブルを結合し内容をクエリビルダを用いて取得する。

クエリビルダとは?

  • LaravelのDBアクセスの手法の一つである。
  • クエリ文を先に組み立ててからDBにアクセスする方法である。
  • 使用する句はSQLと共通であるが記載方法に若干のクセがある。

概要

  1. contentテーブルの作成
  2. statusesテーブルの作成
  3. ルーティングの記載
  4. コントローラの作成と記載(クエリビルダの記載)
  5. ビューの作成と記載
  6. データの格納
  7. クエリビルダ単体の確認
  8. JOIN句の確認

詳細

  1. contentテーブルの作成

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

      $ php artisan make:model Content --migration
      
    2. アプリ名ディレクトリで下記コマンドを実行してマイグレーションファイルを開く。

      $ vi database/migrations/YYYY_MM_DD_XXXXXX_create_contents_table.php
      
    3. 開いたマイグレーションファイルを下記の様に追記修正する。

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

      $ php artisan migrate
      
  2. statusesテーブルの作成

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

      $ php artisan make:model Status --migration
      
    2. アプリ名ディレクトリで下記コマンドを実行してマイグレーションファイルを開く。

      $ vi database/migrations/YYYY_MM_DD_XXXXXX_create_statuses_table.php
      
    3. 開いたマイグレーションファイルを下記の様に追記修正する。

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

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

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

      $ vi routes/web.php
      
    2. 下記の一行を追記する。

      アプリ名ディレクトリ/routes/web.php
      Route::get('/output', 'ContentController@output');
      
  4. コントローラの作成と記載(クエリビルダの記載)

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

      $ php artisan make:controller ContentController
      
    2. アプリ名ディレクトリで下記コマンドを実行してコントローラファイルを開く。

      $ vi app/Http/Controllers/Controller.php
      
    3. 下記の様にoutputという名前のアクションを追加する。

      アプリ名ディレクトリ/app/Http/Controllers/Controller.php
      <?php
      
      namespace App\Http\Controllers;
      
      use Illuminate\Http\Request;
      //下記を追記
      use App\Content;
      
      class ContentController extends Controller
      {
          //下記を追記
          public function output()
          {
              $contents_query = Content::select('*');
              $contents = $contents_query->get();
              return view('contents.output', [
                  'contents' => $contents,
              ]);
          }
          //上記までを追記
      }
      
  5. ビューの作成と記載

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

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

      $ vi resources/views/contents/output.blade.php
      
    3. ビューファイルに下記を記載する。

      アプリ名ディレクトリ/resources/views/contents/output.blade.php
      @foreach ($contents as $content)
          <hr>
          <p>{{$content['content']}}</p>
          <p>{{$content['status']}}</p>
      @endforeach
      
  6. データの格納

    1. アプリ名ディレクトリで下記コマンドを実行してtinkerを開く。

      $ php artisan tinker
      
    2. tinkerにて下記を実行してcontentsテーブルにデータを追加する。

      use App\Content;
      $a = new Content();
      $a->content = 'test';
      $a->status_id = 1;
      $a->save();
      
    3. tinkerにて下記を実行してstatusesテーブルにデータを追加する。

      use App\Status;
      $b = new Status();
      $b->status_name = 'good'
      $b->save();
      $c = new Status();
      $c->status_name = 'bad'
      $c->save();
      
  7. クエリビルダ単体の確認

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

      $ php artisan serve
      
    2. 下記にアクセスし、ブラウザから当該アプリを確認する。

    3. 下記の様にブラウザで表示されることを確認する。

      127_0_0_1_8000_output.png

  8. JOIN句の確認

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

      $ vi app/Http/Controllers/Controller.php
      
    2. 開いたコントローラファイルのoutputアクション内部を下記の様に修正する。

      アプリ名ディレクトリ/app/Http/Controllers/Controller.php
      <?php
      
      namespace App\Http\Controllers;
      
      use Illuminate\Http\Request;
      use App\Content;
      
      class ContentController extends Controller
      {
          public function output()
          {
              $contents_query = Content::select('*');
              //下記を追記
              $contents_query->join('statuses', 'contents.status_id', '=', 'statuses.id');
              $contents = $contents_query->get();
              return view('contents.output', [
                  'contents' => $contents,
              ]);
          }
      }
      
    3. アプリ名ディレクトリで下記コマンドを実行してビューファイルを開く。

      $ vi resources/views/contents/output.blade.php
      
    4. ビューファイルに下記を下記の様に修正する。

      アプリ名ディレクトリ/resources/views/contents/output.blade.php
      @foreach ($contents as $content)
          <hr>
          <p>{{$content['content']}}</p>
          <!-- 下記を追記 -->
          <p>{{$content['status_name']}}</p>
      @endforeach
      
    5. 下記にアクセスし、ブラウザから当該アプリを確認する。

    6. 下記の様にブラウザで表示されることを確認する。

      127_0_0_1_8000_output.png

ミニ解説

「クエリビルダ単体の確認」のアクション内のコードについて

  • 下記にコントローラのアクションのコードを記載する。

    アプリ名ディレクトリ/app/Http/Controllers/Controller.php
    public function output()
    {
        //DBにアクセスするためのクエリ文を組み立てている
        //Contentというモデルファイルに紐づいたテーブルの全てのカラムを取得する(SQL文のselect *と同じ)クエリ文を変数$contents_queryに格納している
        $contents_query = Content::select('*');
        //先に組み立てたクエリ文を実行して取得したデータを変数$contentsに格納している。
        $contents = $contents_query->get();
        return view('contents.output', [
            'contents' => $contents,
        ]);
    }
    

「JOIN句の確認」のアクション内のコードについて

  • 下記にコントローラのアクションのコードを記載する。

    アプリ名ディレクトリ/app/Http/Controllers/Controller.php
    public function output()
    {
        //DBにアクセスするためのクエリ文を組み立てている
        //Contentというモデルファイルに紐づいたテーブルの全てのカラムを取得する(SQL文のselect *と同じ)クエリ文を変数$contents_queryに格納している
        $contents_query = Content::select('*');
        //テーブルの結合を行う
        //クエリ文が格納されている変数->join('結合するテーブル名', '結合元テーブル名.結合するカラム名', '=', '結合先テーブル名.リンクするカラム名')
        $contents_query->join('statuses', 'contents.status_id', '=', 'statuses.id');
        //先に組み立てたクエリ文を実行して取得したデータを変数$contentsに格納している。
        $contents = $contents_query->get();
        return view('contents.output', [
            'contents' => $contents,
        ]);
    }
    
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

データプロバイダでテストに値を入れる

phpunitのデータプロバイダについての基本的な使い方のメモです。
PHPUnit 用のテストの書き方

データプロバイダとは

同じアサーションで値だけ変えたい場合にデータプロバイダを使うと便利です。
テストに値を与える部分を別のメソッドに切り出すことができます。

データプロバイダの配列の中身が引数としてテストメソッドに渡され、メソッド内の配列の分だけアサーションが反復処理されます。

下の例ではassertSame()が4回呼ばれることになります。

<?php
use PHPUnit\Framework\TestCase;

class DataTest extends TestCase
{
    /**
     * @dataProvider additionProvider
     */
    public function testAdd($a, $b, $expected)
    {
        $this->assertSame($expected, $a + $b);
    }

    public function additionProvider()
    {
        return [
            [0, 0, 0],
            [0, 1, 1],
            [1, 0, 1],
            [1, 1, 3]
        ];
    }
}

@dataProviderアノテーションでデータプロバイダメソッドを指定します。

/**
 * @dataProvider additionProvider
 */

データプロバイダーの返り値は配列にする必要があります。

return [
    [0, 0, 0],
    [0, 1, 1],
    [1, 0, 1],
    [1, 1, 3]
];

各データセットに名前を付ける

データセットには名前を付けることができます。テストに失敗した場合、データセットの名前が表示されるため、どのデータで失敗したのかわかりやすくなります。

<?php
use PHPUnit\Framework\TestCase;

class DataTest extends TestCase
{
    /**
     * @dataProvider additionProvider
     */
    public function testAdd($a, $b, $expected)
    {
        $this->assertSame($expected, $a + $b);
    }

    public function additionProvider()
    {
        return [
            'adding zeros'  => [0, 0, 0],
            'zero plus one' => [0, 1, 1],
            'one plus zero' => [1, 0, 1],
            'one plus one'  => [1, 1, 3]
        ];
    }
}
$ phpunit DataTest
PHPUnit 4.6.0 by Sebastian Bergmann and contributors.

...F

Time: 0 seconds, Memory: 5.75Mb

There was 1 failure:

1) DataTest::testAdd with data set "one plus one" (1, 1, 3)
Failed asserting that 2 is identical to 3.

/home/sb/DataTest.php:9

FAILURES!
Tests: 4, Assertions: 4, Failures: 1.
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む