投稿者: raika

  • 【PHP】曜日を日本語で表示する

    こんにちは、らいか(@hideiwa1)です。

    今回は、PHPで日時を扱うときに「曜日を日本語で表示する」方法を解説します。

    日時の取得

    日時から日本語の曜日を表示させるには、以下の手順が必要となります。

    ・日時を取得する

    ・曜日を取得する

    ・曜日を日本語へ変換する

    まずは、日時の取得をしましょう。
    今回はDateTimeクラスを使用して解説します。

    
      $date = new DateTime();  // 現在日時の取得

    今回は現在日時で進めますが、日付を指定する場合は以下のように、引数に日時を指定してください。

    
      $date = new DateTime('2011-01-23 11:34:21');  // 指定日時の取得
    https://wp.festina-rente.com/get-the-date/

    曜日を取得する

    次に、取得した日時から曜日を取得します。
    曜日を取得するには、->format(‘w’) を使用します。

    フォーマット文字の “w” は、曜日を数字で取得することが出来ます。
    返り値は 0「日曜」 ~ 6「土曜」 となります。

    
      $data-week = $data -> format("w");  // 曜日の取得

    ちなみに、英語で表示させる場合はフォーマット文字の “l(小文字の’L’)” や “D” を使用してください。

    曜日を日本語へ変換する

    次に、取得した曜日の数字から日本語へ変換します。
    方法は簡単で、以下の2つです

    ・0~6の数字に対応した曜日の配列を用意する

    ・取得した数字の曜日を呼び出す

    
      $week = ["日曜", "月曜", "火曜", "水曜", "木曜", "金曜", "土曜"];  
      // 0~6に対応した曜日の配列を用意
      
      $week-jp = $week[$data-week];
      // 曜日の数字に対応した配列を取得
    
      echo $week-jp  // 曜日の表示

    これで日時から、日本語の曜日を表示させることが出来ました。

    まとめ

    $week = [“日曜”, “月曜”, “火曜”, “水曜”, “木曜”, “金曜”, “土曜”];

    $data = new DateTime();
    $data-week = $data -> format(“w”);

    $week-jp = $week[$data-week];

  • 【PHP】2038年問題を回避する

    こんにちは、らいか(@hideiwa1)です。

    今回は、日時を扱う上で問題となる、「2038年問題」について解説します。

    2038年問題とは

    2038年問題とは、date() 関数を使用した時に、2038年以降の日時がエラーとなる問題です。

    伝統的なシステムでは、Unixタイムスタンプは「符号つき32ビットの整数型」とされています。
    符号つき32ビットの整数型では、「-2,147,483,647  ~ 2,147,483,647 」の数字が表現できます。
    そして、Unixタイムスタンプで 2,147,483,647 は「2038年1月19日3時14分7秒」となります。

    「2038年1月19日3時14分7秒」を過ぎた場合、数値がオーバーフローしてマイナスの値を示すことになります。

    011111111111111111111111111111112,147,483,6472038年1月19日3時14分7秒
    10000000000000000000000000000000-2,147,483,6481901年12月13日20時45分52秒

    つまり、「2038年1月19日3時14分7秒」の1秒後は「1901年12月13日20時45分52秒」と認識されることになります。
    これでは、システムに不具合が発生するのは明らかです。

    回避する方法

    64ビット対応のシステムを使用する

    1つ目の解決策は、「64ビット」に対応したシステムを使用することです。

    基本的に、最近のOSでは64ビットに対応しています。
    それに伴い、PHPも64ビットで使用することが出来る為、「2038年問題」は問題となりません。

    しかし、何らかの事情でシステムの入れ替え・更新が出来ないケースもあり得ます。
    その場合、32ビットのシステムで対応をせざるを得なくなります。

    そのようなケースに対応するには、次のDateTimeクラスを使用する必要があります。

    DateTimeクラスを使用する

    DateTimeクラスでは、日時を「年、月、日、時、分、秒…」などと個別のデータとして扱っています。
    そのため、「秒」のみを基準とするUnixタイムスタンプの問題は発生しません。

    date() 関数で行えることは、基本的にDateTimeクラスでも行えるため、特段の理由がない限り「DateTimeクラス」を使用する方が安全といえます。

    まとめ

    PHPで日時を扱う場合は、「DateTimeクラス」を使用する。

  • 【PHP】日付を取得、表示する

    こんにちは、らいか(@hideiwa1)です。

    今回は、PHPで日付や時間を取得する方法を解説します。

    日付の形式

    日付の形式には、「英文形式」と「Unixタイムスタンプ」の2種類があります。

    英文形式
    “2022-01-01” のような、文字列型での表記

    Unixタイムスタンプ
    ”協定世界時(UTC)での1970年1月1日午前0時0分0秒からの形式的な経過秒数”
    “1640962800” のような、整数型での表記

    date()関数で日付を扱う

    現在の日付を取得する

    まずは、date()関数を使った、日付の取り扱いを見ていきましょう。

    date(‘フォーマット’ [, Unixタイムスタンプ])
    []は省略可能

    第2引数のタイムスタンプを省略した場合、現在日時を取得します。
    フォーマットに関しては、下記の文字が使用できます。

    Y4桁の数字2022
    y2桁の数字22
    L閏年かどうか(閏年なら1、それ以外は0)1 or 0
    Fフルスペルの英語January
    M3文字の英語Jan
    m0を付けた数字01
    n0を付けない数字1
    l(小文字の’L’)フルスペルの英語(曜日)Monday
    D3文字の英語(曜日)Mon
    d0を付けた数字01
    j0を付けない数字1
    H24時間単位、0を付ける00
    G24時間単位、0を付けない23
    h12時間単位、0を付ける01
    g12時間単位、0を付けない12
    i0を付けた数字00
    s0を付けた数字00
    
      date('Y/m/d H:i:s');  // 2022/05/08 22:24:02
      date('y年n月j日');  //22年5月8日
      date('F Y h:i:s');  //May 2022 10:24:02

    任意の日付をフォーマットする

    先ほどは現在の日付を扱いましたが、今度は任意の日付を扱ってみましょう。
    例えば、DBから取得した日付をフォーマットしたい場合などです。

    この場合、日付は基本的に英文形式で設定されていると思うので、こちらをUnixタイムスタンプへ変換する必要があります。
    Unixタイムスタンプへの変換は、strtotime() 関数を使用します。

    strtotime(‘日付’); // 英文形式からUnixタイムスタンプへ変換

    そして、先ほど使用したdate() 関数を使用してフォーマットを行います。
    date() 関数で日付を指定するには、第2引数にUnixタイムスタンプを指定します。

    
      $data = '2019-02-27';
    
      date('Y年n月j日' , strtotime($data) );  // 2019年2月27日

    date() 関数の注意点

    date() 関数で日付を取得、表示する方法を解説してきましたが、date() 関数には1つ問題があります。
    それが、「2038年問題」です。

    date() 関数がUnixタイムスタンプを使用している関係で、扱える数字に桁数の制限があります。
    そのため、2038年以降の日付はエラーとなって取り扱うことが出来ません。

    この問題を回避するためには、後述のDateTimeクラスを使用する必要があります。

    DateTimeクラスで日付を扱う

    現在の日付を取得する

    次は、DateTimeクラスを使用した日付の扱いを見てみましょう。

    DateTimeクラスを使用してDateTimeオブジェクトを作成し、そのオブジェクトを元にフォーマットなどを行っていきます。

    詳しくはオブジェクト指向の概念を理解する必要がありますが、日付の扱いだけであれば、それほど難しくはないと思います。

    $date = new DateTime(‘日付’);
    日付からDateTimeオブジェクトを作成、省略した場合は現在日時で作成

    $date -> format(‘フォーマット’); // 日時をフォーマットに変換

    まずは new DateTime() で新しいDateTimeオブジェクトを作成します。
    この際に日付を指定しなければ、現在の日付でオブジェクトが作成されます。

    次に、->format() で表示形式を指定します。
    フォーマットに関しては、date() 関数と同じ文字が使用できます。

    
      $date = new DateTime();
    
      $date->format('Y/m/d H:i:s');  // 2022/05/08 22:24:02
      $date->format('y年n月j日');  //22年5月8日
      $date->format('F Y h:i:s');  //May 2022 10:24:02

    任意の日付をフォーマットする

    次に、任意の日付を扱う場合です。

    DateTimeオブジェクトを作成する際に、日付を引数に指定します。
    date() 関数のように、Unixタイムスタンプではなく、英文形式の日付で指定します。

    
      $date = new DateTime('2019-02-27');
    
      $date->format('Y年n月j日');  // 2019年2月27日

    まとめ

    $date = date(‘フォーマット’); // 現在の日付
    $date = date(‘フォーマット’, strtotime(‘日付’)); // 指定の日付

    $date = new DateTime(); // 現在の日付
    $date = new DateTime(‘日付’); // 指定の日付
    $date -> format(‘フォーマット’); //フォーマット

  • 【PHP】文字列が含まれているか検索をする

    こんにちは、らいか(@hideiwa1)です。

    今回は、変数に特定の文字列が含まれているか、部分一致で検索する方法について解説します。

    文字列から検索する

    まずは、文字列に検索する文字列が含まれているかを検索する方法を紹介します。

    strpos()

    1つ目は、strpos()です。
    文字列の中を検索し、最初に現れる位置を返します。

    strpos(‘検索対象の文字列’、’検索したい文字列’)

    返り値は、検索した文字が最初に現れる位置(数字)
    見つからない場合は false を返します

    
      $haystack = 'abcdefgh';  //検索対象
      $needle = 'abc';  //検索したい文字列
    
      $result = strpos($haystack, $needle);  // 0
    
      $needle-2 = 'cd';  //検索したい文字列
    
      $result-2 = strpos($haystack, $needle-2);  // 2
    
      $needle-3 = 'xw';  //検索したい文字列
    
      $result-3 = strpos($haystack, $needle-3);  // false

    注意点としては、先頭で見つかった場合、返り値は 0 となる点です。
    if文で判定する場合、0 は false と判定されるため、‘===’で型まで判定する必要があります。

    
      $haystack = 'abcdefgh';  //検索対象
      $needle = 'abc';  //検索したい文字列
    
      $result = strpos($haystack, $needle);  // 0
    
      if($result)
      {
          echo '見つかりました。';  // こちらは表示されない
      }
    
      if($result !== false)
      {
          echo '見つかりました。';  // こちらは表示される
      }

    str_contains()

    2つ目は、str_contains()を使う方法です。
    文字列が含まれるかを true / false で返します。

    str_contains(‘検索対象の文字列’、’検索したい文字列’)

    返り値は、見つかった場合は true 、見つからない場合は false を返します

    
      $haystack = 'abcdefgh';  //検索対象
      $needle = 'abc';  //検索したい文字列
    
      $result = str_contains($haystack, $needle);  // true
    
      $needle-2 = 'xw';  //検索したい文字列
    
      $result-2 = strpos($haystack, $needle-2);  // false

    前述の strpos() に比べて、型の判定を行わなくて良いのがメリットです。

    注意点として、対応はPHP8以降となります。

    preg_match()

    3つ目は preg_match() です。
    こちらは正規表現を使って検索することが出来ます。

    preg_match(‘検索したい文字列’、’検索対象の文字列’)

    返り値は、見つかった場合は 1 、見つからない場合は 0 を返します。
    失敗した場合は false を返します。

    
      $subject = "abcdef";
      $pattern = '/def/';
      
      preg_match($pattern, $subject)  // 1
    
      $pattern-2 = 'def';
      
      preg_match("/$pattern-2/", $subject)  // 1

    注意点として、検索する文字にはデリミタ(区切り文字、一般的には’/’)を含む必要があります。
    もし変数内の文字を使用したい場合、$pattern-2 のように “/変数名/” とする必要があります。

    preg_match() は多少速度が遅くなるため、正規表現を使わない場合はstrpos() や str_contains() を使用しましょう。

    配列から検索する

    次は、配列の中に検索する文字列が含まれているかを検索する方法を紹介します。

    preg_grep()

    配列から部分一致で検索するには、preg_grep() を使用します。
    正規表現を使用して検索し、一致するカラムを返します。

    preg_grep(‘検索したい文字列’、’検索対象の文字列’)

    返り値は、見つかった場合はカラムを返します。
    失敗した場合は false を返します。

    
      $array = ['abcde', 'fghi', 'jklmn'];  //検索対象
      $patten = 'bc';  //検索したい文字列
    
      preg_grep("/$pattern/", $array);  // ['abcde']
    

    注意点として、preg_match() と同様に、検索する文字にはデリミタ(区切り文字、一般的には’/’)を含む必要があります。

    まとめ

    文字列から部分一致検索
    ・strpos(‘検索対象の文字列’、’検索したい文字列’)
    ・str_contains(‘検索対象の文字列’、’検索したい文字列’) *PHP8以降

    配列から部分一致検索
    ・preg_grep(‘検索したい文字列’、’検索対象の文字列’)

  • 【laravel】N+1問題について考える

    こんにちは、らいか(@hideiwa1)です。

    今回は、DBを扱う上で注意するべき「N+1問題」について解説します。

    N+1問題とは

    リレーションを使用する場合、関連するモデルには「遅延読み込み」という特性があります。
    「遅延読み込み」とはどういう事かというと、

    プロパティにアクセスされるまで、データを取得しない

    つまり、リレーションをしただけではクエリを実行しないという事です。

    実際のコードで、どのような事が起きるのかを見てみましょう。

    「User」と「Item」が「1対多」でリレーションしているとします。
    このとき、すべてのuserとitemを取得すると、以下の通りになります。

    
      $user = User::all();
    
      foreach($users as $user)
      {
          $user->items;
      }

    この時、どのようなクエリが実行されているかというと、

    
      select * form Users;
      
      select * from Items where Items.user_id = 1 and Items.user_id is not null;
      select * from Items where Items.user_id = 2 and Items.user_id is not null;
      …

    このように、

    ・まず「users」テーブルより全件を取得
    ・次に、user_id毎に「Items」テーブルから一致するものを取得

    という流れになっています。

    この時、「users」が全10件あったとすると、

    ・「users」テーブルより全件を取得 → 1回
    ・user_id毎に「Items」テーブルから一致するものを取得 → 1~10で10回

    合計で11回、クエリを実行することになります。
    これが「N+1問題」となります。
    (10件を取得するのに、11回クエリを実行する)

    解決方法は?

    正直なところ、対象が10件程度でしたらそれほど影響はありません。
    しかし、これが100件、1000件と増えた場合はどうでしょうか?

    クエリの数が多くなれば、その分処理速度が低下することになります。
    そのため、基本的にN+1問題は避けなければなりません。

    N+1問題の解決方法は、「with」メソッドを使用する方法です。

    withメソッドには、「Eagerロード(積極的読み込み)」という特徴があります。
    Eagerロードでは、データが事前に取得されます。

    先ほどと同じ例を使って、流れを見てみましょう。

    
      $user = User::with('item')->get();
    
      foreach($users as $user)
      {
          $user->items;
      }

    この際に実行されるクエリは、

    
      select * form Users;
      
      select * from Items where Items.user_id in (1, 2, ・・・);

    このように、

    ・まず「users」テーブルより全件を取得
    ・次に、「Items」テーブルから全件を取得

    と、2つへ削減されました。
    そして、件数が増えてもクエリが増えることはありません。

    まとめ

    リレーションをする場合は、「with」メソッドを使用する方が良い。

  • 【laravel】リレーションの基本

    こんにちは、らいか(@hideiwa1)です。

    今回は、laravelでテーブル同士を関連付ける「リレーション」の使い方を解説します。
    これにより、関連するテーブル同士の扱いが容易になります。

    リレーションとは

    複数のテーブルを扱う場合、テーブル同士が関連していることがあります。
    例えば、「ユーザー」と「買った商品」、「商品」と「商品のカテゴリー」などです。

    usersテーブル

    idname
    1山田
    2加藤
    3鈴木
    4佐々木

    itemsテーブル

    idnameuser_id
    1りんご2
    2みかん4
    3バナナ1
    4ぶどう3

    例えばこのような、「ユーザー」と「買った品物」のテーブルがあったとします。

    リレーションを使わない場合、ユーザーの名前と買った品物を取得するには次のようになります。

    
      $user_id = 1;
      $user = User::find($user_id);
      $user_name = $user->name;  //名前の取得
    
      $item = Item::where('user_id', '=', $user_id) -> get();
      $item_name = $item->name; //品物名の取得

    これをリレーションを使用すると、次のように簡潔に書くことが出来ます。

    
      $user_id = 1;
      $user = User::find($user_id);
      $user_name = $user->name;  //名前の取得
    
      $item_name = $user->item->name  //品物名の取得

    リレーションの設定

    では、実際にリレーションの設定をしていきましょう。

    まず、テーブル同士の関係には大きく分けて「1対1」、「1対多」、「多対多」の3種類があります。

    1対1

    「1対1」の関係は、1つのモデルが1つのモデルと関連している状態です。
    例えば、「users」テーブルの1人のユーザーが、「items」テーブルの1つの品物とのみ関連している状態です。

    usersテーブル

    idname
    1山田
    2加藤
    3鈴木
    4佐々木

    itemsテーブル

    idnameuser_id
    1りんご2
    2みかん4
    3バナナ1
    4ぶどう3

    この状態では、1つのユーザーは、1つの品物とだけ関係しています。
    また、1つの品物も、1つのユーザーとだけ関係があります。

    この時、「users」テーブルが「親」、「items」テーブルが「子」となります。
    (「子」テーブルには、「親」テーブルのIDを持つ必要があります。)

    この場合のリレーションの設定は、各モデル内で次のように行います。

    
      app/Models/User.php  //親モデル
    
      namespace App\Models;
    
      use Illuminate\Database\Eloquent\Model;
    
      class User extends Model
      {
          /**
           * ユーザーに関連している品物の取得
           */
          public function item()
          {
              return $this->hasOne(Item::class);
          }
      }
    
      app/Models/Item.php  //子モデル
    
      namespace App\Models;
    
      use Illuminate\Database\Eloquent\Model;
    
      class Item extends Model
      {
          /**
           * 品物に関連しているユーザーの取得
           */
          public function user()
          {
              return $this->belongsTo(User::class);
          }
      }

    「親」→「子」へのリレーションには「hasOne()
    「子」→「親」へのリレーションには「belongsTo()

    この設定により、モデルからリレーション先のモデルを呼び出すことが出来ます。
    さらに、リレーション先のモデルのプロパティを呼び出すことも可能です。

    
      $item = User::find(1)->item;
      $item_name = User::find(1)->item->name;

    1対多

    次に「1対多」の関係です。
    こちらは、1つのモデルが複数のモデルと関連している状態です。
    例えば、「users」テーブルの1人のユーザーが、「items」テーブルの複数の品物と関連している状態です。

    usersテーブル

    idname
    1山田
    2加藤
    3鈴木
    4佐々木

    itemsテーブル

    idnameuser_id
    1りんご1
    2みかん2
    3バナナ1
    4ぶどう3

    この状態では、1つのユーザーは、複数の品物と関係しています。
    また、1つの品物は、1つのユーザーとだけ関係があります。

    この時、「users」テーブルが「親」、「items」テーブルが「子」となります。
    (「子」テーブルには、「親」テーブルのIDを持つ必要があります。)

    この場合のリレーションの設定は、各モデル内で次のように行います。

    
      app/Models/User.php  //親モデル
    
      namespace App\Models;
    
      use Illuminate\Database\Eloquent\Model;
    
      class User extends Model
      {
          /**
           * ユーザーに関連している品物の取得
           */
          public function items()  // 複数形
          {
              return $this->hasMany(Item::class);
          }
      }
    
      app/Models/Item.php  //子モデル
    
      namespace App\Models;
    
      use Illuminate\Database\Eloquent\Model;
    
      class Item extends Model
      {
          /**
           * 品物に関連しているユーザーの取得
           */
          public function user()
          {
              return $this->belongsTo(User::class);
          }
      }

    「親」→「子」へのリレーションには「hasMany()
    *メソッド名は複数形

    「子」→「親」へのリレーションには「belongsTo()
    *メソッド名は単数形

    「1対1」の時と変わって、親モデルのメソッドが「複数形」になっているのに注意です。
    これは、1つのユーザーに対して複数の子モデルが関連しているためです。

    そのため、各プロパティにアクセスするにはforeachなどで各配列ごとにする必要があります。

    
      $items = User::find(1)->items;
      foreach(User::find(1)->items as $item)
      {
          $item_name[] = $item->name;
      }

    多対多

    次に「多対多」の関係です。
    こちらは、複数のモデルが複数のモデルと関連している状態です。
    例えば、「users」テーブルの1人のユーザーが、「items」テーブルの複数の品物と関連している状態です。
    さらに、「items」テーブルの1つの品物も、「users」テーブルの複数のユーザーと関連しています。

    usersテーブル

    idname
    1山田
    2加藤
    3鈴木
    4佐々木

    item_userテーブル

    idname
    1りんご
    2みかん
    3バナナ
    4ぶどう

    itemsテーブル

    user_iditem_id
    11
    14
    22
    21

    この状態では、1つのユーザーは、複数の品物と関係しています。
    また、1つの品物は、複数のユーザーと関係があります。

    この場合は、2つのテーブルを結びつける「中間テーブル」が必要になります。
    中間テーブルは2つのモデルを「_(アンダースコア)」でつなげます。
    また、要素に「(モデル名)_id」のカラムを持たせます。

    この場合のリレーションの設定は、各モデル内で次のように行います。

    
      app/Models/User.php 
    
      namespace App\Models;
    
      use Illuminate\Database\Eloquent\Model;
    
      class User extends Model
      {
          /**
           * ユーザーに関連している品物の取得
           */
          public function items()  // 複数形
          {
              return $this->belongsToMany(Item::class);
          }
      }
    
      app/Models/Item.php 
    
      namespace App\Models;
    
      use Illuminate\Database\Eloquent\Model;
    
      class Item extends Model
      {
          /**
           * 品物に関連しているユーザーの取得
           */
          public function users()  // 複数形
          {
              return $this->belongsToMany(User::class);
          }
      }

    リレーションには「belongsToMany()
    *メソッド名は複数形

    今回も複数モデルが取得されるため、各プロパティにアクセスするにはforeachなどで各配列ごとにする必要があります。

    
      $items = User::find(1)->items;
      foreach(User::find(1)->items as $item)
      {
          $item_name[] = $item->name;
      }

    「多対多」のリレーションの使い方については、こちらの記事も参考にしてください。

    【laravel】リレーションbelongsToManyの使い方

    リレーションの応用

    外部キーを変更する

    リレーションは、自動的に外部キーを「親モデルの名前+_id」であると想定します。
    先の「users」(親)と「items」(子)の例では、子モデルに「user_id」が存在すると想定しています。

    しかし、設計上別の名前にしたい場合もあると思います。
    その際には、リレーション時に外部キーの名称を指定することが出来ます。
    (第2引数に指定します)

    また、親モデルのid以外を関連付けたい場合も、リレーションでkeyを指定することが出来ます。
    (第3引数に指定します)

    
      //外部キーをcustomer_keyへ変更
      return $this->hasOne(Item::class, 'customer_key');
    
      //usersテーブルのcustomer_idを利用
      return $this->hasOne(Item::class, 'customer_key', 'customer_id');

    usersテーブル

    idcustomer_idname
    11001山田
    22268加藤
    35812鈴木
    45224佐々木

    itemsテーブル

    idnamecustomer_key
    1りんご1001
    2みかん5812
    3バナナ2268
    4ぶどう5224

    リレーションのデータを全件取得する

    今までは1つのモデルについて、リレーション先のモデルを取得していました。
    今回は、全部のモデルに対して取得してみたいと思います。

    
      $users = User::all();
      foreach($users as $user)
      {
          $items[] = $user->item;
      }

    この方法でもよいのですが、「N+1問題」があるためにあまり推奨されません。
    (ここでは詳しく説明しませんが、クエリの効率が良くありません。)

    【laravel】N+1問題について考える

    よりクエリの効率をよくするためには、「with」メソッドを使用します。

    
      $users = User::with('item')->get();
      foreach($users as $user)
      {
          $items[] = $user->item;
      }

    まとめ

    「1対1」の場合:
    ・親 「hasOne(Model::class)」
    ・子 「belongsTo(Model::class)」

    「1対多」の場合:
    ・親 「hasMany(Model::class)」
    ・子 「belongsTo(Model::class)」

    「1対多」の場合:
    ・親 「belongsToMany(Model::class)」
    ・子 「belongsToMany(Model::class)」

  • 【laravel】リレーションbelongsToManyの使い方

    こんにちは、らいか(@hideiwa1)です。

    今回は、laravelでテーブル同士を関連付ける【belongsToMany】の使い方を解説します。
    これにより、多対多のテーブルの扱いが容易になります。

    リレーションの基本

    まずは、laravelにおけるリレーションの確認です。

    リレーションとは、データベースのテーブル同士を関連づける機能です。
    例えば、「users」テーブルと「items」テーブルを例にしてみましょう。

    1対1

    ユーザーが1つの品物だけを持っていて、その品物がすべて1つずつの場合、「users」テーブルと「items」テーブルの関係は「1対1」の関係です。

    usersテーブル
    id name
    1 山田
    2 加藤
    3 佐々木
    itemsテーブル
    id name users_id 
    1 りんご 1
    2 みかん 3
    3 バナナ 2

    1対多

    ユーザーが複数の品物を持っていて、その品物がすべて1つずつの場合、「users」テーブルと「items」テーブルの関係は「1対多」の関係です。

    usersテーブル
    id name
    1 山田
    2 加藤
    3 佐々木
    itemsテーブル
    id name users_id 
    1 りんご 1
    2 みかん 3
    3 バナナ 1

    多対多

    ユーザーが複数の品物を持っていて、その品物が複数存在する場合、「users」テーブルと「items」テーブルの関係は「多対多」の関係です。
    今回使用するのは、こちらのケースになります。

    usersテーブル
    id name
    1 山田
    2 加藤
    3 佐々木
    item_userテーブル
    user_id item_id
    1 2
    1 1
    3 3
    2 3
    3 1
    itemsテーブル
    id name
    1 りんご
    2 みかん
    3 バナナ
    【laravel】リレーションの基本

    belongsToManyの使い方

    テーブル設計

    では、早速リレーションの設定をしていきましょう。

    まずは、各テーブルを作成します。
    「多対多」の場合、2つのテーブルを結びつける「中間テーブル」が必要となります。

    中間テーブルを作成する際の注意点ですが、以下の通りです。

    関連付けるテーブル名を「_(アンダースコア)」でつなげる

    つなげるテーブル名は「単数形

    つなげる順番は、「アルファベット順

    各テーブルのIDをカラムに指定する
    (今回の場合は「user_id」と「item_id」)

    今回の場合、「item_user」テーブルとなります。

    リレーションの設定

    中間テーブルが作成出来たら、今度はモデルへのリレーションの設定です。

    「多対多」の場合、「belongsToMany」メソッドを使って新しいメソッドを作成します。
    userモデル、itemモデルのそれぞれに設定が必要となります。

    belongsToMany(モデルクラス名、中間テーブル名、外部キー、関連づけるモデルの外部キー)
    第2引数以降は省略可能です。

    
      app/Models/User.php
    
      public funcion items()
      {
          return $this->belongsToMany(Item::class);
      }
    
    
      app/Models/Item.php
    
      public funcion users()
      {
          return $this->belongsToMany(User::class);
      }
    

    データを追加する

    次に、中間テーブルへデータを追加していきましょう。
    データを追加するには、「attach」メソッドを使用します。

    
      $user = User::find(1);
    
      $item_id = 2;
    
      $user->items()->attach($item_id);

    こちらの例では、user_id:1、item_id:2 のデータが追加されます。

    また、attach() の引数には配列を 指定することも可能です。

    データを取得する

    次に、リレーション先からデータを取り出してみましょう。

    リレーション先のデータにアクセスする際には、プロパティ名を指定します。
    中間テーブルのデータにアクセスする際には、「pivot」属性を使用します。

    belongsToMany で関連付けられたモデルには、自動的に pivot 属性が割り当てられます。
    この属性の中には、中間テーブルを示すモデルが含まれています。

    
      $user = User::find(1);
    
      foreach($user->items as $item)
      {
          echo $item->name;
          echo $item->pivot->item_id;
      }

    データを更新する

    中間テーブルのデータを更新する際には、「sync」メソッドを使用します。

    syncメソッドを使用すると、引数に指定されたIDのみが中間テーブルに残るように更新されます。

    
      $user = User::find(1);
    
      $user->items()->sync([1,3]);
    item_userテーブル
    user_id item_id
    1 1
    1 2
    3 2
    2 3
    3 1

    item_userテーブル
    user_id item_id
    1 1
    3 2
    2 3
    3 1
    1 3

    データを削除する

    データを削除する際には、「detach」メソッドを使用します。

    detachメソッドを使用すると、該当するデータを中間テーブルから削除します。
    各モデルのデータは、そのままデータベースに残ります。

    
      $user = User::find(1);
    
      $user->items()->detach(1);
        //user_id:1、item_id:1のデータを削除する
    
      $user->items()->detach();
        //user_id:1のデータを全て削除する

    使い方の応用例

    中間テーブルに項目を追加する

    初期状態では、中間テーブルには各モデルキーのみが存在します。
    この中間テーブルに対して、追加の項目を設定したい場合は、リレーションの設定で項目の指定が必要となります。

    項目を指定するには、「withPivot」メソッドを使用します。
    また、created_at および updated_at のタイムスタンプを使用する場合は、「withTimestamps」メソッドを使用します。

    
      app/Models/User.php
    
      public funcion items()
      {
          return $this->belongsToMany(Item::class)
              ->withPivot('count', 'price')
              ->withTimestamps();
      }

    保存する際は、attachの第2引数へ追加データの配列を指定します。
    sync を使用する場合は、指定のIDに追加データを指定します。

    
      $user = User::find(1);
    
      $item_id = 2;
    
      $user->items()->attach($item_id, ['count' => 3]);
    
      $user->items()->sync([1 => ['count' => 3], 3]);

    中間テーブルにメソッドを追加する

    中間テーブルへメソッドを追加したい場合、中間テーブルのカスタムピボットモデルを定義する必要があります。

    作成する際は、Model ではなく、Pivot を継承する点が注意です。

    
      app/Models/ItemUser.php
    
      namespace App\Models;
    
      use Illuminate\Database\Eloquent\Relations\Pivot;
    
      class ItemUser extends Pivot
    
      public funcion hello()
      {
         echo 'hello';
      }
    

    次に、リレーションへ「using」メソッドを追加します。
    これにより、中間テーブルのメソッドを使用することが出来るようになります。

    
      app/Models/User.php
    
      public funcion items()
      {
          return $this->belongsToMany(Item::class)
              ->using(ItemUser::class);
      }

    メソッドを呼び出す際は、「pivot」属性を使用します。

    
      $user = User::find(1);
    
      foreach($user->items as $item)
      {
          echo $item->pivot->hello();
      }

    まとめ

    「多対多」のリレーションには「belongsToMany(Model::class)」

    「table_table」の中間テーブルが必要

    追加は「attach」、更新は「sync」、削除は「detach」

    中間テーブルの要素を取得するには「pivot」

  • 勉強や運動などが続かない方にお勧め!『まんがで身につく続ける技術』

    新しいことを始めたいけど、続かないというお悩みはありませんか?

    こんにちは、らいか(@hideiwa1)です。

    「勉強や運動を始めたいけど、なかなか続かない」
    「そもそも始めたくても、踏み出せない」

    このような経験をお持ちの方は多いのではないでしょうか?

    『まんがで身につく続ける技術』では、行動科学に基づくマネジメントにより、行動を続ける技術を学ぶことが出来ます。

    今回は本書から、『続ける為の技術』の一部を紹介します。

    「続ける」為に必要な事

    「続ける」ことに「才能」や「意志」、「やる気」は、全く必要ありません。

    行動を続けられる人と、続けられない人、その違いは何だと思いますか?

    • 「やる気が足りないんだよ」
    • 「彼はもともと努力家だから」
    • 「そこまで意志が強くないから、続かないんだよね」

    このように考える方が多いのではないでしょうか。

    実は、「続ける」ことに「やる気」や「才能」は関係ないんです!

    必要なのは、科学的根拠に基づいた「続ける技術」を身につけることです。
    この「続ける技術」を身につければ、あなたはなりたい自分になることが出来るのです。

    行動を構成する要素とは

    すべての行動は、

    • 先行条件(行動の直前条件)
    • 行動
    • 結果条件(行動の直後条件)

    この3要素から成り立ちます。
    例えば「食べ過ぎる」という行動について考えてみましょう。

    • 先行条件 … ストレスでイライラする
    • 行動 … 食べ過ぎる
    • 結果条件 … お腹がいっぱいになり満足する

    このように分解することが出来ます。

    つまり行動を続けるためには、「先行条件」を整えることで、自然と「行動」が起こるようにすればいいのです。

    また、コントロールしたい行動(ターゲット行動)には「過剰行動」と「不足行動」の2種類があります。

    • 過剰行動 … やめたい行動
    • 不足行動 … 足りない行動

    さらに、「不足行動」には行動を邪魔する「ライバル行動」があります。
    例えば、以下のようになります。

    • 禁煙したい … 過剰行動(喫煙をする)
    • 運動をしたい … 不足行動(運動をする)・ライバル行動(ゲームをする)

    まずは、ターゲット行動が「過剰行動」なのか、「不足行動」なのかを意識する必要があります。

    やりたい行動の発生を増やす方法

    ターゲット行動が「不足行動」の場合、

    • ターゲット行動を増やす先行条件を設定する
    • ライバル行動を抑える先行条件を設定する

    これらを意識する必要があります。

    行動を増やすポイントは3つあります。

    • 「行動のヘルプ」をつくる(行動の数を増やす助けになる)
    • 「動機づけ条件」をつくる(行動に対するメリットやご褒美)
    • 「行動のハードル」を下げる(行動をやさしくする)

    例えば「運動をする」というターゲット行動の場合、

    • 行動のヘルプ … 玄関にトレーニングウェアを置く、お気に入りのランニングシューズを買う
    • 動機づけ条件 … 健康的になる、運動したらショッピングに行く
    • 行動のハードル … 毎日ではなく、週1回から始める、1回10分から始める

    などの要素を考えることが出来ます。

    ライバル行動を減らすには、これの逆になります。

    • 「行動のヘルプ」を減らす
    • 「動機づけ条件」を減らす

    ライバル行動が「ゲームをする」の場合、

    • 行動のヘルプ … スマホのゲームをアンインストールする、ゲーム機のコンセントを抜く
    • 動機づけ条件 … ゲーム以外にリラックスできることをする

    このような対策をすることで、ライバル行動が起きにくい状況を作ります。

    やめたい行動を減らす方法

    ターゲット行動が「過剰行動」の場合、対策方法は「不足行動」の逆になります。

    • 「行動のヘルプ」を取り除く(行動の数を増やす助けになる)
    • 「動機づけ条件」を取り除く(行動に対するメリットやご褒美)
    • 「行動のハードル」を上げる(行動をやさしくする)

    例えば「禁煙をする」というターゲット行動の場合、

    • 行動のヘルプ … 飲み会に参加しない、喫煙所の近くを通らない
    • 動機づけ条件 … 口さみしいときはガムを嚙む
    • 行動のハードル … 煙草を持ち歩かない、財布を持ち歩かない

    などの対策を考えることが出来ます。

    まとめ

    どのような目標であれ、一朝一夕には結果が出ることはありません。
    目標を達成するためには、「継続」が必要不可欠です。

    継続は精神論や才能ではなく、技術を知っているかどうかで変わります。

    皆さんも、「続ける技術」を身につけて、目標への一歩を踏み出してみませんか?

  • 「JavaScript攻略!WebAPIについて徹底解説します」に参加しました

    こんにちは、らいか(@hideiwa1)です。

    本日は松田信介さん(@xhackjp1)のビデオ講座「JavaScript攻略!WebAPIについて徹底解説します」に参加しましたので、その感想などを書いていきます。

    HTTPとは?APIとは?

    まず基本として、HTTPとは何か?という事から。

    簡単に言うと、HTTPとは「ネットを介してテキストをやり取りする仕組み」です。

    htmlやjavascriptなどもテキストデータなので、それをサーバーから取得して、ブラウザで処理をしてページを表示させています。

    主なメソッドとしては「GET」や「POST」などがあり、データの送受信を行うことができます。

    APIとは「サービスとサービスをつなぐ仕組み」で、第3者がデータを利用できるようにしたものです。
    そして、HTTPリクエストを通じて行うのが、webAPIです。

    webAPIは、twitterやgoogle,ぐるなびなど様々なサービスで提供されており、利用することができます。

    HTTPリクエストの送信

    javascriptではHTTPリクエストを送信できるメソッドがあり、それが

    • XMLHttpRequest
    • fetch

    の2種類です。
    その他、jQueryならAjax、vueならAxiosなどのメソッドも利用できます。

    データの送受信に使われるフォーマットは、JSONという形式です。
    APIのインターフェースとしては、RESTGraphQLなどがあります。
    (詳しくは
      RESTの課題とGraphQL 〜GraphQLを簡単に使ってみる〜 
     こちらの記事が分かりやすいと思います)

    非同期通信

    webAPIを使用する際、注意しなくてはいけないのが通信にかかる時間です。

    通信を行う際は少なからず時間がかかり、取得するデータが多ければその分時間がかかることになります。
    その通信中に、ブラウザの処理が止まってしまってはユーザーの使い勝手が悪くなってしまいます。

    そこで利用するのが、非同期処理です。

    function sample1(){
      return new Promise(resolve, reject){
        fetch("URL", {
          method: "GET", 
        }). then( responce => responce.text())
        .then(text => resolve(text));
      }
    }
    
    async function call(){
      const result = await sample1();
      console.log(result);
    }
    
    console.log('A');
    call();
    console.log('B');
    
    結果:A B text

    通常、プログラムの処理は上から順に行われますが、ここではwebAPIの結果を待たずに次の処理へ進んでいます。

    処理の流れとして、

    call();
      async関数call()を呼び出す
    
    async function call()
      Promiseオブジェクトを返し、処理を先に進める
      処理完了後に、Promiseオブジェクトのresolve()を返す
    
    await sample1()
      関数sample1()を実行
      Promiseオブジェクトのresolve()が帰ってくるまで処理を止める。
    
    function sample1(){
      return new Promise(resolve, reject){
      Promiseオブジェクトを返す
      処理完了後に、Promiseオブジェクトのresolve(text)を返す

    Promiseは、非同期処理の完了を待って結果を取得するオブジェクトであり、成功時にはresolve()、エラー時にはreject()を返します。

    async functionは、Promiseオブジェクトを返します。つまり、次の2つは同じ意味となります。

    async function test1(){
      return 'test';
    }
    
    function test2(){
      return new Promise(resolve){
        resolve('test');
      }
    }

    awaitは、Promiseが返ってくるまで処理を止めます

    これらのasync/await/promiseの処理を使い、ユーザーの利便性を落とさずにwebAPIの利用をしていきます。

    最後に

    今までAjaxやaAxiosなどは利用していましたが、APIとは何かについては曖昧なままでした。

    今回の講義では、webAPIの概念やasync/awaitを使った非同期処理の方法を学ぶことができたので、有意義なものとなりました。

    今後とも勉強会に参加して、プログラミングの理解を深めたいと思います。

  • 本を読むのが遅いという方にお勧め!『死ぬほど読めて忘れない高速読書』

    皆さん、1か月に何冊の本を読んでいますか?

    こんにちは、らいか(@hideiwa1)です。

    情報のインプットとして重要な読書。
    しかし、必要と分かっていても読む時間がない、という方も多いのではないでしょうか。

    『死ぬほど読めて忘れない高速読書』には、本を早く読むだけではなく、自身の知識として吸収できる読書術が書かれています。

    今日は本書から、『高速読書術』の一部を紹介したいと思います。

    記憶に残らない速読は意味がない

    死ぬほど読めて忘れない、高速読書

    本を早く読むと聞いて、「どうせ速読でしょ」「1冊5分で読むの?」などと思う方もいるでしょう。

    まず伝えたいのは、『高速読書術』は「速読」とは違う、ということです。

    速読でいかに早く読めたとしても、そのあとで記憶に残っていなければ何の意味もありません。

    『高速読書術』では、脳科学を元にした「早く読めて」「忘れない」方法を教えてくれます。

    1冊30分で3回読む

    実践イメージは本屋での立ち読み

    『高速読書術』では、1冊の本を30分かけて、時間を空けて3回読みます

    1回目:全体をザックリと読んで、気になるところにドッグイヤーを付けてる。

    2回目:ドッグイヤーを付けたところを中心に読み、気になる箇所に青ペンで印をする。

    3回目:青ペンの個所を読み、自分の言葉でコメントを書きこむ。

    この「3回読む」というのがポイントで、
    1回で理解しなければいけない
    というプレッシャーを感じず、気楽に読むことができます。

    私は今まで、「本は綺麗なまま読む」タイプでしたが、ドッグイヤーや書き込みをすることにより、今までより記憶に残りやすくなりました。

    目的をもって本を読む

    読書の「目的」を言語化しよう

    「何のために本を読むのか?」を明確にしておくと、読むときに必要な情報が見えてきます。

    例えば「wordpress」の情報が欲しいとして、その中でも「テーマの作り方」なのか「投稿の仕方」なのかによって必要な情報は変わってきます。

    本を読むとき、その本すべてを理解する必要はなく、必要な情報を必要な分だけ得られれば問題はないのです。

    成果は スピード × 知識 × 行動 で成長する

    アウトプットすれば、長期記憶として保存される

    月に1冊しか本を読まない人と、月に10冊本を読む人ではどちらが成長できるでしょうか?

    もちろん読む本の質にもよりますが、多く読む方がより成長できるはずです。

    しかし、読書によって得られた知識も、使わなければ意味がありません。
    そこで必要なのが「アウトプット」です。

    本を読み終えたら、「アウトプットノート」を書きます。
    「アウトプットノート」には、本から得られた要点と、その要点を元に自分が行う行動を書き記します。

    「これは仕事に生かせそう」とか、「普段の習慣に加えよう」など、1つや2つでもいいので行動に移せれば、その分成長がすることができます。

    まとめ

    知識を得るためにも「読書」は重要です。
    その時間が短くなれば、同じ時間で多くの知識を身に着けることができます。

    さらに、読書によって身に着けた知識を実際の行動に移すことで、より成長をすることができます。

    皆さんもこの機会に読書、始めてみてはいかがでしょう?