Skip to content

Instantly share code, notes, and snippets.

@geerpm
Created November 7, 2017 02:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save geerpm/b60eb36e745cba8f2d64a41072ee6627 to your computer and use it in GitHub Desktop.
Save geerpm/b60eb36e745cba8f2d64a41072ee6627 to your computer and use it in GitHub Desktop.
Auto generate Fixture *records* for cakephp3.x test (phpunit)
<?php
/**
* 現dbからfixture用のデータを出力する
* src/Shell/GenFixtureFromDbShell.php
*
* $ bin/cake gen_fixture_from_db [tablename] [idStr] [overwrite]
* @idStr
* - 1,2,3,4
* - 1..5
* - empty means All records
* @overwrite boolean
*
* e.g.
* $ bin/cake gen_fixture_from_db users
* $ bin/cake gen_fixture_from_db users 1,3,8
* $ bin/cake gen_fixture_from_db users 1..4
* $ bin/cake gen_fixture_from_db users 1..4,8,9..13 true
*/
namespace App\Shell;
use Cake\Console\Shell;
use Cake\Datasource\ConnectionManager;
use Cake\Utility\Inflector;
class GenFixtureFromDbShell extends Shell
{
/**
* cakephp db config
* @var string
*/
const DB_CONFIG_NAME = 'default';
/**
* filter
* @param array $row as a record at the table
* @return array
*/
protected function filter($row)
{
$row = (array)$row;
foreach ($row as $k => $v) {
if (is_numeric($v) && strpos($v, '.') === false) {
$row[$k] = (int)$v;
}
}
return $row;
}
/**
* main()
* @param string table name
* @param string $idStr
* @param bool $overwrite
* @return void
*/
public function main($table, $idStr = '', $overwrite = false)
{
$table = preg_replace('/\W/', '', $table);
list($idList, $idRange) = $this->parseIdStr($idStr);
$sql = $this->buildQuery($table, $idList, $idRange);
$conn = ConnectionManager::get(self::DB_CONFIG_NAME);
$dbResult = $conn->execute($sql)->fetchAll('assoc');
$result = [];
foreach ($dbResult as $row) {
$row = $this->filter($row);
$result[] = $row;
}
$className = Inflector::camelize($table) . 'Fixture';
$filepath = $this->safeSavingFilePath($className, $overwrite);
$date = date('Y-m-d H:i:s');
$var = var_export($result, true);
$file = <<<EOT
<?php
/**
* {$table} fixture
* auto generated by GenFixtureFromDbShell
* {$date}
*/
namespace App\Test\Fixture;
use Cake\TestSuite\Fixture\TestFixture;
class {$className} extends TestFixture
{
/**
* records set
* @var array
*/
public \$records = {$var};
}
EOT;
echo "$filepath" . PHP_EOL;
echo $file . PHP_EOL;
file_put_contents("$filepath", $file);
}
/**
* parse id param argument
* @param string $idStr
* @return array
*/
protected function parseIdStr($idStr)
{
$idList = [];
$idRange = [];
if (! empty($idStr)) {
$tmp = explode(',', trim($idStr . ','));
foreach ($tmp as $part) {
if (strpos($part, '..') !== false) {
$tmp2 = explode('..', $part);
$idRange[] = [
'min' => (int)$tmp[0] ?? null,
'max' => (int)$tmp[1] ?? null,
];
} else {
$idList[] = (int)$part;
}
}
}
return [$idList, $idRange];
}
/**
* build query by proccessed id params
* @param string $table
* @param array $idList
* @param array $idRange
* @return string as SQL
*/
protected function buildQuery($table, $idList, $idRange)
{
$sql = "SELECT * FROM {$table} ";
$sqlWhere = [];
if (count($idList) > 0) {
foreach ($idList as $k => $id) $idList[$k] = (int)$id;
$sqlWhere[] = '( `id` IN (' . join(',', $idList) . ') )';
}
foreach ($idRange as $set) {
$where = '';
if ($set['min']) {
$where = '`id` >= ' . (int)$set['min'];
}
if ($set['min'] && $set['max']) {
$where .= ' and ';
}
if ($set['max']) {
$where .= '`id` <= ' . (int)$set['max'];
}
if ($where) {
$sqlWhere[] = "( {$where} )";
}
}
if (count($sqlWhere)) {
$sql .= ' WHERE ' . join(' OR ', $sqlWhere);
}
return $sql;
}
/**
* get available save path
* @param string $className
* @param bool $overwrite
* @return string
*/
protected function safeSavingFilePath($className, $overwrite)
{
$dir = TESTS . '/Fixture';
if (! file_exists($dir) && ! mkdir($dir, 0755, true)) {
throw new \Exception("Fixture directory not exist (And failed make)");
}
$filename = $className . '.php';
if (file_exists("{$dir}/{$filename}") && ! $overwrite) {
throw new \Exception('Fixture already exist. you can overwrite with the option: set 3rd arg = true ' . "{$dir}/{$filename}");
}
return "{$dir}/{$filename}";
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment