20191125のPHPに関する記事は16件です。

PHP の Error/Exception の分類方法やまとめ方を考えてみたときのメモ。

LogicException と RuntimeException の各子クラスの関連

Logic Runtime 意味
Domain Range 変数が、事前に定義された範囲から逸脱してる。
Out Of Range Out Of Bounds 無効なインデックス、キー。
Invalid Argument Unexpected Value 関数側か、関数の呼び出し側か。
Length Overflow / Underflow すでに長さが変だった / 操作したら長さが変になる。

Domain と Range

単純に、Logic Exception か Runtime Exception か。

Domain は「事前に定義された、過不足なくすべて列挙されたドメインデータの一覧」に含まれない、という例外。

Range は「全て列挙するのは難しいのだけれど、事前に定義された、境界が明確なデータの範囲」から逸脱する、という例外。

正直、この2つについてはもっと根本的な解釈を間違えている可能性があると思ってる。
RangeException の説明に「アンダーフローやオーバーフロー以外の計算エラーが発生した」とあるので、「なにか操作をしようと思ったら変だった(Domain)」「なにか操作をしたら、変になった(Range)」なのかなぁとも思ったりする。

Domain と Range が同じ意味合いで対応する という話は、RangeException の説明に「これ(RangeEaception)は実行時版の DomainException です」とあるので確定。

OutOfRange と OutOfBounds

単純に、Logic Exception か Runtime Exception か。

TypeScript の場合、「コンパイル時に検出」は型定義でできるので、Out of Range は使用する機会がない。

Valid な値が、列挙するのが馬鹿らしいほどの数がある場合に使う例外。
データを列挙できるかできないか?という点で、Domain/Range と OutOfRange/OutOfBounds を使い分ける。(という使い分けでいいのか?)

InvalidArgument と UnexpectedValue

Invalid Argument は呼び出された関数側で throw する。
普通に引数の Validation したときに Invalid なら投げる。

Unexpected Value は関数を呼び出した側で throw する。
関数を呼び出して戻ってきた値が意図した通りになっているかを確認する用途。

例えば https://github.com/sebastianbergmann/diff/blob/master/tests/Utils/UnifiedDiffAssertTrait.php みたいなやつ。

フォームから送られてきた「セレクトボックスやラジオボタンで選んだ値」の改ざんのときは、 DomainException でもいいんじゃね?

そもそも Domain か OutOfBound で迷ってる時点でおかしいんじゃね?

わからん。
いまは、フロントエンドが実装をミスってる可能性もあるので、「一応確認してくれ」という意図で、Domain Exception にしておくのでもいい気がしている。

まぁ、サーバサイドから見たら「外部から来たデータ」であることに変わりはないので、LogicException は不適切なので、Out Of Bounds にしよう派なので、自分で実装するときは Out Of Bounds にするけど。

JavaScript の Error 3種類と、PHP の Exception の対応について

JavaScript には、PHP の例外のような使い方をする(と思われる) Error が3つある。

  • TypeError: 値が期待される型でない場合のエラー
  • RangeError: 値が配列内に存在しない、または値が許容範囲にない場合のエラー
  • ReferenceError: 存在しない変数が参照された場合のエラー

これらは、もしかして PHP の Domain/Range OutOfXxx InvalidXxx のそれぞれに対応するんじゃね?と思ったりした。

ただし、 ReferenceError は Undefined な 変数 にアクセスしようとした場合の話であって、 オブジェクトの Undefined なキー ではない(はず)なので、PHP で言うところの Error レベルの話で、Exception と対比させるのは間違いかもしれない。

PHP Exception JavaScript Error 意味
Domain Range Reference おそらく列挙できるので。ほんとは変数の話だから、 RangeError と見るべきかもしれない。
OutOfRange OutOfBound Range まぁ、普通に範囲エラーだよな。
InvalidArgument UnexpectedValue Type 用途的に考えて同じ。

付録

PHP の Error/Exception の継承関係のクラス図

生成元の Plant UML のソースはこちら

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

preg_matchが2を返す

https://bugs.php.net/bug.php?id=78853

preg_matchは、パターンにマッチした場合は1を、マッチしなければ0を、エラーが発生したらfalseを返します。

01.png

ということでこんな正規表現を試してみましょう。

var_dump(preg_match('/^|\d{1,2}$/', "7"));

結果

02.png

なんだこれ?

2が返ってきました。
英語版にもしっかり"1か0かfalseを返す"と書いてあって、ドキュメントの更新漏れとかでもなさそうです。

PHP7.3から発生するようになったみたいなので、ちょっくら原因でも探ってみるかとソースを覗いてみたのですが、
7.3.0
7.2.24

諦めました。

ちなみにPHP7.0でコンパイルオプションpcre.jitというものが追加され、正規表現にJITを使うようになっています。
このJIT用メモリというのが意外と小さく、たとえば以下の正規表現はpcre.jitの状態によって返り値が変わってきます。

var_dump(preg_match('/^(A{1,2}B)+$/',str_repeat('AB',8192)));

pcre.jit=0であれば返り値は正しく1となります。
しかし、デフォルトのpcre.jit=1であれば返り値はfalseとなり、preg_last_errorにはJIT用メモリが足りないよというPREG_JIT_STACKLIMIT_ERRORが返ってきます。

でもpcre.jit=0にしても、最初の正規表現では2が返ってきました。
preg_last_errorを確認してもエラーは起こっていないので、pcre.jitは特に関係ないようです。

さてこのバグですが、先日修正されました
7.4にもマージされたので、2019/11/28リリース予定のPHP7.4.0正式版ではなおっていると思います。

なお、中身はifをひとつ突っ込んだだけで、どうしてこんなので直るのかさっぱりわかりません。

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

wordpress ACFのちょっとした使い方

案件で、初めてwordpressの構築を任せていただきました。勉強になることばかりで楽しんでいます。
自分の整理がてら、学んだことをまとめてみます。

ACF

言わずもがなのwordpressプラグイン。カスタム投稿実装時には、ないと辛い。

基本

簡単にですが、実際に使用したものを中心にまとめていきます。

the_field();

フィールドの値を出力する際に使用する。

get_field();

フィールドの値を取得する際に使用する。
取得した値を表示する際は、echoで出力する。

<?php
$field = get_field('field_name');
echo $field;

フィールドの値の有無でif構文を使用する際にも使用する。

<?php
if ($the_field = get_field('field_name)) {
echo $the_field;
} else {
echo `値がありません`;
}

Repeater Field

Repeater FieldはACF PROで使用できる繰り返しフィールドです。使ってみればわかる。便利。

sub_field();

繰り返しフィールドをもとに、サブフィールドでループを行う。

<?php
if (have_rows('parent_field')) {
 while (have_rows('parent_field')) {
  the_row();
  the_sub_field('child-field'); // ここで出力をする

  // データを取得するだけなら
 // if (get_the_field('child-field')) {
  // echo '値があります!'
  //}
 }
} else {
 echo '入力がない場合の処理です。';
}

Options Page

Options PageはACFのアドオン。これまた使ってみればわかる。便利。
引数にoptionを与えることで取得できる。

<?php
the_field('option_field', 'option');

投稿オブジェクト

投稿オブジェクトは、登録されている記事等の情報一覧をオブジェクト形式で受け取ることができる。そんなに頻繁に使うことはないのかな。。。しらんけど

<?php
$field = get_field('post_field');

// データの各種とり方はこれで確認!
var_dump($field);

// タイトル
echo $post_field->post_title;

// 記事ID
echo $post_field->ID;

// パーマリンク
echo get_the_permalink($post_field->ID);

あと、取得した記事IDをget_the_field();に引数として入れることで、特定の記事の情報も取れる!

最後に

上記組み合わせると、データを自由に取れそうです!
まだまだ勉強することだらけです。。。。worpdress難しいけど、楽しいです。これからもがんばろ〜っと!

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

PHPからSlackに通知するシンプルな方法

流れ

1.Slack App を作成する
2.PHPにコードを記述する

Slack App の作成

Slack App の新規作成

https://api.slack.com/
上記URLにアクセスし、画面真ん中の「Start Building」をクリックする。

「App Name」:アプリの名前を入力
「Development Slack Workspace」:アプリを導入するワークスペースを選択

Slack App の設定

「Basic Information」→「Display Information」でアプリのアイコンや色を設定できる。

「OAuth & Permissions」→「Scopes」で「Add an OAuth Scope」をクリックする。
「Add permission ...」の欄をクリックして、「chat:write:bot」を選択して有効にする。
「Install App to Workspace」をクリックし、「許可する」を選択する。
「OAuth Access Token」をコピーしておく。

PHPの記述

$token = {OAuth_Access_Token};//上記でコピーした「OAuth Access Token」
$channel = {Channel_Name};//投稿するチャンネル名(もしくはチャンネルID)
$text = {Post_Message};//投稿するメッセージ

$channel = urlencode($channel);//文字列をURLエンコードする(例えば日本語はそのままURLとして使用できない)
$text = urlencode($text);

$url = "https://slack.com/api/chat.postMessage?token=${token}&channel=%23${channel}&text=${text}";
$response = file_get_contents($url);
return $response;//特に意味はない。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PHPで使える機械学習ライブラリ「PHP-ML」を試してみた

機械学習とかちょっと興味あるけどPythonの学習から始めなきゃいけないのか…と思っていたら、
PHPでもPHP-MLという機械学習用のライブラリが用意されていたので試してみました。

導入手順

composerのインストール

まず、公式サイトよりcomposerをインストールします。

php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php -r "if (hash_file('sha384', 'composer-setup.php') === 'a5c698ffe4b8e849a443b120cd5ba38043260d5c4023dbf93e1558871f1f07f58274fc6f4c93bcfd858c6bd0775cd8d1') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
php composer-setup.php
php -r "unlink('composer-setup.php');"

PHP-MLのインストール

php composer.phar require php-ai/php-ml

k近傍法を試してみる

「ケイきんぼうほう」って読みます。
機械学習アルゴリズムの中でも簡単なアルゴリズムと言われておりパターン認識でよくつかわれているようです。
似たような名前でk平均法というのがありますが、k平均法は教師なし学習k近傍法は教師あり学習という違いがあります。

ちなみに、現状機械学習と言ったら教師あり学習の方を指す事が多いようです。教師あり学習では、人間があらかじめ付けた正解のラベルに基づき、機械が学習を行います。
参考:教師あり学習と教師なし学習

さらに、教師あり学習にも分類回帰の2パターンあるようです。
違いは、目標変数が離散値であるか連続値であるかという事のようです。
参考:回帰と分類の違い

サンプル

k近傍法のサンプル
<?php
require_once 'vendor/autoload.php';

use Phpml\Classification\KNearestNeighbors;

$samples = [[1, 3], [1, 4], [2, 4], [3, 1], [4, 1], [4, 2]];
$labels = ['a', 'a', 'a', 'b', 'b', 'b'];

$classifier = new KNearestNeighbors();
$classifier->train($samples, $labels);

echo $classifier->predict([3, 2]);

// [1, 3], [1, 4], [2, 4]にaというラベル、
// [3, 1], [4, 1], [4, 2]にはbというラベルを付けておき、
// [3, 2]というデータがあった場合にどちらのラベルが付くか?というのを分析している。
// この場合はbというラベルが付く。

機械学習で使われるその他アルゴリズム

機械学習でよく使われているアルゴリズムについては以下の記事が分かりやすくまとめられていました。
機械学習に知るべき10のアルゴリズム

感想

PHP-MLのライブラリをインストールするだけなら5分で終わります。
だけどドキュメントに出てくる用語は知らない言葉ばかりで、検索して調べたらまた知らない用語が出てくるという感じでなので、慣れるにはだいぶ時間がかかりそうです。
とはいえ、手軽に機械学習の学習環境が整うので、まずはPHP-MLで機械学習の全体像をつかんでから、Pythonを学習するのもありかと思いました。

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

WSL(Ubuntu)にssh、MySQL、PHP、Apache2 を入れるまで。

WSL(Ubuntu)にssh、MySQL、PHP、Apache2 を入れるまで。

WSL の Ubuntu をインストールする。

省略

初期設定。

// rootのパスワードを設定
$ sudo passwd root

# su -

// 日本語化
# apt install -y language-pack-ja manpages-ja manpages-ja-dev
# update-locale LANG=ja_JP.UTF8

// リポジトリ一覧の更新と、パッケージの更新。
# apt update
# apt upgrade -y

※ 途中、以下の「サービス再起動」に関して聞かれるので Yes で進む。
 Restart services during package upgrades without asking?   

// 終わったら再起動する。Windows を再起動するか、
// 管理者で Windowsコマンドプロンプト を開いて以下を実行してサービスを再起動する。
net stop LxssManager
net start LxssManager

WSLのプロンプトが見にくいので、tera term が使えるようにする。

# cd /etc/ssh
# vi sshd_config

PasswordAuthentication yes

※ この時、配色の関係で vi の画面が非常に見えにくい場合は以下を実行して色を無くす。
:syntax off

// ssh に必要なキーを作成するらしい。
# ssh-keygen -A
# service ssh start

// ここから tera term で繋ぐ。

MySQL を入れる。

// mysql が入っているかを確認。
# dpkg -l | grep mysql

// インストール(mysql-server-5.7 が入った)
# apt install mysql-server

// ↓で確認したら、mysql-client は一緒に入ってた。
# dpkg -l | grep mysql

// 起動して、とりあえず入れるところまで確認。
# service mysql start
# mysql

WindowsのCドライブは容量をあまり使いたくないのでデータディレクトリを D ドライブに移す。

// いったんプロセスを落とす。
# service mysql stop

// D ドライブを drvfs でマウントしなおす。これをしないと、chmod や chown が効かなかった。
# umount /mnt/d
# mount -t drvfs D: /mnt/d -o metadata

// my.cnf はあまり触りたくなかったのでデータディレクトリを移動して、シンボリックリンクを設定する。
# mv /var/lib/mysql /mnt/d/mysql/
# ln -s /mnt/d/mysql /var/lib/mysql

# service mysql start

php を入れる。

# apt install php

// ↑ だけで、apache2 も libapache2-mod-php も入ってきた。

# service apache2 start

// 動くか確認。
# cd /var/www/html
# echo '<?php phpinfo();' > index.php

// http://localhost/index.php で、Server API が "Apache 2.0 Handler" になっていることを確認。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

51歳からのプログラミング 備忘 Laravel 自作 認証 モドキ

セキュリティーとかあまり関係ないような、個人運用のWEBサイトに、簡単な認証システム(モドキ)を実装したい!なんてニーズはないのだろうけれど、認証モドキを作ってみた。いつか使ってみようかな。フレームワークのを使えよ!って言われますね、たぶん。

OverView

モドキなので、ほんとに簡単。バリデーションとか入れてません。
概要は下記

localhost:8000/でアクセスすると、認証済状態であればTOPページに、認証未済であればLoginページに遷移。ログインは、フォームで"123"を入力すればログイン完了!ログイン完了時にsessionとクッキーを設定して認証済状態にします。

sessionはconfig.sessionで、ブラウザを閉じるまでsessionを維持する状態としてます。認証済後は、topページ、secondページ、logoutページを移動できる。認証未済状態で直接top,second,logoutページにはアクセスできません。という感じでゴー!

ファイル構成

Laravel 6.5.2

ファイル名 説明
web.php ルートファイル
SampleController.php コントローラ
MyAuth.php ミドルウェア:ルート保護
login.blade.php ログインファイル
top.blade.php
second.blade.php
logout.blade.php

web.php

web.php
<?php

Route::get ('/','SampleController@confirmAuth');
Route::view('/login','login');
Route::get ('/sessStart','SampleController@sessStart');
Route::middleware(['MyAuth'])->group(function(){
  Route::view('/top','top');
  Route::view('/second','second');
  Route::view('/logout','logout');
  Route::get ('/deleteSess','SampleController@deleteSess');
});

SampleController.php

SampleController.php
<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Cookie;

class SampleController extends Controller
{

  // session は mySession 、cookie は myCookieで設定
  // mySession == myCookie なら true を返す関数
  public static function checkCookie(){
    if( session()->has('mySession') && Cookie::has('myCookie') ){
      if( session('mySession') == Cookie::get('myCookie') ){
          return true;
      }
    }
    return false;
  }

  // checkCookie関数が true なら topページへ
  // false なら loginページに遷移
  public function confirmAuth(){
    if( self::checkCookie() ){ return view('top'); }
    return view('login');
  }

  // mySession と myCookie を設定して topページへ遷移
  public function sessStart(){
    $value = (string) rand();
    session()->put('mySession',$value);
    Cookie::queue('myCookie',$value);
    return view('top');
  }

  // logout 後 に、mySession と myCookie を削除
  public function deleteSess(){
    session()->forget('mySession');
    setcookie('myCookie','',time()-1);
    return redirect('/');
  }
}

MyAuth.php

MyAuth.php
// ミドルウェア
<?php

namespace App\Http\Middleware;

use Closure;
use App\Http\Controllers\Controller;
use App\Http\Controllers\SampleController;
use Illuminate\Http\Request;

class MyAuth
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */

    public function handle($request, Closure $next)
    {
      // SampleController の checkCookie関数を使ってチェック
      if(SampleController::checkCookie()){
        return $next($request);
      }
      return redirect('/login');
    }
}

