20190724のPHPに関する記事は12件です。

LaravelのControllerで生成・加工したデータをVue.jsのテンプレートファイルで利用する方法

はじめに

LaravelとVue.jsでちょっとしたアプリを作っていた時に、LaravelのControllerで生成・加工したデータをVue.jsのテンプレートファイルに渡して使用するには下記の手順でデータを渡す必要がありましたので今後必要になった時に直ぐに思い出せる様にまとめたいと思います。

Controller→View(Bladeファイル)→Vue(Vue.jsテンプレート)

前提とするデータ構成

とある店舗情報を格納するデータをDB等から取得して下記の多次元配列としてControllerで整形したと想定します。
*Controllerでの細かいデータの取得・加工処理については本記事では割愛します。

array(5){
  0 => array(5)
  1 => array(5)
  2 => array(5)
  3 => array(5)
  4 => array(5) 
}

valueである各配列の中身は下記の様な形式のデータとします。

array(5){
    'shopId' => "testId1",
    'shopName' => "testShop1",
    'price' => "1000",
    'shopTel' => "1234-5678-90",
    'shopMessage' => array('short' => "test shot message",
                        'long' => "test long message"
    ),
    'shopImage' => array('url1' => "https://example.com/sample1.jpg",
                        'url2' => "https://example.com/sample2.jpg"
    )
}

Controller

順を追って、まずはControllerから流れを見て行きます。

上記の店舗情報データを$sampleDataとします。

この$sampleDataをVueファイルで配列の様に扱うにはjsonエンコーディングを行いオブジェクト化する必要があります。

$shopData = json_encode($sampleData);

viewを指定する箇所を含めると下記の様な具合になります。

app/Http/Controllers/SampleController.php

public function index()
{

    /*** データの加工処理は省略 ***/

    // 配列のjsonエンコード化
    $shopData = json_encode($sampleData);

    // viewファイルに$shopDataを渡す
    return view('index')->with('shopData', $shopData);
}

View

次はViewファイルを見て行きます。

bodyタグ内を下記の通り記述して行きます。

resources/views/index.blade.php

<main id="app">
    <shop-page v-bind:shop-data="{{ $shopData }}"></shop-page>
</main>

shop-pageタグがVueテンプレートの内容を反映する箇所です。
このshop-pageタグにControllerから受け取ったデータをバインド(結びつける)します。
「v-bind」属性(ディレクティブ)でバインドを行います。
v-bindで指定した「shop-data」がVueテンプレート内にてControllerから来た$shopDataのデータを受け持つことになります。
Vueテンプレート内ではキャルメルケースのshopDataと言う名前でデータが利用されることになります。

Vueテンプレート

Vueテンプレートの中身は下記の通りです。

resources/components/ShopPage.vue

<template>
    <div class="card text-white bg-dark mb-3" v-for="shop in shopData">
        <div class="row no-gutters">
            <img class="card-img" :src="shop.shopImage.url1" alt="no image">
            <div class="card-body">
                <h3 class="card-title">{{ shop.shopName }}</h3>
                <p class="card-text">{{ shop.shopMessage.short }}</p>
            </div>
        </div>
    </div>
</template>


<script>
    export default {
        props: {
            shopData: {
                type: Object
            },
        },
       name:'shop-page'
   }
</script>

scriptタグ内のprops(プロパティ)に記載されているshopDataがbladeファイル内での$shopDataになります。
型にObject型を指定する必要があります。

データの利用例として、templateタグ内で店舗情報をBootstrapのcardで表示するコードを記載しています。

for文の要領で店舗情報ごとにcardを作成するには一番外側のcardクラスが指定されたdivタグ内でv-forディレクティブを設定する方法があります。
下記の通りに指定することでforeach文の様に各店舗情報のオブジェクトを抽出することが出来ます。

v-for="shop in shopData"

今回のデータ構成ではkeyの値を参照する必要の無い作りになっている為「v-for」ディレクティブでkeyの値を取得していませんが、もし必要な場合は下記の通りに記載する必要があります。

v-for="(shop, key) in shopData"

「shop」はControllerで生成したの店舗ごとの情報をまとめたデータです。
このshopの値は「v-for」ディレクティブが指定されたタグ内で記載されている全てのタグ内で各データに沿ったkeyを指定することで利用出来ます。

shop{
    'shopId' : "testId1",
    'shopName' : "testShop1",
    'price' : "1000",
    'shopTel' : "1234-5678-90",
    'shopMessage' : {
        'short' : "test shot message",
        'long' : "test long message"
    },
    'shopImage' : {
        'url1' : "https://example.com/sample1.jpg",
        'url2' : "https://example.com/sample2.jpg"
    }
}

h1タグやpタグにて文字列を出力する場合は下記の通り二重括弧を使って値を指定します。

<h1 class="card-title">{{ shop.shopName }}</h1>
<p class="card-text">{{ shop.shopMessage.short }}</p>

画像を表示させる場合は少し書き方が異なります。
src属性に画像データのパスやURLを指定しますが、「src」の直前に「:」(コロン)を指定する必要がある。

<img class="card-img" :src="shop.shopImage.url1" alt="no image">

店舗情報をボタンクリックイベント後の関数で利用したい場合は下記の様に「v-on:click」ディレクティブに関数名を指定してパラメータとして店舗情報を指定すると良いです。
関数定義内の各詳細のデータの指定の仕方は同様です。

<a v-on:click="testFunc(shop)" href="javascript::void(0)" class="btn btn-primary">detail</a>

ちなみに

bladeファイル上で配列のkey指定をして数値や文字列など単体のデータを渡す場合はControllerでjsonエンコードを行う必要はありません。
配列のままbladeファイルでkey指定することによって単体のデータを渡すことが出来ます。

app/Http/Controllers/SampleController.php

$singleValue = array('key1' => 1, 'key2' => 2, 'key3' => 3);

resources/views/index.blade.php

<shop-page v-bind:shop-data="{{ $shopData }}" v-bind:single-value="{{ $singleValue['key1'] }}" ></shop-page>

この場合はVueファイル内ではpropsでNumber型やString型を指定する必要があります。

以上です。
LaravelをやるとVue.jsに触れる機会が出てくる為この辺りの理解も深める必要があるなと感じました!

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

codeigniterでthird_party内のcontrollerを使う

codeigniterのthird partyは便利です。色々なものをモジュール化して分けておける。configとかも、ある程度だいたいできちゃう。

けれどもコントローラーだけはだめ。なぜならコントローラーからthird partyを始めとした大体のクラスを読んじゃっているから。

けれどもthird partyにコントローラーとかを含めちゃって使い回せるようにしたい!!

というわけでやりましょう。

事前にファイルをrequireする

まあ、単純です。controllerファイルの先頭でthird party内のコントローラーを読み込んで、それをextendsするだけ。

まず、third party内に読み込むためのコントローラーを作ります。

application/third_party/test/controllers/Welcome_preset.php
defined('BASEPATH') OR exit('No direct script access allowed');
class Welcome_preset extends CI_Controller{
    public function index(){
           $this->load->view('welcome_message');
    }
}

次に、実際に参照されるコントローラー。

application/controllers/Welcome.php
defined('BASEPATH') OR exit('No direct script access allowed');

require_once APPPATH . "third_party/test/controllers/Welcome_preset.php";

class Welcome extends Welcome_preset{
    public function __construct(){
        parent::__construct();
    }
}

これで、Welcomeコントローラーに接続される時に実行されるのは継承元のWelcome_presetクラスのものとなります。

そのプロジェクトだけで利用したい関数とかを作りたかったら、参照先のWelcomeに書けばいいし、汎用的なのはpresetに、と取り回ししやすい形で運用できます。いえいいえい。

考え方はシンプルで、

接続

Welcome.php

Welcome_preset.php呼び出し

Welcome_presetを継承したWelcomeクラス実行

という感じ。

ソーシャルログイン系とか、自分の中で作り方が決まっててもうコントローラーまるまるコピペっとしてるやつとか、ちょっとした改変でOKとかってなってるものをこれで一括管理できます。楽ちんまるです。

さらに、Welcome_presetでMY_Contollerを継承するようにしておけば、

MY_Controller → Welcome_preset → Welcomeと、呼び出せるのでこれまた便利です。

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

Google Cloud Platformのタイムゾーン設定

GCPのAppEngine上でphpサーバーを動かして、Cloud SQLでMySQLを使っているのですが、
タイムゾーン設定がどちらもデフォルトでUTCになっており、JTCへの設定変更に詰まったのでメモに残します。

Cloud SQLの設定

ダッシュボードの設定 > 設定の編集 からdefault_time_zoneフラグに+09:00を追加する。
スクリーンショット 2019-07-24 21.04.16.png

これでMySQLの接続して確認できたらOK

mysql> show variables like '%time_zone%';
+------------------+--------+
| Variable_name    | Value  |
+------------------+--------+
| system_time_zone | UTC    |
| time_zone        | +09:00 |
+------------------+--------+

AppEngineの設定

デプロイ時にapp.yamlと同じ場所にphp.iniを配置する。

php.iniの中には、

php.ini
date.timezone = "Asia/Tokyo"

以上です。

AppEngineが一番ハマったのに文量ほぼなかった。

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

Composerで特定パッケージのみを更新

ComposerでPHPのパッケージ管理を行っているとき、composer update コマンドを使用することで、パッケージの更新をまとめて行うことができます。

ですが、テストの都合などで特定パッケージのみバージョンアップしたい場合もあります。

以下の方法を使えば、特定のパッケージのみを更新することができます。

※間違った点などあればご教授いただければ幸いです。

特定パッケージのみ更新する

composer update コマンドの後にパッケージ名を指定すれば、composer.json に記載された特定のパッケージとその依存のみを最新バージョンに更新できます。

$ composer update aws/aws-sdk-php

特定ベンダーの全パッケージを一括で更新する

ワイルドカードを使用することで、composer.json に記載された特定のベンダーの全てのパッケージとその依存を最新バージョンに更新できます。

$ composer update aws/*

依存パッケージの更新がないか事前に確認する

ただ、いくらパッケージを指定したとしても、依存パッケージが同時に更新されてしまう可能性があります。

そうした場合、--dry-run オプションを付けて実行することで、実際に更新することなく何が更新されるかを事前にチェックすることができます。

念の為、パッケージを最新にする前に挙動を確認しておくとよいです。

$ composer update --dry-run aws/aws-sdk-php

参考

逆引き!Composer コマンド・ライン一覧 - Qiita

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

php-master-changes 2019-07-23

今日はストリームの読み書きでエラーを通知するようにする修正、pdo_oci の不要コードの削除、PDO で、"?" をエスケープできるようにする修正、ドキュメントの更新、テスト中に残っていた E_STRICT を削除する修正があった!

2019-07-23

nikic: Report errors from stream read and write operations

  • https://github.com/php/php-src/commit/d59aac58b3e7da7ad01a194fe9840d89725ea229
  • [7.4~]
  • ストリームの読み書きでエラーを通知するよう修正
  • php_stream_read() and php_stream_write() が ssize_t を返すようになり、負値は失敗扱いで、fread() とか fwrite() が false を返す
  • EWOULDBLOCK と EAGAIN はノンブロッキングストリームではエラー扱いではなく、読み書きサイズ 0 の成功扱い
  • EINTR はなんか扱い決まってなくてふわっとしてる
  • ユーザになんかこの変更でまずい影響出たら挙動は調整しそう、一旦入れてるという感じ
  • #73535 の対応で、ストリーム API いじるなら今じゃねえの、みたいな感じのもよう
  • #4433 あたりから話の流れたどれるけど気合要りそう

nikic: Also report errors from Zend stream reader operation

nikic: Add upgrading entries

petk: Remove HAVE_OCILOBISTEMPORARY and HAVE_OCICOLLASSIGN

mbeccati: Fix FR #71885 (Allow escaping question mark placeholders)

petk: Update NEWS

derickr: Update NEWS for PHP 7.4.0beta1

derickr: Update NEWS for 7.4.0beta2

Girgias: Cleanup of remaining E_STRICT in tests

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

PHPで数字を0埋めする

PHPで数字を0埋めするにはsprintf関数を使用します。

sprintf('%02d', 1); // 01
sprintf('%03d', 1); // 001
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

php-master-changes 2019-07-22

この日は システムの libgd 利用時の gd 拡張のビルド修正、fpm が SEGV で死ぬ問題の修正、reflection でクラス変数アクセスコードにクラススコープを適用するようにする修正、zend_update_class_constants() の実装への静的メンバーテーブルの初期化処理の追加、CI でこけるテストの修正、7.4 での大量の諸々の非推奨化、不要コードの削除、ドキュメントの更新、ReflectionReference において rc=1 の自己参照配列を特別扱いするようにする修正があった!

2019-07-22

remicollet: improve temporary fix for system libgd

plmnikulin: Prevent use after free in fpm_event_epoll_wait

dstogov: Evaluate constant in class scope

dstogov: Initialize static_members_table

nikic: Reduce number of workers in test

nikic: Deprecate get_magic_quotes_gpc() and get_magic_quotes_runtime()

nikic: Deprecate array_key_exists() on objects

nikic: Deprecate Reflection export() methods

nikic: Deprecate encoding as 3rd param to mb_strrpos()

nikic: Deprecate ezmlm_hash()

nikic: Deprecate hebrevc()

nikic: Deprecate money_format()

nikic: Deprecate is_real() function

nikic: Deprecate FILTER_SANITIZE_MAGIC_QUOTES

nikic: Deprecate implode() with swapped parameter order

nikic: Deprecate (real) cast

nikic: Deprecate convert_cyr_string()

nikic: Deprecate restore_include_path()

nikic: Deprecate allow_url_include

nikic: Deprecate unbinding $this from non-static closure

nikic: Add deprecations to UPGRADING

cmb69: Drop superfluous ENABLE_GD_TTF

nikic: Remove test for bug #77185

cmb69: Remove superfluous HAVE_GD_BUNDLED checks

petk: Remove HAVE_DSA_DEFAULT_METHOD

petk: Fix internals upgrading log

petk: Remove HAVE_PQPUTCOPYEND

remicollet: cleanup gd build with system libgd - drop need to use libpng with system libgd - drop need to use libjpeg with system libgd - drop need to use libXpm with system libgd - drop need to use libfreetype with system libgd - improve configure comments

nikic: Revert "Add ReflectionReference::getRefcount()"

nikic: Special-case rc=1 self-referential arrays in ReflectionReference

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

Laravelでいいね機能

環境

PHP 7.3
Laravel 5.8

Laravelにいいね機能を実装しようと思い、調べていたらLaravel-LoveというライブラリがLaravel Newsで紹介されていました。

cybercog/laravel-love

準備

今回はUserモデルでPostモデルにいいねします。

インストール

$ composer require cybercog/laravel-love

Likeタイプを生成

$ php artisan love:reaction-type-add Like 1

Reactarebl(いいねするモデル)の準備

app/User.php
<?php

namespace App;

use Cog\Contracts\Love\Reacterable\Models\Reacterable as ReacterableContract;
use Cog\Laravel\Love\Reacterable\Models\Traits\Reacterable;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable implements ReacterableContract
{
    use Reacterable;
}
$ php artisan love:setup-reacterable --model="App\User" --nullable

Reactable(いいねされるモデル)準備

app\Post.php
<?php

namespace App;

use Cog\Contracts\Love\Reactable\Models\Reactable as ReactableContract;
use Cog\Laravel\Love\Reactable\Models\Traits\Reactable;
use Illuminate\Database\Eloquent\Model;

class Post extends Model implements ReactableContract
{
    use Reactable;
}
$ php artisan love:setup-reactable --model="App\Post" --nullable

実際にいいねする

<?php
use App\User;
use App\Post;
use Cog\Laravel\Love\ReactionType\Models\ReactionType;

$user1 = User::find(1);
$post1 = Post::find(1);

$likeType = ReactionType::fromName('Like');

//リアクター、リアクタントとして登録。
//すでに登録してある場合、例外が投げられます。
if ($user1->isNotRegisteredAsLoveReacter()) {
    $user1->registerAsLoveReacter();
}
if ($post1->isNotRegisteredAsLoveReactant()) {
    $post1->registerAsLoveReactant();
}

$reacter = $user1->getLoveReacter();
$reactant = $post1->getLoveReactant();

//$user1が$post1をいいねしていないことを確認
if ($reacter->isNotReactedToWithType($reactant, $likeType)) {
    //$user1で$post1をいいね
    $reacter->reactTo($reactant, $likeType);
}

//$user1がいいねしたPostが入ったCollectionを取得
$posts = Post::query()
    ->whereReactedByWithType($reacter, $likeType)
    ->get();

//$post1をいいねしたUserが入ったCollectionを取得
$likeReactions = $post1
    ->getLoveReactant()
    ->reactions()
    ->where('reaction_type_id', ReactionType::fromName('Like')->getId())
    ->get();

$likeUsers = [];
foreach ($likeReactions as $likeReaction) {
    $likeUsers[] = User::where('love_reacter_id', $likeReaction->getReacter()->id)->first();
}

//$post1をいいねした数を取得
count($likeUsers);

//いいね解除
if ($reacter->isReactedToWithType($reactant, $likeType)) {
    $reacter->unreactTo($reactant, $likeType);
}

参考

Laravel-Loveのドキュメンテーション
Githubのissue

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

phpのsys_get_temp_dir()関数がmacのデフォルトだと変な位置になっててしかもpermissin errorという罠

php で一時ファイルを一時ファイルディレクトリに作成して配置したいのにできない

ファイルを一時的に保存すべくphpの関数sys_get_temp_dirから取得したディレクトリにファイルをtouchしたらPermission denied

出力してもたら以下の場所でした。
Macでは見かけないフォルダなんですけどここにアクセス権を与えればいいんですが、/tmpという有名なテンポラリを使ったほうが消し忘れも防げるしいいとおもうんです。

/var/folders/49/w16_lxpn2qj_jp3fh1bjqxx00000gp/T

そこで、php.iniで設定できないか調べたら、設定項目が存在しません。
でも、ありました。

sys_temp_dir

sys_temp_dir = /tmp

これをphp.iniに追加して再起動。これでOKです。

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

秘密鍵を使ったSSHでPDO接続

はじめに

業務で踏み台経由でDBへ接続する必要があった時やったこと。
PDOはSSH接続する方法はないっぽいので、SSHトンネルをバックグランドで実行しといて、
それ宛にPDOで接続する。

バックグランド実行の方法はこちら

環境

  • Mac
  • PHP5.1
[クライアント] ---- [ 踏み台サーバー] ---- [データベース]
・Mac         ・ユーザー       ・アクセスは踏み台からのみ許可
・PHP        ・パスワード
           ・秘密鍵

コード

バックグラウンドでSSHトンネリングの実行

-N 指定してリモートでコマンド実行できないようにしています。
停止のときに使うため、変数に格納しています。

php
$cmd = "ssh -f -N -L 13306:dbhost:3306 sshuser@sshhost -i key/id_rsa";
exec($cmd);
[クライラント] -> [このトンネルへ13306で接続] -> [sshuser@sshhostとしてデータベースの3306へ転送] -> [データベース]

PDO接続

SSHトンネリングを実行した状態で。

php
//ローカルの13306へ向けて
$dsn = 'mysql:dbname=db;host=127.0.0.1;port=13306';
$user = 'root';
$password = 'root';

try {
    $dbh = new PDO($dsn, $user, $password);
    echo "接続成功\n";
} catch (PDOException $e) {
    echo "接続失敗: " . $e->getMessage() . "\n";
    exit();
}

SSHトンネリングの停止

php
//開始時に使ったコマンドを元に調べる
$_cmd = "ps aux | grep '[0-9] ".$cmd."' | awk '{print $2}'";
exec( $_cmd ,$output ,$return_var );

//$ouput[0]にPID入っているのでkill
exec('kill '.$output[0]);

実装

DB設定やらポート設定はかくじで。

SSHTunneling.php
class SSHTunneling{

    private static $pids = array();
    private static $cmd;

    public static function start(){
        self::$cmd = 'ssh -f -N -L '.$tunnel_port.':'.DBConfig::$host_name.':'.DBConfig::$port.' '.$ssh_user.'@'.$ssh_host.' -i '.$private_key;
        echo self::$cmd.PHP_EOL;
        echo "SSHトンネリングを開始します。".PHP_EOL;
        exec( self::$cmd ,$output ,$return_var );
        if( $return_var != 0) throw new Exception( $output[0] );
        self::set_pid();
    }

    private function set_pid(){
        $_cmd = "ps aux | grep '[0-9] ".self::$cmd."' | awk '{print $2}'";
        exec( $_cmd ,$outputs ,$return_var );
        if( $return_var != 0) throw new Exception( $outputs[0] );
        foreach ((array)$outputs as $output) {
            echo "SSH PID : ".$output.PHP_EOL;
            self::$pids[] = $output;
        }
    }

    public static function stop(){
        echo "SSHトンネリングを終了します".PHP_EOL;
        foreach (self::$pids as $pid) {
            $_cmd = 'kill '.$pid;
            echo $_cmd.PHP_EOL;
            exec( $_cmd ,$output ,$return_var );
            if( $return_var != 0) throw new Exception( $output[0] );
        }
    }
}
php
$dsn = 'mysql:dbname=db;host=127.0.0.1;port='.$tunnel_port;
$db_user = 'root';
$db_password = 'root';

try {
    SSHTunneling::start();
    $dbh = new PDO($dsn, $db_user , $db_password);
    echo "接続成功\n";
    SSHTunneling::stop();
} catch (PDOException $e) {
    echo "接続失敗: " . $e->getMessage() . "\n";
    SSHTunneling::stop();
    exit();
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PHPからSSHをバックグラウンドで実行、停止

はじめに

PHPで踏み台通してMySQLに接続する際にやったこと。
PECLだと専用関数あるらしいが、ない環境だったためシェルつかってバックグラウンドでやることに。

バックグラウンド実行

変数に格納しているのは、停止のときに使うためです。

php
$cmd = "ssh -f -i /tmp/key.txt ssh_user@host_name";
exec($cmd);

オプション

  • [ -f ] バックグランドで実行する
  • [ -i ] 秘密鍵を使用する

バックグラウンドの停止

さっきのコマンドを元にPIDを取得して、killする。

php
//開始時に使ったコマンドを元に調べる
$_cmd = "ps aux | grep '[0-9] ".$cmd."' | awk '{print $2}'";
exec( $_cmd ,$output ,$return_var );

//$ouput[0]にPID入っているのでkill
exec('kill '.$output[0]);
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PHPでSSHをバックグラウンドで実行、停止

はじめに

PHPで踏み台通してMySQLに接続する際にやったこと。
PECLだと専用関数あるらしいが、ない環境だったためシェルつかってバックグラウンドでやることに。

バックグラウンド実行

変数に格納しているのは、停止のときに使うためです。

php
$cmd = "ssh -f -i /tmp/key.txt ssh_user@host_name";
exec($cmd);

オプション

  • [ -f ] バックグランドで実行する
  • [ -i ] 秘密鍵を使用する

バックグラウンドの停止

さっきのコマンドを元にPIDを取得して、killする。

php
//開始時に使ったコマンドを元に調べる
$_cmd = "ps aux | grep '[0-9] ".$cmd."' | awk '{print $2}'";
exec( $_cmd ,$output ,$return_var );

//$ouput[0]にPID入っているのでkill
exec('kill '.$output[0]);
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む