CakePHP3にてシェルとタスクを利用してコマンドラインからデータベースのデータを操作する

開発環境は、Windows 10 Pro(64bit) + PHP 7.2.12 + CakePHP 3.6.14 + XAMPP Control Panel v3.2.2。

基本的な操作

以下のプログラムをHelloShell.phpの名前でsrc/Shellディレクトリ内に保存する。

<?php

namespace App\Shell;

use Cake\Console\Shell;

class HelloShell extends Shell
{
    public function main()
    {
        $this->out(__('Hello world.'));
    }
}

?>

コマンドラインのカレントディレクトリをアプリのルートディレクトリにしてから、

bin\cake hello

と入力すると、Hello world.と表示されます。
main()関数の中に処理を書いておくと、

bin\cake hello main

のように書かなくても、省略して実行できます。なので、main()関数以外の名前で、関数を使いたければ、例えば、hoge()と書いて、その中の処理を書いて、実行する際は、

bin\cake hello hoge

と入力すればOKです。

データベースへアクセスして操作してみる

1.テストのために以下のテーブルを作成します。

create table samples(
  id int auto_increment primary key,
  data varchar(255) not null,
  created datetime,
  modified datetime
)charset=utf8mb4;

2.カレントディレクトリをアプリのルートディレクトリにして以下のコマンドを入力して、作成したテーブルに関係するファイルを自動的に作成しておきます。

bin\cake bake all samples

3.上記のHelloShell.phpを以下のソースコードに置き換えてください

<?php
namespace App\Shell;

use Cake\Console\Shell;

class HelloShell extends Shell
{
    public $tasks = ['Template'];

    public function main($taskname = '')
    {
				if($taskname === 'add'){
					$this->Template->main();
				}else if($taskname === 'delete'){
					$this->Template->delete();
				}else{
					$this->out(__('No Task.'));
				}
    }
}
?>

関数に引数を書くとコマンドラインから入力された値を受け取ることができます。


4. .src/Shellディレクトリ内にTaskディレクトリを作成します。

5.次に、Taskディレクトリ内に、TemplateTask.phpの名前で以下のコードを保存します。

<?php
namespace App\Shell\Task;

use Cake\Console\Shell;
use Cake\I18n\Time;
use Cake\ORM\TableRegistry;

class TemplateTask extends Shell
{

		public function initialize(){
			  date_default_timezone_set('Asia/Tokyo');
		}

    public function main()
    {
				$samples = TableRegistry::getTableLocator()->get('Samples');
				$query = $samples->query();
				$query->insert(['data','created','modified'])
					->values([
						'data' => '投稿しました',
						'created' => Time::now(),
						'modified' => Time::now()
					])
					->execute();
        $this->out(__('Insert Data.'));
    }

		public function delete(){
				$samples = TableRegistry::getTableLocator()->get('Samples');
				$query = $samples->query();
				$query->delete()
				->where(function($exp, $q){
					return $exp->lte("created", new Time('1 hours ago') );
				})
				->execute();

		$this->out(__('Delete Data.'));
		}
}
?>

6.カレントディレクトリをアプリのルートディレクトリにして、
以下のコマンドを実行すると、データが追加されます。

bin\cake hello add

以下のコマンドを実行すると、データを入力して1時間経過したデータを削除します。

bin\cake hello delete

それ以外に、単に、

bin\cake hello

と入力したり、hello以降に適当な値を入力しても、

bin\cake hello hoge

No Task.というメッセージが表示されるだけになります。


・Authコンポーネントを利用して認証機能を実装して、ログインしないと、データを追加や更新や削除できないようにしても、シェル経由で、データを追加や更新や削除することができるみたいです。


■本番環境ではどうなのか?(ロリポップの場合)
レンタルサーバーのロリポップのスタンダードプランでやってみたところ、CakePHPは普通に動作できるが、cronを使用したり、SSLでアクセスして、手動で実行させようと、bin/cake.phpを動作させると、PHPのバージョンはPHP 5.5.35 (cli) で、CakePHPを使用するには、5.6.0以上にしろと表示され、実行できない。

そこで、推奨できないが、緊急策として、CakePHPを介さずに、PHPでデータベースに直接アクセスして、データを追加するプログラムを作ってみた。このプログラムを実行するたびに、samplesテーブルにデータが追加される。

<?php

date_default_timezone_set('Asia/Tokyo');
$now = date("Y/m/d H:i:s");
$url = "";
$user = "";
$password = "";
$database = "";
$connect = mysql_connect($url,$user,$password) or die("can't connect");
$db = mysql_select_db($database, $connect) or die("can't Select database");
$sql = "INSERT INTO samples (data,created,modified) VALUES ('test', '$now', '$now');";
$result = mysql_query($sql,$connect);
echo $result;

?>

ただ、

上記のプログラムを検証してみると、SSLでログインして、php 絶対パスor 相対パスでのphpのプログラム名では、うまく動作するが、cronで、そのプログラムを指定すると、うまく動作しなかった。原因は分からないが、検証したところ、どうも、mysql_connect部分がおかしいみたい。

そこで、以下のようなPDOを利用したプログラムに切り替えると、cronでもきちんと動作した。

<?php

date_default_timezone_set('Asia/Tokyo');
$now = date("Y/m/d H:i:s");

$url = "";
$user = "";
$password = "";
$database = "";

$dbh = new PDO("mysql:dbname=$database;host=$url",$username,$password);

$count = $dbh->exec("INSERT INTO samples (data,created,modified) VALUES ('test', '$now', '$now')");
echo $count;

?>

参考リンク
シェル - 3.7
日付と時刻 - 3.7
データベースアクセス & ORM - 3.7
クエリービルダー - 3.7
PHPでデータベースに接続するときのまとめ - Qiita
データの追加(INSERT文) - データの追加と削除 - MySQLの使い方
PHPでmysql_connect関数を使いMySQLへ接続するサンプルです。 · GitHub
PHP: PDO - Manual
データの削除(DELETE文) - データの追加と削除 - MySQLの使い方

ロリポップのcronでプログラムを定期実行してみる

プランによってcronの使用制限があります。自分の場合はスタンダードなので、
10個までcronが登録できて、1分毎に作動できます。
cron設定 / サーバー・プログラム / マニュアル - レンタルサーバーならロリポップ!

今回はテストとしてサンプルプログラムを1分ごとに起動したいと思います。

1.ユーザー管理ページへログインする
https://user.lolipop.jp/

2.左サイドバーのサーバーの管理・設定 - cron設定をクリック

3.ルート部分のwebディレクトリに、test_cronディレクトリを作成して、その中に、以下のコードをcron.phpで保存します。

<?php
  date_default_timezone_set('Asia/Tokyo');

  $handle = fopen("test.txt", "a+");
  fwrite($handle, date("Y-m-d H:i:s")."\r\n");
  fclose($handle);
?>

4.
cronの設定名はtest_cron
日付 ( 月 )は、毎月
日付 ( 日 )は毎日
曜日は毎日
時間 ( 時 )は毎時
時間 ( 分 )は1分毎
実行ファイルパスはtest_cron/cron.php
と記入し、設定ボタンをクリックすると作成する

5.これによって、1分ごとに現在時刻がtest.txtに追加されていきます。


※今回はサンプルプログラムなので、作成したcronを削除することを忘れないでください。

CakePHP3でPHPUnitを使ってテストを行う

開発環境は、Windows 10 Pro(64bit) + PHP 7.2.12 + CakePHP 3.6.14 + XAMPP Control Panel v3.2.2。

前提として、
CakePHPの組み込みサーバー
・XAMPPのApache
・XAMPPのMySQL
が起動しています。

今回は、初めてなので公式ドキュメントに基づいて書いておきます。



1.CakePHPの公式ドキュメントに基づき、コマンドを入力して、composerでphpunitをインストールする
テスト - 3.7

composer require --dev phpunit/phpunit:"^5.7|^6.0"
vendor\bin\phpunit --version

と入力して、バージョン情報が表示されたら、きちんとインストールされています。


2.次に、CakePHPの公式ドキュメントに基づき、ヘルパーとヘルパーのテストを作成します。

テスト - 3.7
最初のテストケースの欄の、ProgressHelperクラスについて書かれたコードをコピペし、<?php ~ ?>で囲って、src/View/Helperディレクトリに、ProgressHelper.phpという名前で保存します。
次に、ProgressHelperTestクラスについて書かれたコードをコピペし、<?php ~ ?>で囲って、setUp()関数とtestBar()関数の中身もコピペして入力し、tests/TestCase/View/HelperディレクトリにProgressHelperTest.phpという名前で保存します。


3.次に、テストを実行してみます。サーバーとデータベースが実行していることを確認し、以下のコマンドを入力して実行します。

vendor\bin\phpunit tests/TestCase/View/Helper/ProgressHelperTest.php

これできちんとテストが実行されたと思います。


4.次に下記のリンクのコードカバレッジの生成の欄に基づき、
テスト - 3.7
下記のコードを入力した時に、テスト結果が視覚的に見やすく表示されるようにしたいと思います。

vendor\bin\phpunit --coverage-html webroot/coverage tests/TestCase/View/Helper/ProgressHelperTest.php

そのためには、まず、現在の環境にXdebugをインストールする必要があります。
もし、インストールしていなければ、テスト結果に、

Error:         No code coverage driver is available

のメッセージが表示されることになります。
そこで、localhostでXAMPPのトップページにアクセスして、上部のPHPInfoの欄へアクセスします。
f:id:k01ken:20190115183535p:plain

下記のページへアクセスしておきます。
Xdebug: Support; Tailored Installation Instructions

PHPInfoのページにて、Ctrlを押しながらAを押して、ページ全体を反転させて、Ctrlを押しながらCを押して、コピーします。

上のページの四角い枠にCtrlを押しながらVを押して、ペーストし、Analyse my phpinfo() outputボタンをクリックします。

そうすると、最適なxdebugのdllファイルが選択されるので、
You're already running the latest Xdebug version
に書かれている手順通りに行うと、Xdebugが実行できます。
先ほどのPHPInfoのページにアクセスして、xdebugで検索して、以下のような欄があれば成功です。
f:id:k01ken:20190115184934p:plain