Middleware では return view ではなく redirectにした。いろいろ調べてたらMidlewareはget送信するみたいな話が、どっかにあったな。
get送信ならRoute::viewで受けられると思うのだけれど、
Call to a member function setCookie() on null
とエラーを賜ります。なぜ?
return redirect でちゃんと動いたので、とりあえず。

login.blade.php

login.blade.php
{{-- jqueryを使えるようにする呪文です --}}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>

<script>
  $(function(){
    $('form').submit(function(e){
      e.preventDefault();

      // ログイン処理
      // 123が入力されていればログイン完了
      // ログイン完了なら、ログイン状態を維持する処理へ(SampleController@sessStart)

      if($('input').val() == "123"){
        location.href = "/sessStart";
      }
      return;
    });
  });
</script>

<form>
  <input type="text" value="123">
  <button>LOGIN</button>
</form>

top.blade.php~logout.blade.php

top.blade.php
<a href="/second">second</a> | <a href="/logout">logout</a>
<p>
top
second.blade.php
<a href="/second">top</a> | <a href="/logout">logout</a>
<p>
second
logout.blade.php
<a href="/second">top</a> | <a href="/second">second</a>
<p>
<a href="deleteSess">LOGOUT</a>

メモ

Undefined variable: _SESSION
session_start()が正しく実行されていないときに出た!

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

51歳からのプログラミング 備忘 Laravel 自作認証モドキ

セキュリティーとかあまり関係ないような、個人運用のWEBサイトに、簡単な認証モドキを実装したい!なんてニーズはないのだろうけれど、認証モドキを作ってみた。いつか使ってみようかな。

OverView

モドキなので、ほんとに簡単。バリデーションとか入れてません。
概要は下記

localhost:8000/でアクセスすると、認証済状態であればTOPページに、認証未済であればLoginページに遷移。ログインは、フォームで"123"を入力すればログイン完了!ログイン完了時にsessionとクッキーを設定して認証済状態にします。

sessionはconfig.sessionで、ブラウザを閉じるまでsessionを維持する状態としてます。認証済後は、topページ、secondページ、logoutページを移動できる。認証未済状態で直接top,second,logoutページにはアクセスできません。という感じでゴー!

ファイル構成

Laravel 6.5.2

ファイル名 説明
web.php ルートファイル
SampleController.php コントローラ
MyAuth.php ミドルウェア:ルート保護
login.blade.php ログインファイル
top.blade.php
second.blade.php
logout.blade.php

web.php

web.php
<?php

Route::get ('/','SampleController@confirmAuth');
Route::view('/login','login');
Route::get ('/sessStart','SampleController@sessStart');
Route::middleware(['MyAuth'])->group(function(){
  Route::view('/top','top');
  Route::view('/second','second');
  Route::view('/logout','logout');
  Route::get ('/deleteSess','SampleController@deleteSess');
});

SampleController.php

SampleController.php
<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Cookie;

class SampleController extends Controller
{

  // session は mySession 、cookie は myCookieで設定
  // mySession == myCookie なら true を返す関数
  public static function checkCookie(){
    if( session()->has('mySession') && Cookie::has('myCookie') ){
      if( session('mySession') == Cookie::get('myCookie') ){
          return true;
      }
    }
    return false;
  }

  // checkCookie関数が true なら topページへ
  // false なら loginページに遷移
  public function confirmAuth(){
    if( self::checkCookie() ){ return view('top'); }
    return view('login');
  }

  // mySession と myCookie を設定して topページへ遷移
  public function sessStart(){
    $value = (string) rand();
    session()->put('mySession',$value);
    Cookie::queue('myCookie',$value);
    return view('top');
  }

  // logout 後 に、mySession と myCookie を削除
  public function deleteSess(){
    session()->forget('mySession');
    setcookie('myCookie','',time()-1);
    return redirect('/');
  }
}

