src/commands/GenerateFixtureController.php
<?php
namespace luya\testsuite\commands;
use luya\console\Command;
use luya\helpers\FileHelper;
use luya\helpers\Inflector;
use Yii;
use yii\db\Connection;
use yii\db\TableSchema;
use yii\db\Query;
use yii\di\Instance;
/**
* Generate Fixtures.
*
* @property Connection $db The db component.
*
* @since 1.0.25
* @author Basil Suter <basil@nadar.io>
*/
class GenerateFixtureController extends Command
{
const MODE_MODEL = 'model';
const MODE_TABLE = 'table';
/**
* @var string The mode which will be taken to genrate the fixture either model or table.
*/
public $mode;
/**
* @var string If mode is table, the name of the table to generate the fixture.
*/
public $table;
/**
* @var string If mode is model, the full class name (path) to the model, like: `app/models/MyUserModel`.
*/
public $model;
/**
* @var boolean Whether the data of the current table should be added in getData() section or not.
*/
public $data;
private $_db = 'db';
/**
* DB Component Setter
*
* @param string $db
*/
public function setDb($db)
{
$this->_db = $db;
}
/**
* DB Component Getter
*
* @return Connection
*/
public function getDb()
{
return Instance::ensure($this->_db, Connection::class);
}
/**
* {@inheritDoc}
*/
public function options($actionID)
{
return array_merge(['db', 'model', 'table', 'model', 'data'], parent::options($actionID));
}
/**
* Generate the Fixture.
*
* @return void
*/
public function actionIndex()
{
if ($this->mode === null) {
$this->mode = $this->select('Table or Model (ActiveRecord) based Fixture', [
self::MODE_MODEL => 'Model (Active Record)',
self::MODE_TABLE => 'Table',
]);
}
if ($this->table === null && $this->mode == self::MODE_TABLE) {
$this->table = $this->prompt("Enter the database table name:");
}
if ($this->model === null && $this->mode == self::MODE_MODEL) {
$this->model = $this->prompt("Path to model class (\app\models\MyModel):");
}
if ($this->table === null && $this->mode == self::MODE_MODEL) {
$this->table = $this->model::tableName();
}
if ($this->data === null) {
$this->data = $this->confirm("Add current table data?", true);
}
$className = $this->mode == self::MODE_TABLE ? $this->table : $this->model;
$schema = $this->getSchema($this->table);
$className = $this->generateClassName($className);
$fixtureClassContent = $this->generateClassFile(
$schema,
$className,
$this->generateData($schema, $this->table),
$this->model,
$this->table,
$this->data
);
$folder = Yii::getAlias('@app/tests/fixtures');
$filePath = Yii::getAlias('@app/tests/fixtures/'.$className.'.php');
if (FileHelper::createDirectory($folder) && FileHelper::writeFile($filePath, $fixtureClassContent)) {
return $this->outputSuccess("fixture file {$filePath} has been created.");
}
return $this->outputError("Error while generting fixture.");
}
/**
* Get Schema
*
* @param string $table
* @return TableSchema
*/
public function getSchema($table)
{
return $this->db->getTableSchema($table);
}
/**
* Gnerate class name
*
* @param string $className
* @return string
*/
public function generateClassName($className)
{
return Inflector::classify($className.'Fixture');
}
/**
* Generate the view
*
* @param TableSchema $schema
* @param [type] $className
* @param array $data
* @param [type] $modelClass
* @param [type] $tableName
* @return string
*/
public function generateClassFile(TableSchema $schema, $className, array $data, $modelClass = null, $tableName = null, $addData = null)
{
return $this->view->renderFile(__DIR__ . '/views/generate-fixture.php', [
'schema' => $schema,
'data' => $data,
'className' => $className,
'modelClass' => $modelClass,
'tableName' => $tableName,
'addData' => $addData,
]);
}
/**
* Generate fixture data
*
* @param TableSchema $schema
* @param string $table
* @return array
*/
public function generateData(TableSchema $schema, $table)
{
$data = [];
foreach ((new Query)->from($table)->all($this->db) as $index => $items) {
$data[$this->primaryKeyValue($schema, $items, $index)] = $items;
}
return $data;
}
/**
* Get the primary key value for a given items row
*
* @param TableSchema $schema
* @param array $items
* @param string $defaultValue
* @return string
*/
protected function primaryKeyValue(TableSchema $schema, array $items, $defaultValue)
{
$values = [];
foreach ($schema->primaryKey as $keyName) {
if (array_key_exists($keyName, $items)) {
$values[] = $items[$keyName];
}
}
return empty($values) ? $defaultValue : implode("-", $values);
}
}