最後に、もう一度、上記のコードを入力した後に、

vendor\bin\phpunit --coverage-html webroot/coverage tests/TestCase/View/Helper/ProgressHelperTest.php

localhost:8765/coverage/index.htmlへアクセスすると、表示されていると思います。
f:id:k01ken:20190115185643p:plain

参考リンク
Cake PHP3のphpunitでコードカバレッジ見たいのに見られない - キーボードはパンタグラフが好き
【CakePHP3】PHPUnitでテストの自動化 | INSIGHT
xdebugをwindowsのphpに設定する方法で悩んだ件 - Qiita
CakePHP3でControllerのユニットテストを書く例 - Qiita

CakePHP3でプラグイン(FriendsOfCake/bootstrap-ui)を用いてBootstrapを使う

開発環境は、Windows 10 Pro(64bit) + PHP 7.2.12 + CakePHP 3.6.14。

1.composer.jsonを開いて、requireの中に以下を追加

"friendsofcake/bootstrap-ui": "^1.4",

2.コマンドプロンプトからcomposer updateでプラグインをインストール

3.config/bootstrap.php内に、

Plugin::load('BootstrapUI');

を追加する

4.src/View/AppView.phpを開いて、
上部に、

use BootstrapUI\View\UIView;

を追加し、

class AppView extends View

class AppView extends UIView

に変更する。

5.src/Application.php内のbootstrap()メソッド内に、

$this->addPlugin('BootstrapUI');

を追加する。


参考サイト

GitHub - FriendsOfCake/bootstrap-ui: CakePHP3: Transparently use Bootstrap
・公式ページ(英語)。使い方も書いている。

Windows10にてロリポップへGit BashのSSLでアクセスする

開発環境はWindows10 Pro(64bit)。

ローカル環境から本番環境へアップロードするだけじゃなくて、本番環境上にて、プログラムを直接インストールしてみたいと思いやってみました。

1.Git Bashを起動する

2.以下の形式通りにコマンドを入力する

ssh アカウント@サーバー -p 接続ポート

3.入力して、しばらくしてから、パスワードの入力を求められるので、パスワードをコピーして、Ctrl+Shiftキーを押しながら、insertキーを押してから、Enterキーを押す。ただ、ペーストしても、画面上には何も表示されないので注意。失敗して、Permission denied, please try again.と表示されても、何回か繰り返すと、成功する。

4.試しに、php -vruby -vと入力すると、バージョン情報が表示されると思います。

参考リンク
スタンダードプランのLolipopにパスワード認証でSSH接続(Git Bash/Windows) | 勉強とガジェット

Sass(SCSS)を使ってみる

開発環境は、Windows 10 Pro(64bit) + node v10.15.0。

Sass(SCSS)はCSSをより短い入力で書いて、そのままではきちんと動作しないので、変換して、CSSファイルを作成する仕組みです。

すでにnode.js(npm)をインストールしている前提で書いています。

以下の公式サイトの指示通りにやってみたいと思います。
Sass: Syntactically Awesome Style Sheets


1.npmにてsassをインストールする

npm install -g sass

2.テスト用にディレクトリを作成します

cd c:\
mkdir sass
cd sass

3.試しに何か書いてみます。下記のファイルをtest.scssとして保存します。

$color: #000000;

.test{
  color: $color;
}

4.次にカレントディレクトリを先ほど作成したsassディレクトリにして、以下のコマンドを入力して変換します。

sass test.scss test.css

そうすると、同じディレクトリ内に、test.cssとtest.css.mapが作成されていて、test.cssの中身を見ると、

.test {
  color: #000000;
}

/*# sourceMappingURL=test.css.map */

ときちんと変換されていることが分かります。
後は、このCSSファイルを使いたいところに用いるだけです。

PHPUnitを使う

開発環境はWindows 10 Pro(64bit) + PHP 7.2.12。

PHPでテストを行うパッケージであるPHPUnitを利用してみたいと思います。

1.カレントディレクトリをxampp内のhtdocsディレクトリへ移動し、そこで、phpunitというディレクトリを作成して、カレントディレクトリをphpunitへ移動

2.composerでphpunitをインストールするための以下のコマンドを入力

composer require phpunit/phpunit

もし、インストールに成功していたら、以下のコマンドでバージョンが表示されるはずです。

vendor\bin\phpunit --version

3.次に動作を確かめるプログラムを書きます。

<?php
function sum_function($value1, $value2, $value3){
  return $value1 + $value2 + $value3;
}
?>

上記のプログラムをsum-function.phpで保存します。

4.次に動作をチェックするプログラムを書きます

<?php
require 'vendor/autoload.php';
include './sum-function.php';
use PHPUnit\Framework\TestCase;

class SumFunctionTest extends TestCase{
	public function test_one(){
		$value1 = 100;
		$value2 = 200;
		$value3 = 300;
		$result = sum_function($value1,$value2,$value3);
		$this->assertEquals(600,$result);
	}
}
?>

5.以下のコマンドを入力してPHPUnitを実行して動作を確かめます

vendor\bin\phpunit SumFunctionTest.php