MyAuth.php

MyAuth.php
// ミドルウェア
<?php

namespace App\Http\Middleware;

use Closure;
use App\Http\Controllers\Controller;
use App\Http\Controllers\SampleController;
use Illuminate\Http\Request;

class MyAuth
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */

    public function handle($request, Closure $next)
    {
      // SampleController の checkCookie関数を使ってチェック
      if(SampleController::checkCookie()){
        return $next($request);
      }
      return redirect('/login');
    }
}

Middleware では return view ではなく redirectにした。いろいろ調べてたらMidlewareはget送信するみたいな話が、どっかにあったな。
get送信ならRoute::viewで受けられると思うのだけれど、
Call to a member function setCookie() on null
とエラーを賜ります。なぜ?
return redirect でちゃんと動いたので、とりあえず。

login.blade.php

login.blade.php
{{-- jqueryを使えるようにする呪文です --}}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>

<script>
  $(function(){
    $('form').submit(function(e){
      e.preventDefault();

      // ログイン処理
      // 123が入力されていればログイン完了
      // ログイン完了なら、ログイン状態を維持する処理へ(SampleController@sessStart)

      if($('input').val() == "123"){
        location.href = "/sessStart";
      }
      return;
    });
  });
</script>

<form>
  <input type="text" value="123">
  <button>LOGIN</button>
</form>

top.blade.php~logout.blade.php

top.blade.php
<a href="/second">second</a> | <a href="/logout">logout</a>
<p>
top
second.blade.php
<a href="/second">top</a> | <a href="/logout">logout</a>
<p>
second
logout.blade.php
<a href="/second">top</a> | <a href="/second">second</a>
<p>
<a href="deleteSess">LOGOUT</a>

メモ

Undefined variable: _SESSION
session_start()が正しく実行されていないときに出た!

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

Mockeryで正規表現を使う

環境

  • Laravel Framework 6.0.3
  • Mockery 1.0
  • Docker 19.03.4 (Laravelの実行環境)

背景

Laravelではファサードをモックしたテストを手軽に書く事ができます。公式ドキュメントにもある通り、モックされたファサードはMockeryインスタンスを返します。そのため、Mockery::withでファサードの引数を検証する事ができます。

課題

ファサードの引数にランダムな値が含まれる場合などにwithで正規表現を使いたい場合、直感的に正規表現を書いても認識されません。

以下のようなファイルをアップロードするコマンドがあるとします。同名のファイルが存在する場合は、上書きしないように元の名前にユニークな値を追記したファイル名でアップロードします。

コマンド

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;

class FileUploadCommand extends Command
{
    protected $signature = 'uploadfile';

    public function handle()
    {
        $filename = 'uploadfile.txt';
        $content = 'これからアップロードされるファイルです';
        if (! Storage::disk('backups')->exists($filename)) {
           Storage::disk('backups')->put($filename, $content);
           Log::info('新規ファイルがアップロードされました。ファイル名:' . $filename);
        } else {
           $rename = sprintf('%s.%s', $filename, Str::uuid());
           Log::info('既に同名のファイルが存在したためリネームしました。ファイル名:' . $rename);
        }
    }
}

テスト

withに正規表現っぽい値を入れて、リネーム処理のテストを書いてみます。

<?php

namespace Tests\Feature;

use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Mockery;
use Tests\TestCase;

class FileUploadCommandTest extends TestCase
{
    public function testリネーム処理()
    {
        Storage::disk('backups')->put(
            'uploadfile.txt',
            'これはアップロード済みファイルです'
        );
        Log::shouldReceive('info')->once()->with("/既に同名のファイルが存在したためリネームしました。ファイル名:/");

        $this->artisan('uploadfile');
    }
}

テスト実行

[root@1b8af3a695ec www]# vendor/bin/phpunit tests/Feature/FileUploadCommandTest.php
PHPUnit 8.3.5 by Sebastian Bergmann and contributors.

E                                                                   1 / 1 (100%)

Time: 1.11 seconds, Memory: 24.00 MB

There was 1 error:

1) Tests\Feature\FileUploadCommandTest::testリネーム処理()
Mockery\Exception\NoMatchingExpectationException: No matching handler found for Mockery_0_Illuminate_Log_LogManager::info('既に同名のファイルが存在したためリネームしました。ファイル名:uploadfile.txt.c91c2c81-f26a-4c02-8dda-5e9c260af597'). Either the method was unexpected or its arguments matched no expected argument list for this method

実行しても正規表現としては、見なされないようでテストは失敗します^^;

解決方法

Mockery::patternを使います。

テストコードを修正

正規表現っぽく書いた場所をMockery::patternを使って書き直してみます。

- Log::shouldReceive('info')->once()->with("/既に同名のファイルが存在したためリネームしました。ファイル名:/");
+ Log::shouldReceive('info')->once()->with(Mockery::pattern("/既に同名のファイルが存在したためリネームしました。ファイル名:/"));

テスト再実行

[root@1b8af3a695ec www]# vendor/bin/phpunit tests/Feature/FileUploadCommandTest.php
PHPUnit 8.3.5 by Sebastian Bergmann and contributors.

.                                                                   1 / 1 (100%)

Time: 1.76 seconds, Memory: 24.00 MB

OK (1 test, 2 assertions)

?

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

Osclassを検討して撤退を決めたまでの記録

Osclassは、クラシファイドサービス(とかマッチングとか出会い系)サイトが作れるPHP製のCMS。
これを使って楽がしたかったんだ。

概要

  • 2019年9月に開発終了 → forkされて続いてはいる
  • テーマとプラグインのマーケットも終了
    • 代替マーケットも活気がない
  • 広告商品のカテゴリ毎にページデザインを変更できない?
  • できることがよくわからない
    • Show caseの情報が少ない
    • テーマ自作の詳細な解説が見付からない
    • マーケットが死んでいるので、実際のテーマやプラグインからアイデアが得られない
    • →コードを見るしかない
  • →撤退しました

調査

とりあえず動かしてみよう!

インストールガイド:https://osclass.gitbook.io/osclass-docs/beginners/install
…じょ、情報量が少ない…

ので、とりあえず遊びたい方々のために「VagrantでCentOS7を作ってOsclassを起動するスクリプト」をご用意しました。

ファイル

Vagrantfile
Vagrant.configure("2") do |config|
  config.vm.box = "centos/7"
  config.vm.network "forwarded_port", guest: 80, host: 8080
  config.vm.provision :shell, path: './setting.sh', privileged: true
end

必須じゃないもの入りまくってると思います。

setting.sh
#!/bin/sh
yum update
yum install vim
echo "set number" >> ~/.vimrc
yum -y install https://centos7.iuscommunity.org/ius-release.rpm
yum -y install git2u yum-utils
yum-config-manager --disable ius
yum -y install zlib zlib-devel openssl-devel sqlite-devel gcc-c++ glibc-headers libyaml-devel readline readline-devel libffi-devel curl
yum -y remove mariadb-libs
rm -rf /var/lib/mysql
rpm -ivh http://dev.mysql.com/get/mysql57-community-release-el7-8.noarch.rpm
yum -y install mysql mysql-devel mysql-server
systemctl start mysqld.service
systemctl enable mysqld.service
mysql_root_path=`cat /var/log/mysqld.log | grep root@localhost | awk '{ print $11 }'`
echo "export OSCLASS_DATABASE_PASSWORD=\"${mysql_root_path}\"" >> ~/.bashrc
mysql -uroot -p${mysql_root_path} --connect-expired-password -e "ALTER USER 'root'@'localhost' IDENTIFIED BY '${mysql_root_path}'; flush privileges;"
mysql -uroot -p${mysql_root_path} -e "GRANT ALL PRIVILEGES ON osclass.* TO osclassuser@localhost IDENTIFIED BY '${mysql_root_path}' WITH GRANT OPTION;"
mysql -uroot -p${mysql_root_path} -e "FLUSH PRIVILEGES;"
mysql -uroot -p${mysql_root_path} -e "CREATE DATABASE osclass;"
yum -y install httpd httpd-tools httpd-devel httpd-manual
yum -y install http://rpms.famillecollet.com/enterprise/remi-release-7.rpm
yum -y install --enablerepo=remi,remi-php73 php php-mbstring php-xml php-xmlrpc php-gd php-pdo php-pecl-mcrypt php-mysqlnd php-pecl-mysql
curl -LO https://github.com/navjottomer/Osclass/releases/download/v3.9.0/osclass-v3.9.0.zip
yum -y install unzip
unzip osclass-v3.9.0.zip
cp -r osclass/* /var/www/html
rm -rf osclass
rm -f osclass-v3.9.0.zip
chown apache:apache /var/www/html
chown -R apache:apache /var/www/html/oc-content/{uploads,downloads,languages}
chcon -t httpd_sys_script_rw_t /var/www/html
chcon -R -t httpd_sys_script_rw_t /var/www/html/oc-content/{uploads,downloads,languages}
/usr/sbin/setsebool -P httpd_can_network_connect=1
systemctl start httpd.service
systemctl enable httpd.service

ssh-keygen -t rsa -b 4096 -N "" -f ~vagrant/.ssh/id_rsa
eval "$(ssh-agent -s)"
ssh-add ~vagrant/.ssh/id_rsa
cat ~vagrant/.ssh/id_rsa.pub
echo "database name: osclass"
echo "database username: osclassuser"
echo "database password: ${mysql_root_path}"

参考:マッチングサイト向けCMS osclass - Qiita

使い方

[1] 好きなところに置く

$ ls
Vagrantfile setting.sh

[2] vagrant upする

$ vagrant up

[3] 接続情報が出る

    default: ssh-rsa { git用ssh公開鍵 }
    default: database name: osclass # mysql DB name
    default: database username: osclassuser # mysql username
    default: database password: { mysql password }

[4] localhost:8080/index.phpに繋ぎ、mysqlデータベースの接続情報と管理者アカウントの設定を済ませる。

[5] ログインするとダッシュボードに入れた。
image.png

基礎調査

リポジトリ

大元での開発が終了している

ここ:https://github.com/osclass/Osclass
…が、開発が終了している。

fork後のリポジトリはここ:https://github.com/navjottomer/Osclass
現在もそれなりの頻度で開発は進められている。

マーケット

公式マーケットが潰れている

なんと公式マーケットがメニューにない!
image.png
2019/09/05に終了していたらしい。よってメニューからも消えた。
「osclass market」のサービスが2019年9月5日に終了!!影響と今後の対策 - 月収20万アフィリエイターの作業ログ。

これについての外部マーケットさんのコメントがこちら。
Osclass Market has been closed! OsclassPoint.com became most popular osclass market! - OsclassPoint

代替マーケットも活気がない

https://osclasspoint.com/search
https://osclass.market/products
https://market.osclasscommunity.com/themes

商品は1〜2桁、ダウンロードも1〜2桁くらい。
潰れた公式マーケットから流れたものも入っていると考えると、新作テーマ・プラグインの開発はほぼ行われていないと思われる。

事例

公式のshowcaseページも運営終了
https://osclass.org/showcase

この辺のサイトがOsclassらしい
https://jmty.jp/
https://www.perdiomeu.com.br/
https://www.aloha-street.com/classified/
https://search-lesson.com/
ジモティーは今はOsclassではないと小耳に挟んだりもした。だとすると夢がない。

参考:
オープンソースでマッチングサイトが構築できるOsclassを導入してみた - はてな村定点観測所
Osclassで構築されたサイト事例 - 日本語で作る無料マッチングサイトOsclass

そのまま使ってみる

設定項目

image.png

カテゴリ

カテゴリ別のページデザインにはできない…!?
静的ページを使えってことかな?
項目の「有無」はうまくやればできそう。それ以上のカスタマイズがどれくらい面倒かは不明。
image.png

静的なページ

普通。ソース直書きもできる。
image.png

画像や動画の挿入も普通。特に変な装飾はされない。
image.png
出典:【公式】アニメ「ポケットモンスター」第1話「ピカチュウ誕生!」

連絡手段

基本的にはボタン押したらメール。
くらしのマーケットが提供しているような「チャットっぽい」機能はない。
「カレンダーから予約する」的な機能(実際はそういうメール)はフォームというかテーマのカスタマイズで実装できそう。

テーマを作る・探す

開発者用ガイドを見る

https://osclass.gitbook.io/osclass-docs/developers/plugins-themes
…ごめんなさい、よくわかりません。

既存テーマを探す

こういう時は既存のテーマからインスピレーションを得よう!

…が、前述の通りマーケットが死んでいるので無料テーマが全然試せない。
そのためだけに外部マーケットにユーザ登録するのもちょっと嫌ですね。活気ないし。
1つ試してみたが、レスポンシブでなく(デフォルトテーマと)機能上の違いもなさそうだった。
image.png

Wordpressでもできる?

Wordpressにはクラシファイドサービス用のテーマもいくつかあるらしい。今度触ってみよう。
マッチングサイトができるWordPressテーマ10選 - YELLOW GLASSES

まとめ

辛かったので今日のところは撤退します。

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

「Laravel DB Designer 」vol.3 使い方・仕様 について解説

今回は" Laravel DB Designer "の使い方・仕様について書きました(vol3)

『Laravelを使う人を幸せにしたいという思いから作った』

(vol2の続きです)[https://qiita.com/daisu_yamazaki/items/92dc3cc599a264c3fb0f]

e.jpg

https://laraveldb.com
※英語圏対応済み

主機能

  • ER図作成 (対応している”型”はページ下部に表記)
  • ER図作成 → Migrationファイルを生成
  • ER図作成 → チェック用クエリービルダーを自動生成
  • Migrationファイル → ER図を生成(リバース)

テーブル名

テーブル名の頭に"m_"を付けた場合(Master:都道府県のように最初から用意するテーブル)

  • 「 m_テーブル名 」とすると" $table->softDeletes(); "は追加されません

  • 「 m_テーブル名 」とすると" $table->timestamps(); "は追加されません

テーブル名の頭に"t_"を付けた場合(Transaction:ユーザーの入力でデータが追加されていくテーブル)

  • 「 t_テーブル名 」とすると" $table->softDeletes(); "が自動で追加されます

  • 「 t_テーブル名 」とすると" $table->timestamps(); "が自動で追加されます

テーブル名の頭に"t_"も"m_"も付けない場合(接頭辞を付けない場合)

  • "m_" や "t_"を付けなければ " $table->softDeletes(); "が自動で追加されます

  • "m_" や "t_"を付けなければ "$table->timestamps(); "が自動で追加されます

image.png

【使用時の気をつけるPOINT】

1)
フォルダにMigrationファイル(Schema::createのみ)一式集めZip圧縮したファイルをアップロードすることで、ER図へ変換(リバース)することが可能です。

2)
以下Migrationファイル 「 Schema::create 」のみ現在は可能
※ Schema::create以外は対応検討中

Schema::create("テーブル名", function (Blueprint $table) {...}

3)
外部キー(使った場合)親子の順番でMigrationファイルを選び、Migrateしなくてはいけない
※ 親子順でファイル名(時間等)を少しずらし対応検討中

4)
ダウンロードしたMigrationファイル(ZIP)をそのまま再アップロードは出来ません
一度解凍してから自身のPCでZIPしてアップロードしてください。(PHPでの圧縮アルゴリズムの問題かも)
※ 今後の調査対象の一つ

5)
MySQLのみ対応
※ 要望が多ければPostgres,SQLite等の対応も検討

「ER図のSave/Load」機能

image.png

ER図データのLoad/Save

Save/Load機能 機能詳細
クラウドへ保存 Web上のDB(Firebase)に保存します。
クラウドデータ一覧 自身がWebに保存したデータ一覧
ブラウザに保存 LocalStorageに一時保存
ブラウザデータ一覧 自身がlocalに保存したデータ一覧

上記の「データ一覧」選択後、「 -- Data List -- 」の選択肢が表示されます。
そこに表示されるデータ項目を選択するとER図が復元します。

ER図から出力(外部出力)

Save/Load機能 機能詳細
ER図からSQLを作成 現在表示しているEQ図からMySQLテーブルを作成するSQL文を作成
Laravel(Migration) 現在表示しているEQ図からLaravel専用のMigrationファイルをZIP圧縮して一式ダウンロード

子テーブルへの外部キー制約が記載されてるMigrationファイルは、
「 5分遅らせた 」ファイル名が生成しています(現時点)。
理由)親テーブルをMigrateしてから子テーブルをMigrateしないとエラーになるため最低限の対応を追加しました。
今後は、外部キーの親・子を全て判断して順番を「時間でずらすことで対応」していこうと考えています(未実装)。

Reverse ERD

Migrationファイル一式をZIP圧縮 → [ Reverse >>> ERD ]ボタンでアップロード
アップロード完了するとER図が表示されます。

Migration(ZIPファイルに一式纏めて) 機能詳細
[ Reverse >>> ERD ] Migrationファイル一式をフォルダに入れて、ZIP圧縮したファイルをアップロード

<< 要注意 >>
「Laravel DB Designer」からZIPファイルをダウンロードしたファイルをそのままアップロードは出来ません。必ず、一度解凍したものをZIP圧縮しなおしてuploadしてください。

今回vol3のまとめ

今回は「 Laravel DB Designer 」の操作方法とメイン機能である「 Save/Load 」と「 出力 」の解説をさせていただきました。まだまだUXの部分には力をいれられてないので、こういった使用説明が必要だと思い書きました。
少しでもご理解いただき使用していただければと存じます。
また、説明が抜けてるところがあるかもしれません、随時更新、内容によっては新しく解説記事を投稿して行こうと思います。

『Laravelを使う人を幸せにしたいという思いから作った』
https://laraveldb.com

以上
今後とも宜しくお願い致します。

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

【 Laravel 】「Laravel DB Designer」で設計から実装まで「ER図←→Migration」相互変換!” 「使い方・仕様 」について解説” vol3

今回は" Laravel DB Designer "の「 使い方・仕様 」について書きました(vol3)

『Laravelを使う人を幸せにしたいという思いから作った』
https://laraveldb.com
※英語圏対応済み

e.jpg

主機能

  • ER図作成 (対応している”型”はページ下部に表記)
  • ER図作成 → Migrationファイルを生成
  • ER図作成 → チェック用クエリービルダーを自動生成
  • Migrationファイル → ER図を生成(リバース)

テーブル名

テーブル名の頭に"m_"を付けた場合(Master:都道府県のように最初から用意するテーブル)

  • 「 m_テーブル名 」とすると" $table->softDeletes(); "は追加されません

  • 「 m_テーブル名 」とすると" $table->timestamps(); "は追加されません

テーブル名の頭に"t_"を付けた場合(Transaction:ユーザーの入力でデータが追加されていくテーブル)

  • 「 t_テーブル名 」とすると" $table->softDeletes(); "が自動で追加されます

  • 「 t_テーブル名 」とすると" $table->timestamps(); "が自動で追加されます

テーブル名の頭に"t_"も"m_"も付けない場合(接頭辞を付けない場合)

  • "m_" や "t_"を付けなければ " $table->softDeletes(); "が自動で追加されます

  • "m_" や "t_"を付けなければ "$table->timestamps(); "が自動で追加されます

image.png

【使用時の気をつけるPOINT】

1)
フォルダにMigrationファイル(Schema::createのみ)一式集めZip圧縮したファイルをアップロードすることで、ER図へ変換(リバース)することが可能です。

2)
以下Migrationファイル 「 Schema::create 」のみ現在は可能
※ Schema::create以外は対応検討中

Schema::create("テーブル名", function (Blueprint $table) {...}

3)
外部キー(使った場合)親子の順番でMigrationファイルを選び、Migrateしなくてはいけない
※ 親子順でファイル名(時間等)を少しずらし対応検討中

4)
ダウンロードしたMigrationファイル(ZIP)をそのまま再アップロードは出来ません
一度解凍してから自身のPCでZIPしてアップロードしてください。(PHPでの圧縮アルゴリズムの問題かも)
※ 今後の調査対象の一つ

5)
MySQLのみ対応
※ 要望が多ければPostgres,SQLite等の対応も検討

「ER図のSave/Load」機能

image.png

ER図データのLoad/Save

Save/Load機能 機能詳細
クラウドへ保存 Web上のDB(Firebase)に保存します。
クラウドデータ一覧 自身がWebに保存したデータ一覧
ブラウザに保存 LocalStorageに一時保存
ブラウザデータ一覧 自身がlocalに保存したデータ一覧

上記の「データ一覧」選択後、「 -- Data List -- 」の選択肢が表示されます。
そこに表示されるデータ項目を選択するとER図が復元します。

ER図から出力(外部出力)

Save/Load機能 機能詳細
ER図からSQLを作成 現在表示しているEQ図からMySQLテーブルを作成するSQL文を作成
Laravel(Migration) 現在表示しているEQ図からLaravel専用のMigrationファイルをZIP圧縮して一式ダウンロード

子テーブルへの外部キー制約が記載されてるMigrationファイルは、
「 5分遅らせた 」ファイル名が生成しています(現時点)。
理由)親テーブルをMigrateしてから子テーブルをMigrateしないとエラーになるため最低限の対応を追加しました。
今後は、外部キーの親・子を全て判断して順番を「時間でずらすことで対応」していこうと考えています(未実装)。

Reverse ERD

Migrationファイル一式をZIP圧縮 → [ Reverse >>> ERD ]ボタンでアップロード
アップロード完了するとER図が表示されます。

Migration(ZIPファイルに一式纏めて) 機能詳細
[ Reverse >>> ERD ] Migrationファイル一式をフォルダに入れて、ZIP圧縮したファイルをアップロード

<< 要注意 >>
「Laravel DB Designer」からZIPファイルをダウンロードしたファイルをそのままアップロードは出来ません。必ず、一度解凍したものをZIP圧縮しなおしてuploadしてください。

今回vol3のまとめ

今回は「 Laravel DB Designer 」の操作方法とメイン機能である「 Save/Load 」と「 出力 」の解説をさせていただきました。まだまだUXの部分には力をいれられてないので、こういった使用説明が必要だと思い書きました。
少しでもご理解いただき使用していただければと存じます。
また、説明が抜けてるところがあるかもしれません、随時更新、内容によっては新しく解説記事を投稿して行こうと思います。

『Laravelを使う人を幸せにしたいという思いから作った』
https://laraveldb.com

以上
今後とも宜しくお願い致します。

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

【 Laravel 】「Laravel DB Designer 」を便利に使うための知識 ”使い方・仕様 ”について解説 Vol.3

今回は" Laravel DB Designer "の使い方・仕様について書きました(vol3)

『Laravelを使う人を幸せにしたい』という思いから作った「Laravel DB Designer」
(vol2の続きです)[https://qiita.com/daisu_yamazaki/items/92dc3cc599a264c3fb0f]

e.jpg

https://laraveldb.com
※英語圏対応済み

主機能

  • ER図作成 → 対応している”型”はvol2記事の下へ
  • ER図作成 → Migrationファイルを生成
  • ER図作成 → チェック用クエリービルダーを自動生成
  • Migrationファイル → ER図を生成(リバース)再設計可能

テーブル名

テーブル名の頭に"m_"を付けた場合(Master:都道府県のように最初から用意するテーブル)

  • 「 m_テーブル名 」とすると" $table->softDeletes(); "は追加されません

  • 「 m_テーブル名 」とすると" $table->timestamps(); "は追加されません

テーブル名の頭に"t_"を付けた場合(Transaction:ユーザーの入力でデータが追加されていくテーブル)

  • 「 t_テーブル名 」とすると" $table->softDeletes(); "が自動で追加されます

  • 「 t_テーブル名 」とすると" $table->timestamps(); "が自動で追加されます

テーブル名の頭に"t_"も"m_"も付けない場合(接頭辞を付けない場合)

  • "m_" や "t_"を付けなければ " $table->softDeletes(); "が自動で追加されます

  • "m_" や "t_"を付けなければ "$table->timestamps(); "が自動で追加されます

「ER図のSave/Load」機能

ER図データのLoad/Save

Save/Load機能 機能詳細
クラウドへ保存 Web上のDB(Firebase)に保存します。
クラウドデータ一覧 自身がWebに保存したデータ一覧
ブラウザに保存 LocalStorageに一時保存
ブラウザデータ一覧 自身がlocalに保存したデータ一覧

上記の「データ一覧」選択後、「 -- Data List -- 」の選択肢が表示されます。
そこに表示されるデータ項目を選択するとER図が復元します。

ER図から出力(外部出力)

Save/Load機能 機能詳細
ER図からSQLを作成 現在表示しているEQ図からMySQLテーブルを作成するSQL文を作成
Laravel(Migration) 現在表示しているEQ図からLaravel専用のMigrationファイルをZIP圧縮して一式ダウンロード

子テーブルへの外部キー制約が記載されてるMigrationファイルは、
「 5分遅らせた 」ファイル名が生成しています(現時点)。
理由)親テーブルをMigrateしてから子テーブルをMigrateしないとエラーになるため最低限の対応を追加しました。
※子の子テーブル等の外部キー制約は自身で順番にMigrateの必要があります!

Reverse ERD

フォルダにMigrationファイル(Schema::createのみ)一式集めZip圧縮したファイルをアップロードすることで、ER図へ変換(リバース)することが可能です。

Migrationファイル一式をZIP圧縮 → [ Reverse >>> ERD ]ボタンでアップロード
アップロード完了するとER図が表示されます。

Migration(ZIPファイルに一式纏めて) 機能詳細
[ Reverse >>> ERD ] Migrationファイル一式をフォルダに入れて、ZIP圧縮したファイルをアップロード

1.注意
以下Migrationファイル 「 Schema::create 」のみ現在は可能
※ Schema::create以外は対応検討中

Schema::create("テーブル名", function (Blueprint $table) {...}

2.注意
「Laravel DB Designer」からZIPファイルをダウンロードしたファイルをそのままアップロードは出来ません。必ず、一度解凍したものをZIP圧縮しなおしてuploadしてください。

今回vol3のまとめ

今回は「 Laravel DB Designer 」の操作方法とメイン機能である「 Save/Load 」と「 出力 」の解説をさせていただきました。まだまだUXの部分には力をいれられてないので、こういった使用説明が必要だと思い書きました。

また、シンプルな記法(ベーシックな?)をベースに仕様/処理を考えたため、複雑な、又はイレギュラーな記述が入ってるケースでは思った通りの出力にならないこともあるかも知れません。しかし、1から全て書いて行くよりは、楽になると思っています。また、設計後に再度ER図からのやり返しができるので、そこも利点だと思います。
少しでもご理解いただき使用していただければと存じます。

また、説明が抜けてるところがあるかもしれません、随時更新、内容によっては新しく解説記事を投稿して行こうと思います。(現在はMySQLのみ対応:要望が多ければPostgres,SQLite等の対応も検討する予定です)

『Laravelを使う人を幸せにしたい』という思いから作った
Laravel DB Designer https://laraveldb.com
今後とも宜しくお願い致します。

以上、今回はここまで。

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

「Laravel DB Designer 」vol.3 「使い方・仕様 」について解説”

今回は" Laravel DB Designer "の「 使い方・仕様 」について書きました(vol3)

『Laravelを使う人を幸せにしたいという思いから作った』
https://laraveldb.com
※英語圏対応済み

e.jpg

主機能

  • ER図作成 (対応している”型”はページ下部に表記)
  • ER図作成 → Migrationファイルを生成
  • ER図作成 → チェック用クエリービルダーを自動生成
  • Migrationファイル → ER図を生成(リバース)

テーブル名

テーブル名の頭に"m_"を付けた場合(Master:都道府県のように最初から用意するテーブル)

  • 「 m_テーブル名 」とすると" $table->softDeletes(); "は追加されません

  • 「 m_テーブル名 」とすると" $table->timestamps(); "は追加されません

テーブル名の頭に"t_"を付けた場合(Transaction:ユーザーの入力でデータが追加されていくテーブル)

  • 「 t_テーブル名 」とすると" $table->softDeletes(); "が自動で追加されます

  • 「 t_テーブル名 」とすると" $table->timestamps(); "が自動で追加されます

テーブル名の頭に"t_"も"m_"も付けない場合(接頭辞を付けない場合)

  • "m_" や "t_"を付けなければ " $table->softDeletes(); "が自動で追加されます

  • "m_" や "t_"を付けなければ "$table->timestamps(); "が自動で追加されます

image.png

【使用時の気をつけるPOINT】

1)
フォルダにMigrationファイル(Schema::createのみ)一式集めZip圧縮したファイルをアップロードすることで、ER図へ変換(リバース)することが可能です。

2)
以下Migrationファイル 「 Schema::create 」のみ現在は可能
※ Schema::create以外は対応検討中

Schema::create("テーブル名", function (Blueprint $table) {...}

3)
外部キー(使った場合)親子の順番でMigrationファイルを選び、Migrateしなくてはいけない
※ 親子順でファイル名(時間等)を少しずらし対応検討中

4)
ダウンロードしたMigrationファイル(ZIP)をそのまま再アップロードは出来ません
一度解凍してから自身のPCでZIPしてアップロードしてください。(PHPでの圧縮アルゴリズムの問題かも)
※ 今後の調査対象の一つ

5)
MySQLのみ対応
※ 要望が多ければPostgres,SQLite等の対応も検討

「ER図のSave/Load」機能

image.png

ER図データのLoad/Save

Save/Load機能 機能詳細
クラウドへ保存 Web上のDB(Firebase)に保存します。
クラウドデータ一覧 自身がWebに保存したデータ一覧
ブラウザに保存 LocalStorageに一時保存
ブラウザデータ一覧 自身がlocalに保存したデータ一覧

上記の「データ一覧」選択後、「 -- Data List -- 」の選択肢が表示されます。
そこに表示されるデータ項目を選択するとER図が復元します。

ER図から出力(外部出力)

Save/Load機能 機能詳細
ER図からSQLを作成 現在表示しているEQ図からMySQLテーブルを作成するSQL文を作成
Laravel(Migration) 現在表示しているEQ図からLaravel専用のMigrationファイルをZIP圧縮して一式ダウンロード

子テーブルへの外部キー制約が記載されてるMigrationファイルは、
「 5分遅らせた 」ファイル名が生成しています(現時点)。
理由)親テーブルをMigrateしてから子テーブルをMigrateしないとエラーになるため最低限の対応を追加しました。
今後は、外部キーの親・子を全て判断して順番を「時間でずらすことで対応」していこうと考えています(未実装)。

Reverse ERD

Migrationファイル一式をZIP圧縮 → [ Reverse >>> ERD ]ボタンでアップロード
アップロード完了するとER図が表示されます。

Migration(ZIPファイルに一式纏めて) 機能詳細
[ Reverse >>> ERD ] Migrationファイル一式をフォルダに入れて、ZIP圧縮したファイルをアップロード

<< 要注意 >>
「Laravel DB Designer」からZIPファイルをダウンロードしたファイルをそのままアップロードは出来ません。必ず、一度解凍したものをZIP圧縮しなおしてuploadしてください。

今回vol3のまとめ

今回は「 Laravel DB Designer 」の操作方法とメイン機能である「 Save/Load 」と「 出力 」の解説をさせていただきました。まだまだUXの部分には力をいれられてないので、こういった使用説明が必要だと思い書きました。
少しでもご理解いただき使用していただければと存じます。
また、説明が抜けてるところがあるかもしれません、随時更新、内容によっては新しく解説記事を投稿して行こうと思います。

『Laravelを使う人を幸せにしたいという思いから作った』
https://laraveldb.com

以上
今後とも宜しくお願い致します。

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

php.iniの場所・パスを調べる方法

php.iniを変更したいけど、場所がわからない時、ありますよね。
そんな時はこれ↓

$ php -i | grep php.ini
Configuration File (php.ini) Path => /Applications/MAMP/bin/php/php7.1.31/conf
Loaded Configuration File => /Applications/MAMP/bin/php/php7.1.31/conf/php.ini
参考

https://qiita.com/tmsanrinsha/items/2fda05db29b62090e3de

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

配列の要素をフィルタリング(array_filter, array_reduce)

配列の要素をフィルタリングする(array_filter, array_reduce)

次のような連想配列からvalueが偶数の要素のみを取り出します。

index.php
$array = [
    [ 'number' => 1 ],
    [ 'number' => 2 ],
    [ 'number' => 3 ],
    [ 'number' => 4 ],
    [ 'number' => 5 ],
    [ 'number' => 6 ],
    [ 'number' => 7 ],
    ];

こちらを一旦var_dump()しておきます。

index.php
array(7) {
  [0]=>
  array(1) {
    ["number"]=>
    int(1)
  }
  [1]=>
  array(1) {
    ["number"]=>
    int(2)
  }
  [2]=>
  array(1) {
    ["number"]=>
    int(3)
  }
  [3]=>
  array(1) {
    ["number"]=>
    int(4)
  }
  [4]=>
  array(1) {
    ["number"]=>
    int(5)
  }
  [5]=>
  array(1) {
    ["number"]=>
    int(6)
  }
  [6]=>
  array(1) {
    ["number"]=>
    int(7)
  }
}

このような構造の配列になっております(添字に注目)

まずはarray_filter()を使ってvalueが偶数の物を取り出していきましょう。

array_filter()

index.php
$array_even = array_filter($array, function ($int) {
    return $int['number'] % 2 === 0;
});

こちらをvar_dump()してみます。

index.php
array(3) {
  [1]=>
  array(1) {
    ["number"]=>
    int(2)
  }
  [3]=>
  array(1) {
    ["number"]=>
    int(4)
  }
  [5]=>
  array(1) {
    ["number"]=>
    int(6)
  }
}

うまく取り出せました。
添字を見てみると、$arrayの添字がそのまま使われています。
こちらがarray_filter()の挙動です。

続いてarray_reduce()を使って同様の処理を行っていきます。

array_reduce()

index.php
$array_even = array_reduce($array, function ($number, $int) {
    if ($int['number'] % 2 === 0) {
        $number[] = $int;
    }
    return $number;
});

こちらをvar_dump()してみると

index.php
array(3) {
  [0]=>
  array(1) {
    ["number"]=>
    int(2)
  }
  [1]=>
  array(1) {
    ["number"]=>
    int(4)
  }
  [2]=>
  array(1) {
    ["number"]=>
    int(6)
  }
}

array_filter()と同様にvalueに偶数を持つ要素を取り出すことができました。
添字を見てみると、添字がリセットされ0-basedな配列になっています

単に配列をフィルタリングする際には、array_filter()を、添字も使用する処理ならばarray_reduce()を使用すると良いでしょう

追記:array_filter()してarray_values()してもo-basedな配列にすることができます。

以上が配列をフィルタリングする際のarray_filter()array_reduce()の挙動の違いでした。
ご閲覧ありがとうございました。

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