mirror of
https://gitee.com/ulthon/ulthon_admin.git
synced 2026-07-07 18:42:49 +08:00
修复seeder错误;删除第三方的think迁移工具,在extend中重新实现;
This commit is contained in:
97
extend/think/migration/Command.php
Normal file
97
extend/think/migration/Command.php
Normal file
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: yunwuxin <448901948@qq.com>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace think\migration;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Phinx\Config\Config;
|
||||
use Phinx\Db\Adapter\AdapterFactory;
|
||||
|
||||
abstract class Command extends \think\console\Command
|
||||
{
|
||||
protected $adapter;
|
||||
|
||||
public function getAdapter()
|
||||
{
|
||||
if (isset($this->adapter)) {
|
||||
return $this->adapter;
|
||||
}
|
||||
|
||||
$options = $this->getDbConfig();
|
||||
|
||||
$adapter = AdapterFactory::instance()->getAdapter($options['adapter'], $options);
|
||||
|
||||
if ($adapter->hasOption('table_prefix') || $adapter->hasOption('table_suffix')) {
|
||||
$adapter = AdapterFactory::instance()->getWrapper('prefix', $adapter);
|
||||
}
|
||||
|
||||
$adapter->setInput($this->input);
|
||||
$adapter->setOutput($this->output);
|
||||
|
||||
$this->adapter = $adapter;
|
||||
|
||||
return $adapter;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取数据库配置
|
||||
* @return array
|
||||
*/
|
||||
protected function getDbConfig(): array
|
||||
{
|
||||
$default = $this->app->config->get('database.default');
|
||||
|
||||
$config = $this->app->config->get("database.connections.{$default}");
|
||||
|
||||
if (0 == $config['deploy']) {
|
||||
$dbConfig = [
|
||||
'adapter' => $config['type'],
|
||||
'host' => $config['hostname'],
|
||||
'name' => $config['database'],
|
||||
'user' => $config['username'],
|
||||
'pass' => $config['password'],
|
||||
'port' => $config['hostport'],
|
||||
'charset' => $config['charset'],
|
||||
'suffix' => $config['suffix'] ?? '',
|
||||
'table_prefix' => $config['prefix'],
|
||||
];
|
||||
} else {
|
||||
$dbConfig = [
|
||||
'adapter' => explode(',', $config['type'])[0],
|
||||
'host' => explode(',', $config['hostname'])[0],
|
||||
'name' => explode(',', $config['database'])[0],
|
||||
'user' => explode(',', $config['username'])[0],
|
||||
'pass' => explode(',', $config['password'])[0],
|
||||
'port' => explode(',', $config['hostport'])[0],
|
||||
'charset' => explode(',', $config['charset'])[0],
|
||||
'suffix' => explode(',', $config['suffix'] ?? '')[0],
|
||||
'table_prefix' => explode(',', $config['prefix'])[0],
|
||||
];
|
||||
}
|
||||
|
||||
$table = $this->app->config->get('database.migration_table', 'migrations');
|
||||
|
||||
$dbConfig['migration_table'] = $dbConfig['table_prefix'] . $table;
|
||||
$dbConfig['version_order'] = Config::VERSION_ORDER_CREATION_TIME;
|
||||
|
||||
return $dbConfig;
|
||||
}
|
||||
|
||||
protected function verifyMigrationDirectory(string $path)
|
||||
{
|
||||
if (!is_dir($path)) {
|
||||
throw new InvalidArgumentException(sprintf('Migration directory "%s" does not exist', $path));
|
||||
}
|
||||
|
||||
if (!is_writable($path)) {
|
||||
throw new InvalidArgumentException(sprintf('Migration directory "%s" is not writable', $path));
|
||||
}
|
||||
}
|
||||
}
|
||||
77
extend/think/migration/Creator.php
Normal file
77
extend/think/migration/Creator.php
Normal file
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
namespace think\migration;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Phinx\Util\Util;
|
||||
use RuntimeException;
|
||||
use think\App;
|
||||
|
||||
class Creator
|
||||
{
|
||||
|
||||
protected $app;
|
||||
|
||||
public function __construct(App $app)
|
||||
{
|
||||
$this->app = $app;
|
||||
}
|
||||
|
||||
public function create(string $className)
|
||||
{
|
||||
$path = $this->ensureDirectory();
|
||||
|
||||
if (!Util::isValidPhinxClassName($className)) {
|
||||
throw new InvalidArgumentException(sprintf('The migration class name "%s" is invalid. Please use CamelCase format.', $className));
|
||||
}
|
||||
|
||||
if (!Util::isUniqueMigrationClassName($className, $path)) {
|
||||
throw new InvalidArgumentException(sprintf('The migration class name "%s" already exists', $className));
|
||||
}
|
||||
|
||||
// Compute the file path
|
||||
$fileName = Util::mapClassNameToFileName($className);
|
||||
$filePath = $path . DIRECTORY_SEPARATOR . $fileName;
|
||||
|
||||
if (is_file($filePath)) {
|
||||
throw new InvalidArgumentException(sprintf('The file "%s" already exists', $filePath));
|
||||
}
|
||||
|
||||
// Verify that the template creation class (or the aliased class) exists and that it implements the required interface.
|
||||
$aliasedClassName = null;
|
||||
|
||||
// Load the alternative template if it is defined.
|
||||
$contents = file_get_contents($this->getTemplate());
|
||||
|
||||
// inject the class names appropriate to this migration
|
||||
$contents = strtr($contents, [
|
||||
'MigratorClass' => $className,
|
||||
]);
|
||||
|
||||
if (false === file_put_contents($filePath, $contents)) {
|
||||
throw new RuntimeException(sprintf('The file "%s" could not be written to', $path));
|
||||
}
|
||||
|
||||
return $filePath;
|
||||
}
|
||||
|
||||
protected function ensureDirectory()
|
||||
{
|
||||
$path = $this->app->getRootPath() . 'database' . DIRECTORY_SEPARATOR . 'migrations';
|
||||
|
||||
if (!is_dir($path) && !mkdir($path, 0755, true)) {
|
||||
throw new InvalidArgumentException(sprintf('directory "%s" does not exist', $path));
|
||||
}
|
||||
|
||||
if (!is_writable($path)) {
|
||||
throw new InvalidArgumentException(sprintf('directory "%s" is not writable', $path));
|
||||
}
|
||||
|
||||
return $path;
|
||||
}
|
||||
|
||||
protected function getTemplate()
|
||||
{
|
||||
return __DIR__ . '/command/stubs/migrate.stub';
|
||||
}
|
||||
}
|
||||
313
extend/think/migration/Factory.php
Normal file
313
extend/think/migration/Factory.php
Normal file
@@ -0,0 +1,313 @@
|
||||
<?php
|
||||
|
||||
namespace think\migration;
|
||||
|
||||
use ArrayAccess;
|
||||
use Faker\Generator as Faker;
|
||||
|
||||
class Factory implements ArrayAccess
|
||||
{
|
||||
|
||||
/**
|
||||
* The model definitions in the container.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $definitions = [];
|
||||
|
||||
/**
|
||||
* The registered model states.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $states = [];
|
||||
|
||||
/**
|
||||
* The registered after making callbacks.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $afterMaking = [];
|
||||
|
||||
/**
|
||||
* The registered after creating callbacks.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $afterCreating = [];
|
||||
|
||||
/**
|
||||
* The Faker instance for the builder.
|
||||
*
|
||||
* @var Faker
|
||||
*/
|
||||
protected $faker;
|
||||
|
||||
/**
|
||||
* Create a new factory instance.
|
||||
*
|
||||
* @param Faker $faker
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Faker $faker)
|
||||
{
|
||||
$this->faker = $faker;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define a class with a given short-name.
|
||||
*
|
||||
* @param string $class
|
||||
* @param string $name
|
||||
* @param callable $attributes
|
||||
* @return $this
|
||||
*/
|
||||
public function defineAs(string $class, string $name, callable $attributes)
|
||||
{
|
||||
return $this->define($class, $attributes, $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Define a class with a given set of attributes.
|
||||
*
|
||||
* @param string $class
|
||||
* @param callable $attributes
|
||||
* @param string $name
|
||||
* @return $this
|
||||
*/
|
||||
public function define(string $class, callable $attributes, string $name = 'default')
|
||||
{
|
||||
$this->definitions[$class][$name] = $attributes;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define a state with a given set of attributes.
|
||||
*
|
||||
* @param string $class
|
||||
* @param string $state
|
||||
* @param callable|array $attributes
|
||||
* @return $this
|
||||
*/
|
||||
public function state(string $class, string $state, $attributes)
|
||||
{
|
||||
$this->states[$class][$state] = $attributes;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define a callback to run after making a model.
|
||||
*
|
||||
* @param string $class
|
||||
* @param callable $callback
|
||||
* @param string $name
|
||||
* @return $this
|
||||
*/
|
||||
public function afterMaking(string $class, callable $callback, string $name = 'default')
|
||||
{
|
||||
$this->afterMaking[$class][$name][] = $callback;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define a callback to run after making a model with given state.
|
||||
*
|
||||
* @param string $class
|
||||
* @param string $state
|
||||
* @param callable $callback
|
||||
* @return $this
|
||||
*/
|
||||
public function afterMakingState(string $class, string $state, callable $callback)
|
||||
{
|
||||
return $this->afterMaking($class, $callback, $state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Define a callback to run after creating a model.
|
||||
*
|
||||
* @param string $class
|
||||
* @param callable $callback
|
||||
* @param string $name
|
||||
* @return $this
|
||||
*/
|
||||
public function afterCreating(string $class, callable $callback, string $name = 'default')
|
||||
{
|
||||
$this->afterCreating[$class][$name][] = $callback;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define a callback to run after creating a model with given state.
|
||||
*
|
||||
* @param string $class
|
||||
* @param string $state
|
||||
* @param callable $callback
|
||||
* @return $this
|
||||
*/
|
||||
public function afterCreatingState(string $class, string $state, callable $callback)
|
||||
{
|
||||
return $this->afterCreating($class, $callback, $state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of the given model and persist it to the database.
|
||||
*
|
||||
* @param string $class
|
||||
* @param array $attributes
|
||||
* @return mixed
|
||||
*/
|
||||
public function create(string $class, array $attributes = [])
|
||||
{
|
||||
return $this->of($class)->create($attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of the given model and type and persist it to the database.
|
||||
*
|
||||
* @param string $class
|
||||
* @param string $name
|
||||
* @param array $attributes
|
||||
* @return mixed
|
||||
*/
|
||||
public function createAs(string $class, string $name, array $attributes = [])
|
||||
{
|
||||
return $this->of($class, $name)->create($attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of the given model.
|
||||
*
|
||||
* @param string $class
|
||||
* @param array $attributes
|
||||
* @return mixed
|
||||
*/
|
||||
public function make(string $class, array $attributes = [])
|
||||
{
|
||||
return $this->of($class)->make($attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of the given model and type.
|
||||
*
|
||||
* @param string $class
|
||||
* @param string $name
|
||||
* @param array $attributes
|
||||
* @return mixed
|
||||
*/
|
||||
public function makeAs(string $class, string $name, array $attributes = [])
|
||||
{
|
||||
return $this->of($class, $name)->make($attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the raw attribute array for a given named model.
|
||||
*
|
||||
* @param string $class
|
||||
* @param string $name
|
||||
* @param array $attributes
|
||||
* @return array
|
||||
*/
|
||||
public function rawOf(string $class, string $name, array $attributes = [])
|
||||
{
|
||||
return $this->raw($class, $attributes, $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the raw attribute array for a given model.
|
||||
*
|
||||
* @param string $class
|
||||
* @param array $attributes
|
||||
* @param string $name
|
||||
* @return array
|
||||
*/
|
||||
public function raw(string $class, array $attributes = [], string $name = 'default')
|
||||
{
|
||||
return array_merge(
|
||||
call_user_func($this->definitions[$class][$name], $this->faker), $attributes
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a builder for the given model.
|
||||
*
|
||||
* @param string $class
|
||||
* @param string $name
|
||||
* @return FactoryBuilder
|
||||
*/
|
||||
public function of(string $class, string $name = 'default')
|
||||
{
|
||||
return new FactoryBuilder(
|
||||
$class, $name, $this->definitions, $this->states,
|
||||
$this->afterMaking, $this->afterCreating, $this->faker
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load factories from path.
|
||||
*
|
||||
* @param string $path
|
||||
* @return $this
|
||||
*/
|
||||
public function load(string $path)
|
||||
{
|
||||
$factory = $this;
|
||||
|
||||
if (is_dir($path)) {
|
||||
foreach (glob($path . '*.php') as $file) {
|
||||
require $file;
|
||||
}
|
||||
}
|
||||
|
||||
return $factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given offset exists.
|
||||
*
|
||||
* @param string $offset
|
||||
* @return bool
|
||||
*/
|
||||
public function offsetExists($offset)
|
||||
{
|
||||
return isset($this->definitions[$offset]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of the given offset.
|
||||
*
|
||||
* @param string $offset
|
||||
* @return mixed
|
||||
*/
|
||||
public function offsetGet($offset)
|
||||
{
|
||||
return $this->make($offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the given offset to the given value.
|
||||
*
|
||||
* @param string $offset
|
||||
* @param callable $value
|
||||
* @return void
|
||||
*/
|
||||
public function offsetSet($offset, $value)
|
||||
{
|
||||
$this->define($offset, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unset the value at the given offset.
|
||||
*
|
||||
* @param string $offset
|
||||
* @return void
|
||||
*/
|
||||
public function offsetUnset($offset)
|
||||
{
|
||||
unset($this->definitions[$offset]);
|
||||
}
|
||||
|
||||
}
|
||||
437
extend/think/migration/FactoryBuilder.php
Normal file
437
extend/think/migration/FactoryBuilder.php
Normal file
@@ -0,0 +1,437 @@
|
||||
<?php
|
||||
|
||||
namespace think\migration;
|
||||
|
||||
use Faker\Generator as Faker;
|
||||
use InvalidArgumentException;
|
||||
use think\Collection;
|
||||
use think\Model;
|
||||
|
||||
class FactoryBuilder
|
||||
{
|
||||
|
||||
/**
|
||||
* The model definitions in the container.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $definitions;
|
||||
|
||||
/**
|
||||
* The model being built.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $class;
|
||||
|
||||
/**
|
||||
* The name of the model being built.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $name = 'default';
|
||||
|
||||
/**
|
||||
* The database connection on which the model instance should be persisted.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $connection;
|
||||
|
||||
/**
|
||||
* The model states.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $states;
|
||||
|
||||
/**
|
||||
* The model after making callbacks.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $afterMaking = [];
|
||||
|
||||
/**
|
||||
* The model after creating callbacks.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $afterCreating = [];
|
||||
|
||||
/**
|
||||
* The states to apply.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $activeStates = [];
|
||||
|
||||
/**
|
||||
* The Faker instance for the builder.
|
||||
*
|
||||
* @var Faker
|
||||
*/
|
||||
protected $faker;
|
||||
|
||||
/**
|
||||
* The number of models to build.
|
||||
*
|
||||
* @var int|null
|
||||
*/
|
||||
protected $amount = null;
|
||||
|
||||
/**
|
||||
* Create an new builder instance.
|
||||
*
|
||||
* @param string $class
|
||||
* @param string $name
|
||||
* @param array $definitions
|
||||
* @param array $states
|
||||
* @param array $afterMaking
|
||||
* @param array $afterCreating
|
||||
* @param Faker $faker
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($class, $name, array $definitions, array $states,
|
||||
array $afterMaking, array $afterCreating, Faker $faker)
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->class = $class;
|
||||
$this->faker = $faker;
|
||||
$this->states = $states;
|
||||
$this->definitions = $definitions;
|
||||
$this->afterMaking = $afterMaking;
|
||||
$this->afterCreating = $afterCreating;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the amount of models you wish to create / make.
|
||||
*
|
||||
* @param int $amount
|
||||
* @return $this
|
||||
*/
|
||||
public function times($amount)
|
||||
{
|
||||
$this->amount = $amount;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the state to be applied to the model.
|
||||
*
|
||||
* @param string $state
|
||||
* @return $this
|
||||
*/
|
||||
public function state($state)
|
||||
{
|
||||
return $this->states([$state]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the states to be applied to the model.
|
||||
*
|
||||
* @param array|mixed $states
|
||||
* @return $this
|
||||
*/
|
||||
public function states($states)
|
||||
{
|
||||
$this->activeStates = is_array($states) ? $states : func_get_args();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the database connection on which the model instance should be persisted.
|
||||
*
|
||||
* @param string $name
|
||||
* @return $this
|
||||
*/
|
||||
public function connection($name)
|
||||
{
|
||||
$this->connection = $name;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a model and persist it in the database if requested.
|
||||
*
|
||||
* @param array $attributes
|
||||
* @return \Closure
|
||||
*/
|
||||
public function lazy(array $attributes = [])
|
||||
{
|
||||
return function () use ($attributes) {
|
||||
return $this->create($attributes);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a collection of models and persist them to the database.
|
||||
*
|
||||
* @param array $attributes
|
||||
* @return mixed
|
||||
*/
|
||||
public function create(array $attributes = [])
|
||||
{
|
||||
$results = $this->make($attributes);
|
||||
|
||||
if ($results instanceof Model) {
|
||||
$this->store(new Collection([$results]));
|
||||
|
||||
$this->callAfterCreating(new Collection([$results]));
|
||||
} else {
|
||||
$this->store($results);
|
||||
|
||||
$this->callAfterCreating($results);
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the connection name on the results and store them.
|
||||
*
|
||||
* @param Collection $results
|
||||
* @return void
|
||||
*/
|
||||
protected function store($results)
|
||||
{
|
||||
$results->each(function (Model $model) {
|
||||
$model->save();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a collection of models.
|
||||
*
|
||||
* @param array $attributes
|
||||
* @return mixed
|
||||
*/
|
||||
public function make(array $attributes = [])
|
||||
{
|
||||
if ($this->amount === null) {
|
||||
return tap($this->makeInstance($attributes), function ($instance) {
|
||||
$this->callAfterMaking(new Collection([$instance]));
|
||||
});
|
||||
}
|
||||
|
||||
if ($this->amount < 1) {
|
||||
return (new $this->class)->toCollection();
|
||||
}
|
||||
|
||||
$instances = (new $this->class)->toCollection(array_map(function () use ($attributes) {
|
||||
return $this->makeInstance($attributes);
|
||||
}, range(1, $this->amount)));
|
||||
|
||||
$this->callAfterMaking($instances);
|
||||
|
||||
return $instances;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an array of raw attribute arrays.
|
||||
*
|
||||
* @param array $attributes
|
||||
* @return mixed
|
||||
*/
|
||||
public function raw(array $attributes = [])
|
||||
{
|
||||
if ($this->amount === null) {
|
||||
return $this->getRawAttributes($attributes);
|
||||
}
|
||||
|
||||
if ($this->amount < 1) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return array_map(function () use ($attributes) {
|
||||
return $this->getRawAttributes($attributes);
|
||||
}, range(1, $this->amount));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a raw attributes array for the model.
|
||||
*
|
||||
* @param array $attributes
|
||||
* @return mixed
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
protected function getRawAttributes(array $attributes = [])
|
||||
{
|
||||
if (!isset($this->definitions[$this->class][$this->name])) {
|
||||
throw new InvalidArgumentException("Unable to locate factory with name [{$this->name}] [{$this->class}].");
|
||||
}
|
||||
|
||||
$definition = call_user_func(
|
||||
$this->definitions[$this->class][$this->name],
|
||||
$this->faker, $attributes
|
||||
);
|
||||
|
||||
return $this->expandAttributes(
|
||||
array_merge($this->applyStates($definition, $attributes), $attributes)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make an instance of the model with the given attributes.
|
||||
*
|
||||
* @param array $attributes
|
||||
* @return Model
|
||||
*/
|
||||
protected function makeInstance(array $attributes = [])
|
||||
{
|
||||
/** @var Model $model */
|
||||
$model = new $this->class;
|
||||
|
||||
$model->setAttrs($this->getRawAttributes($attributes));
|
||||
|
||||
return $model;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the active states to the model definition array.
|
||||
*
|
||||
* @param array $definition
|
||||
* @param array $attributes
|
||||
* @return array
|
||||
*/
|
||||
protected function applyStates(array $definition, array $attributes = [])
|
||||
{
|
||||
foreach ($this->activeStates as $state) {
|
||||
if (!isset($this->states[$this->class][$state])) {
|
||||
if ($this->stateHasAfterCallback($state)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
throw new InvalidArgumentException("Unable to locate [{$state}] state for [{$this->class}].");
|
||||
}
|
||||
|
||||
$definition = array_merge(
|
||||
$definition,
|
||||
$this->stateAttributes($state, $attributes)
|
||||
);
|
||||
}
|
||||
|
||||
return $definition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the state attributes.
|
||||
*
|
||||
* @param string $state
|
||||
* @param array $attributes
|
||||
* @return array
|
||||
*/
|
||||
protected function stateAttributes($state, array $attributes)
|
||||
{
|
||||
$stateAttributes = $this->states[$this->class][$state];
|
||||
|
||||
if (!is_callable($stateAttributes)) {
|
||||
return $stateAttributes;
|
||||
}
|
||||
|
||||
return call_user_func(
|
||||
$stateAttributes,
|
||||
$this->faker, $attributes
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Expand all attributes to their underlying values.
|
||||
*
|
||||
* @param array $attributes
|
||||
* @return array
|
||||
*/
|
||||
protected function expandAttributes(array $attributes)
|
||||
{
|
||||
foreach ($attributes as &$attribute) {
|
||||
if (is_callable($attribute) && !is_string($attribute) && !is_array($attribute)) {
|
||||
$attribute = $attribute($attributes);
|
||||
}
|
||||
|
||||
if ($attribute instanceof static) {
|
||||
$attribute = $attribute->create()->getKey();
|
||||
}
|
||||
|
||||
if ($attribute instanceof Model) {
|
||||
$attribute = $attribute->getKey();
|
||||
}
|
||||
}
|
||||
|
||||
return $attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run after making callbacks on a collection of models.
|
||||
*
|
||||
* @param Collection $models
|
||||
* @return void
|
||||
*/
|
||||
public function callAfterMaking($models)
|
||||
{
|
||||
$this->callAfter($this->afterMaking, $models);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run after creating callbacks on a collection of models.
|
||||
*
|
||||
* @param Collection $models
|
||||
* @return void
|
||||
*/
|
||||
public function callAfterCreating($models)
|
||||
{
|
||||
$this->callAfter($this->afterCreating, $models);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call after callbacks for each model and state.
|
||||
*
|
||||
* @param array $afterCallbacks
|
||||
* @param Collection $models
|
||||
* @return void
|
||||
*/
|
||||
protected function callAfter(array $afterCallbacks, $models)
|
||||
{
|
||||
$states = array_merge([$this->name], $this->activeStates);
|
||||
|
||||
$models->each(function ($model) use ($states, $afterCallbacks) {
|
||||
foreach ($states as $state) {
|
||||
$this->callAfterCallbacks($afterCallbacks, $model, $state);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Call after callbacks for each model and state.
|
||||
*
|
||||
* @param array $afterCallbacks
|
||||
* @param Model $model
|
||||
* @param string $state
|
||||
* @return void
|
||||
*/
|
||||
protected function callAfterCallbacks(array $afterCallbacks, $model, $state)
|
||||
{
|
||||
if (!isset($afterCallbacks[$this->class][$state])) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($afterCallbacks[$this->class][$state] as $callback) {
|
||||
$callback($model, $this->faker);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given state has an "after" callback.
|
||||
*
|
||||
* @param string $state
|
||||
* @return bool
|
||||
*/
|
||||
protected function stateHasAfterCallback($state)
|
||||
{
|
||||
return isset($this->afterMaking[$this->class][$state]) ||
|
||||
isset($this->afterCreating[$this->class][$state]);
|
||||
}
|
||||
}
|
||||
27
extend/think/migration/Migrator.php
Normal file
27
extend/think/migration/Migrator.php
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: yunwuxin <448901948@qq.com>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace think\migration;
|
||||
|
||||
use Phinx\Migration\AbstractMigration;
|
||||
use think\migration\db\Table;
|
||||
|
||||
class Migrator extends AbstractMigration
|
||||
{
|
||||
/**
|
||||
* @param string $tableName
|
||||
* @param array $options
|
||||
* @return Table
|
||||
*/
|
||||
public function table($tableName, $options = []): \Phinx\Db\Table
|
||||
{
|
||||
return new Table($tableName, $options, $this->getAdapter());
|
||||
}
|
||||
}
|
||||
13
extend/think/migration/NullOutput.php
Normal file
13
extend/think/migration/NullOutput.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace think\migration;
|
||||
|
||||
use think\console\Output;
|
||||
|
||||
class NullOutput extends Output
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct('nothing');
|
||||
}
|
||||
}
|
||||
24
extend/think/migration/Seeder.php
Normal file
24
extend/think/migration/Seeder.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: yunwuxin <448901948@qq.com>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace think\migration;
|
||||
|
||||
use Phinx\Seed\AbstractSeed;
|
||||
|
||||
class Seeder extends AbstractSeed
|
||||
{
|
||||
/**
|
||||
* @return Factory
|
||||
*/
|
||||
public function factory()
|
||||
{
|
||||
return app(Factory::class);
|
||||
}
|
||||
}
|
||||
51
extend/think/migration/Service.php
Normal file
51
extend/think/migration/Service.php
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: yunwuxin <448901948@qq.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think\migration;
|
||||
|
||||
use Faker\Factory as FakerFactory;
|
||||
use Faker\Generator as FakerGenerator;
|
||||
use think\migration\command\factory\Create as FactoryCreate;
|
||||
use think\migration\command\migrate\Breakpoint as MigrateBreakpoint;
|
||||
use think\migration\command\migrate\Create as MigrateCreate;
|
||||
use think\migration\command\migrate\Rollback as MigrateRollback;
|
||||
use think\migration\command\migrate\Run as MigrateRun;
|
||||
use think\migration\command\migrate\Status as MigrateStatus;
|
||||
use think\migration\command\seed\Create as SeedCreate;
|
||||
use think\migration\command\seed\Run as SeedRun;
|
||||
|
||||
class Service extends \think\Service
|
||||
{
|
||||
|
||||
public function boot()
|
||||
{
|
||||
$this->app->bind(FakerGenerator::class, function () {
|
||||
return FakerFactory::create($this->app->config->get('app.faker_locale', 'zh_CN'));
|
||||
});
|
||||
|
||||
$this->app->bind(Factory::class, function () {
|
||||
return (new Factory($this->app->make(FakerGenerator::class)))->load($this->app->getRootPath() . 'database/factories/');
|
||||
});
|
||||
|
||||
$this->app->bind('migration.creator', Creator::class);
|
||||
|
||||
$this->commands([
|
||||
MigrateCreate::class,
|
||||
MigrateRun::class,
|
||||
MigrateRollback::class,
|
||||
MigrateBreakpoint::class,
|
||||
MigrateStatus::class,
|
||||
SeedCreate::class,
|
||||
SeedRun::class,
|
||||
FactoryCreate::class,
|
||||
]);
|
||||
}
|
||||
}
|
||||
116
extend/think/migration/UsePhinx.php
Normal file
116
extend/think/migration/UsePhinx.php
Normal file
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
|
||||
namespace think\migration;
|
||||
|
||||
use Symfony\Component\Finder\Finder;
|
||||
use Symfony\Component\Filesystem\Filesystem;
|
||||
use Symfony\Component\Filesystem\Exception\IOException;
|
||||
use Composer\Script\Event;
|
||||
|
||||
class UsePhinx
|
||||
{
|
||||
public static function run(Event $event)
|
||||
{
|
||||
if (!$event->isDevMode()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$files = [
|
||||
'vendor/robmorgan/phinx/LICENSE' => 'phinx/LICENSE',
|
||||
'vendor/robmorgan/phinx/README.md' => 'phinx/README.md',
|
||||
'vendor/robmorgan/phinx/src/Phinx/Config/' => 'phinx/Config/',
|
||||
'vendor/robmorgan/phinx/src/Phinx/Db/' => 'phinx/Db/',
|
||||
'vendor/robmorgan/phinx/src/Phinx/Migration/' => 'phinx/Migration/',
|
||||
'vendor/robmorgan/phinx/src/Phinx/Seed/' => 'phinx/Seed/',
|
||||
'vendor/robmorgan/phinx/src/Phinx/Util/' => 'phinx/Util/',
|
||||
];
|
||||
|
||||
$io = $event->getIO();
|
||||
|
||||
$fs = new Filesystem;
|
||||
|
||||
//clear
|
||||
$fs->remove('phinx');
|
||||
|
||||
foreach ($files as $from => $to) {
|
||||
// check pattern
|
||||
$pattern = null;
|
||||
if (strpos($from, '#') > 0) {
|
||||
[$from, $pattern] = explode('#', $from, 2);
|
||||
}
|
||||
|
||||
// check the overwrite newer files disable flag (? in end of path)
|
||||
$overwriteNewerFiles = substr($to, -1) != '?';
|
||||
if (!$overwriteNewerFiles) {
|
||||
$to = substr($to, 0, -1);
|
||||
}
|
||||
|
||||
// Check the renaming of file for direct moving (file-to-file)
|
||||
$isRenameFile = substr($to, -1) != '/' && !is_dir($from);
|
||||
|
||||
if (file_exists($to) && !is_dir($to) && !$isRenameFile) {
|
||||
throw new \InvalidArgumentException('Destination directory is not a directory.');
|
||||
}
|
||||
|
||||
try {
|
||||
if ($isRenameFile) {
|
||||
$fs->mkdir(dirname($to));
|
||||
} else {
|
||||
$fs->mkdir($to);
|
||||
}
|
||||
} catch (IOException $e) {
|
||||
throw new \InvalidArgumentException(sprintf('<error>Could not create directory %s.</error>', $to), $e->getCode(), $e);
|
||||
}
|
||||
|
||||
if (false === file_exists($from)) {
|
||||
throw new \InvalidArgumentException(sprintf('<error>Source directory or file "%s" does not exist.</error>', $from));
|
||||
}
|
||||
|
||||
if (is_dir($from)) {
|
||||
$finder = new Finder;
|
||||
$finder->files()->ignoreDotFiles(false)->in($from);
|
||||
|
||||
if ($pattern) {
|
||||
$finder->path("#{$pattern}#");
|
||||
}
|
||||
|
||||
foreach ($finder as $file) {
|
||||
$dest = sprintf('%s/%s', $to, $file->getRelativePathname());
|
||||
|
||||
try {
|
||||
$fs->copy($file, $dest, $overwriteNewerFiles);
|
||||
|
||||
// replace namespace
|
||||
$content = file_get_contents($dest);
|
||||
$replaces = [
|
||||
'use Symfony\Component\Console\Input\InputInterface;' => 'use think\console\Input as InputInterface;',
|
||||
'use Symfony\Component\Console\Output\OutputInterface;' => 'use think\console\Output as OutputInterface;',
|
||||
'\Symfony\Component\Console\Output\OutputInterface' => '\think\console\Output',
|
||||
'\Symfony\Component\Console\Input\InputInterface' => '\think\console\Input',
|
||||
'use Symfony\Component\Console\Output\NullOutput;' => 'use think\migration\NullOutput;',
|
||||
];
|
||||
$content = str_replace(array_keys($replaces), array_values($replaces), $content);
|
||||
file_put_contents($dest, $content);
|
||||
} catch (IOException $e) {
|
||||
throw new \InvalidArgumentException(sprintf('<error>Could not copy %s</error>', $file->getBaseName()), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
if ($isRenameFile) {
|
||||
$fs->copy($from, $to, $overwriteNewerFiles);
|
||||
} else {
|
||||
$fs->copy($from, $to . '/' . basename($from), $overwriteNewerFiles);
|
||||
}
|
||||
} catch (IOException $e) {
|
||||
throw new \InvalidArgumentException(sprintf('<error>Could not copy %s</error>', $from), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
$io->write(sprintf('Copied file(s) from <comment>%s</comment> to <comment>%s</comment>.', $from, $to));
|
||||
}
|
||||
|
||||
//clear
|
||||
$fs->remove('vendor/robmorgan/phinx');
|
||||
}
|
||||
}
|
||||
153
extend/think/migration/command/Migrate.php
Normal file
153
extend/think/migration/command/Migrate.php
Normal file
@@ -0,0 +1,153 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: yunwuxin <448901948@qq.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think\migration\command;
|
||||
|
||||
use Phinx\Db\Adapter\AdapterFactory;
|
||||
use Phinx\Migration\AbstractMigration;
|
||||
use Phinx\Migration\MigrationInterface;
|
||||
use Phinx\Util\Util;
|
||||
use think\migration\Command;
|
||||
use think\migration\Migrator;
|
||||
|
||||
abstract class Migrate extends Command
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $migrations;
|
||||
|
||||
protected function getPath()
|
||||
{
|
||||
return $this->app->getRootPath() . 'database' . DIRECTORY_SEPARATOR . 'migrations';
|
||||
}
|
||||
|
||||
protected function executeMigration(MigrationInterface $migration, $direction = MigrationInterface::UP)
|
||||
{
|
||||
$this->output->writeln('');
|
||||
$this->output->writeln(' ==' . ' <info>' . $migration->getVersion() . ' ' . $migration->getName() . ':</info>' . ' <comment>' . (MigrationInterface::UP === $direction ? 'migrating' : 'reverting') . '</comment>');
|
||||
|
||||
// Execute the migration and log the time elapsed.
|
||||
$start = microtime(true);
|
||||
|
||||
$startTime = time();
|
||||
$direction = (MigrationInterface::UP === $direction) ? MigrationInterface::UP : MigrationInterface::DOWN;
|
||||
$migration->setMigratingUp($direction === MigrationInterface::UP);
|
||||
$migration->setAdapter($this->getAdapter());
|
||||
|
||||
$migration->preFlightCheck();
|
||||
|
||||
if (method_exists($migration, MigrationInterface::INIT)) {
|
||||
$migration->{MigrationInterface::INIT}();
|
||||
}
|
||||
|
||||
// begin the transaction if the adapter supports it
|
||||
if ($this->getAdapter()->hasTransactions()) {
|
||||
$this->getAdapter()->beginTransaction();
|
||||
}
|
||||
|
||||
// Run the migration
|
||||
if (method_exists($migration, MigrationInterface::CHANGE)) {
|
||||
if (MigrationInterface::DOWN === $direction) {
|
||||
// Create an instance of the ProxyAdapter so we can record all
|
||||
// of the migration commands for reverse playback
|
||||
/** @var \Phinx\Db\Adapter\ProxyAdapter $proxyAdapter */
|
||||
$proxyAdapter = AdapterFactory::instance()->getWrapper('proxy', $this->getAdapter());
|
||||
$migration->setAdapter($proxyAdapter);
|
||||
$migration->{MigrationInterface::CHANGE}();
|
||||
$proxyAdapter->executeInvertedCommands();
|
||||
$migration->setAdapter($this->getAdapter());
|
||||
} else {
|
||||
/** @noinspection PhpUndefinedMethodInspection */
|
||||
$migration->change();
|
||||
}
|
||||
} else {
|
||||
$migration->{$direction}();
|
||||
}
|
||||
|
||||
// commit the transaction if the adapter supports it
|
||||
if ($this->getAdapter()->hasTransactions()) {
|
||||
$this->getAdapter()->commitTransaction();
|
||||
}
|
||||
|
||||
$migration->postFlightCheck();
|
||||
|
||||
// Record it in the database
|
||||
$this->getAdapter()
|
||||
->migrated($migration, $direction, date('Y-m-d H:i:s', $startTime), date('Y-m-d H:i:s', time()));
|
||||
|
||||
$end = microtime(true);
|
||||
|
||||
$this->output->writeln(' ==' . ' <info>' . $migration->getVersion() . ' ' . $migration->getName() . ':</info>' . ' <comment>' . (MigrationInterface::UP === $direction ? 'migrated' : 'reverted') . ' ' . sprintf('%.4fs', $end - $start) . '</comment>');
|
||||
}
|
||||
|
||||
protected function getVersionLog()
|
||||
{
|
||||
return $this->getAdapter()->getVersionLog();
|
||||
}
|
||||
|
||||
protected function getVersions()
|
||||
{
|
||||
return $this->getAdapter()->getVersions();
|
||||
}
|
||||
|
||||
protected function getMigrations()
|
||||
{
|
||||
if (null === $this->migrations) {
|
||||
$phpFiles = glob($this->getPath() . DIRECTORY_SEPARATOR . '*.php', defined('GLOB_BRACE') ? GLOB_BRACE : 0);
|
||||
|
||||
// filter the files to only get the ones that match our naming scheme
|
||||
$fileNames = [];
|
||||
/** @var Migrator[] $versions */
|
||||
$versions = [];
|
||||
|
||||
foreach ($phpFiles as $filePath) {
|
||||
if (Util::isValidMigrationFileName(basename($filePath))) {
|
||||
$version = Util::getVersionFromFileName(basename($filePath));
|
||||
|
||||
if (isset($versions[$version])) {
|
||||
throw new \InvalidArgumentException(sprintf('Duplicate migration - "%s" has the same version as "%s"', $filePath, $versions[$version]->getVersion()));
|
||||
}
|
||||
|
||||
// convert the filename to a class name
|
||||
$class = Util::mapFileNameToClassName(basename($filePath));
|
||||
|
||||
if (isset($fileNames[$class])) {
|
||||
throw new \InvalidArgumentException(sprintf('Migration "%s" has the same name as "%s"', basename($filePath), $fileNames[$class]));
|
||||
}
|
||||
|
||||
$fileNames[$class] = basename($filePath);
|
||||
|
||||
// load the migration file
|
||||
/** @noinspection PhpIncludeInspection */
|
||||
require_once $filePath;
|
||||
if (!class_exists($class)) {
|
||||
throw new \InvalidArgumentException(sprintf('Could not find class "%s" in file "%s"', $class, $filePath));
|
||||
}
|
||||
|
||||
// instantiate it
|
||||
$migration = new $class('default', $version, $this->input, $this->output);
|
||||
|
||||
if (!($migration instanceof AbstractMigration)) {
|
||||
throw new \InvalidArgumentException(sprintf('The class "%s" in file "%s" must extend \Phinx\Migration\AbstractMigration', $class, $filePath));
|
||||
}
|
||||
|
||||
$versions[$version] = $migration;
|
||||
}
|
||||
}
|
||||
|
||||
ksort($versions);
|
||||
$this->migrations = $versions;
|
||||
}
|
||||
|
||||
return $this->migrations;
|
||||
}
|
||||
}
|
||||
78
extend/think/migration/command/Seed.php
Normal file
78
extend/think/migration/command/Seed.php
Normal file
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: yunwuxin <448901948@qq.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think\migration\command;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Phinx\Seed\AbstractSeed;
|
||||
use Phinx\Util\Util;
|
||||
use think\migration\Command;
|
||||
use think\migration\Seeder;
|
||||
|
||||
abstract class Seed extends Command
|
||||
{
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $seeds;
|
||||
|
||||
protected function getPath()
|
||||
{
|
||||
return $this->app->getRootPath() . 'database' . DIRECTORY_SEPARATOR . 'seeds';
|
||||
}
|
||||
|
||||
public function getSeeds()
|
||||
{
|
||||
if (null === $this->seeds) {
|
||||
$phpFiles = glob($this->getPath() . DIRECTORY_SEPARATOR . '*.php', defined('GLOB_BRACE') ? GLOB_BRACE : 0);
|
||||
|
||||
// filter the files to only get the ones that match our naming scheme
|
||||
$fileNames = [];
|
||||
/** @var Seeder[] $seeds */
|
||||
$seeds = [];
|
||||
|
||||
foreach ($phpFiles as $filePath) {
|
||||
if (Util::isValidSeedFileName(basename($filePath))) {
|
||||
// convert the filename to a class name
|
||||
$class = pathinfo($filePath, PATHINFO_FILENAME);
|
||||
$fileNames[$class] = basename($filePath);
|
||||
|
||||
// load the seed file
|
||||
/** @noinspection PhpIncludeInspection */
|
||||
require_once $filePath;
|
||||
if (!class_exists($class)) {
|
||||
throw new InvalidArgumentException(sprintf('Could not find class "%s" in file "%s"', $class, $filePath));
|
||||
}
|
||||
|
||||
// instantiate it
|
||||
$seed = new $class($this->input, $this->output);
|
||||
|
||||
if (!($seed instanceof AbstractSeed)) {
|
||||
throw new InvalidArgumentException(sprintf('The class "%s" in file "%s" must extend \Phinx\Seed\AbstractSeed', $class, $filePath));
|
||||
}
|
||||
|
||||
if($seed instanceof Seeder){
|
||||
$seed->setInput($this->input);
|
||||
$seed->setOutput($this->output);
|
||||
}
|
||||
|
||||
$seeds[$class] = $seed;
|
||||
}
|
||||
}
|
||||
|
||||
ksort($seeds);
|
||||
$this->seeds = $seeds;
|
||||
}
|
||||
|
||||
return $this->seeds;
|
||||
}
|
||||
}
|
||||
82
extend/think/migration/command/factory/Create.php
Normal file
82
extend/think/migration/command/factory/Create.php
Normal file
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: yunwuxin <448901948@qq.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think\migration\command\factory;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Phinx\Util\Util;
|
||||
use RuntimeException;
|
||||
use think\console\Command;
|
||||
use think\console\input\Argument as InputArgument;
|
||||
|
||||
class Create extends Command
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('factory:create')
|
||||
->setDescription('Create a new model factory')
|
||||
->addArgument('name', InputArgument::REQUIRED, 'What is the name of the model?');
|
||||
}
|
||||
|
||||
public function handle()
|
||||
{
|
||||
$path = $this->getPath();
|
||||
|
||||
if (!file_exists($path)) {
|
||||
mkdir($path, 0755, true);
|
||||
}
|
||||
|
||||
if (!is_dir($path)) {
|
||||
throw new InvalidArgumentException(sprintf('Factory directory "%s" does not exist', $path));
|
||||
}
|
||||
|
||||
if (!is_writable($path)) {
|
||||
throw new InvalidArgumentException(sprintf('Factory directory "%s" is not writable', $path));
|
||||
}
|
||||
|
||||
$path = realpath($path);
|
||||
$className = $this->input->getArgument('name');
|
||||
|
||||
if (!Util::isValidPhinxClassName($className)) {
|
||||
throw new InvalidArgumentException(sprintf('The migration class name "%s" is invalid. Please use CamelCase format.', $className));
|
||||
}
|
||||
|
||||
$filePath = $path . DIRECTORY_SEPARATOR . $className . '.php';
|
||||
|
||||
if (is_file($filePath)) {
|
||||
throw new InvalidArgumentException(sprintf('The file "%s" already exists', $filePath));
|
||||
}
|
||||
|
||||
// Load the alternative template if it is defined.
|
||||
$contents = file_get_contents($this->getTemplate());
|
||||
|
||||
// inject the class names appropriate to this migration
|
||||
$contents = strtr($contents, [
|
||||
'"ModelClass"' => "\\app\\model\\" . $className . '::class',
|
||||
]);
|
||||
|
||||
if (false === file_put_contents($filePath, $contents)) {
|
||||
throw new RuntimeException(sprintf('The file "%s" could not be written to', $path));
|
||||
}
|
||||
|
||||
$this->output->writeln('<info>created</info> .' . str_replace(getcwd(), '', $filePath));
|
||||
}
|
||||
|
||||
protected function getTemplate()
|
||||
{
|
||||
return __DIR__ . '/../stubs/factory.stub';
|
||||
}
|
||||
|
||||
protected function getPath()
|
||||
{
|
||||
return $this->app->getRootPath() . 'database' . DIRECTORY_SEPARATOR . 'factories';
|
||||
}
|
||||
}
|
||||
92
extend/think/migration/command/migrate/Breakpoint.php
Normal file
92
extend/think/migration/command/migrate/Breakpoint.php
Normal file
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: yunwuxin <448901948@qq.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think\migration\command\migrate;
|
||||
|
||||
use think\console\Input;
|
||||
use think\console\input\Option as InputOption;
|
||||
use think\console\Output;
|
||||
use think\migration\command\Migrate;
|
||||
|
||||
class Breakpoint extends Migrate
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('migrate:breakpoint')
|
||||
->setDescription('Manage breakpoints')
|
||||
->addOption('--target', '-t', InputOption::VALUE_REQUIRED, 'The version number to set or clear a breakpoint against')
|
||||
->addOption('--remove-all', '-r', InputOption::VALUE_NONE, 'Remove all breakpoints')
|
||||
->setHelp(<<<EOT
|
||||
The <info>breakpoint</info> command allows you to set or clear a breakpoint against a specific target to inhibit rollbacks beyond a certain target.
|
||||
If no target is supplied then the most recent migration will be used.
|
||||
You cannot specify un-migrated targets
|
||||
|
||||
<info>php think migrate:breakpoint</info>
|
||||
<info>php think migrate:breakpoint -t 20110103081132</info>
|
||||
<info>php think migrate:breakpoint -r</info>
|
||||
EOT
|
||||
);
|
||||
}
|
||||
|
||||
protected function execute(Input $input, Output $output)
|
||||
{
|
||||
$version = $input->getOption('target');
|
||||
$removeAll = $input->getOption('remove-all');
|
||||
|
||||
if ($version && $removeAll) {
|
||||
throw new \InvalidArgumentException('Cannot toggle a breakpoint and remove all breakpoints at the same time.');
|
||||
}
|
||||
|
||||
// Remove all breakpoints
|
||||
if ($removeAll) {
|
||||
$this->removeBreakpoints();
|
||||
} else {
|
||||
// Toggle the breakpoint.
|
||||
$this->toggleBreakpoint($version);
|
||||
}
|
||||
}
|
||||
|
||||
protected function toggleBreakpoint($version)
|
||||
{
|
||||
$migrations = $this->getMigrations();
|
||||
$versions = $this->getVersionLog();
|
||||
|
||||
if (empty($versions) || empty($migrations)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (null === $version) {
|
||||
$lastVersion = end($versions);
|
||||
$version = $lastVersion['version'];
|
||||
}
|
||||
|
||||
if (0 != $version && !isset($migrations[$version])) {
|
||||
$this->output->writeln(sprintf('<comment>warning</comment> %s is not a valid version', $version));
|
||||
return;
|
||||
}
|
||||
|
||||
$this->getAdapter()->toggleBreakpoint($migrations[$version]);
|
||||
|
||||
$versions = $this->getVersionLog();
|
||||
|
||||
$this->output->writeln(' Breakpoint ' . ($versions[$version]['breakpoint'] ? 'set' : 'cleared') . ' for <info>' . $version . '</info>' . ' <comment>' . $migrations[$version]->getName() . '</comment>');
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all breakpoints
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function removeBreakpoints()
|
||||
{
|
||||
$this->output->writeln(sprintf(' %d breakpoints cleared.', $this->getAdapter()->resetAllBreakpoints()));
|
||||
}
|
||||
}
|
||||
55
extend/think/migration/command/migrate/Create.php
Normal file
55
extend/think/migration/command/migrate/Create.php
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | TopThink [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016 http://www.topthink.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: zhangyajun <448901948@qq.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think\migration\command\migrate;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use RuntimeException;
|
||||
use think\console\Command;
|
||||
use think\console\Input;
|
||||
use think\console\input\Argument as InputArgument;
|
||||
use think\console\Output;
|
||||
use think\migration\Creator;
|
||||
|
||||
class Create extends Command
|
||||
{
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('migrate:create')
|
||||
->setDescription('Create a new migration')
|
||||
->addArgument('name', InputArgument::REQUIRED, 'What is the name of the migration?')
|
||||
->setHelp(sprintf('%sCreates a new database migration%s', PHP_EOL, PHP_EOL));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the new migration.
|
||||
*
|
||||
* @param Input $input
|
||||
* @param Output $output
|
||||
* @return void
|
||||
* @throws InvalidArgumentException
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
protected function execute(Input $input, Output $output)
|
||||
{
|
||||
/** @var Creator $creator */
|
||||
$creator = $this->app->get('migration.creator');
|
||||
|
||||
$className = $input->getArgument('name');
|
||||
|
||||
$path = $creator->create($className);
|
||||
|
||||
$output->writeln('<info>created</info> .' . str_replace(getcwd(), '', realpath($path)));
|
||||
}
|
||||
|
||||
}
|
||||
146
extend/think/migration/command/migrate/Rollback.php
Normal file
146
extend/think/migration/command/migrate/Rollback.php
Normal file
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | TopThink [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016 http://www.topthink.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: zhangyajun <448901948@qq.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think\migration\command\migrate;
|
||||
|
||||
use Phinx\Migration\MigrationInterface;
|
||||
use think\console\input\Option as InputOption;
|
||||
use think\console\Input;
|
||||
use think\console\Output;
|
||||
use think\migration\command\Migrate;
|
||||
|
||||
class Rollback extends Migrate
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('migrate:rollback')
|
||||
->setDescription('Rollback the last or to a specific migration')
|
||||
->addOption('--target', '-t', InputOption::VALUE_REQUIRED, 'The version number to rollback to')
|
||||
->addOption('--date', '-d', InputOption::VALUE_REQUIRED, 'The date to rollback to')
|
||||
->addOption('--force', '-f', InputOption::VALUE_NONE, 'Force rollback to ignore breakpoints')
|
||||
->setHelp(<<<EOT
|
||||
The <info>migrate:rollback</info> command reverts the last migration, or optionally up to a specific version
|
||||
|
||||
<info>php think migrate:rollback</info>
|
||||
<info>php think migrate:rollback -t 20111018185412</info>
|
||||
<info>php think migrate:rollback -d 20111018</info>
|
||||
<info>php think migrate:rollback -v</info>
|
||||
|
||||
EOT
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rollback the migration.
|
||||
*
|
||||
* @param Input $input
|
||||
* @param Output $output
|
||||
* @return void
|
||||
*/
|
||||
protected function execute(Input $input, Output $output)
|
||||
{
|
||||
$version = $input->getOption('target');
|
||||
$date = $input->getOption('date');
|
||||
$force = !!$input->getOption('force');
|
||||
|
||||
// rollback the specified environment
|
||||
$start = microtime(true);
|
||||
if (null !== $date) {
|
||||
$this->rollbackToDateTime(new \DateTime($date), $force);
|
||||
} else {
|
||||
$this->rollback($version, $force);
|
||||
}
|
||||
$end = microtime(true);
|
||||
|
||||
$output->writeln('');
|
||||
$output->writeln('<comment>All Done. Took ' . sprintf('%.4fs', $end - $start) . '</comment>');
|
||||
}
|
||||
|
||||
protected function rollback($version = null, $force = false)
|
||||
{
|
||||
$migrations = $this->getMigrations();
|
||||
$versionLog = $this->getVersionLog();
|
||||
$versions = array_keys($versionLog);
|
||||
|
||||
ksort($migrations);
|
||||
sort($versions);
|
||||
|
||||
// Check we have at least 1 migration to revert
|
||||
if (empty($versions) || $version == end($versions)) {
|
||||
$this->output->writeln('<error>No migrations to rollback</error>');
|
||||
return;
|
||||
}
|
||||
|
||||
// If no target version was supplied, revert the last migration
|
||||
if (null === $version) {
|
||||
// Get the migration before the last run migration
|
||||
$prev = count($versions) - 2;
|
||||
$version = $prev < 0 ? 0 : $versions[$prev];
|
||||
} else {
|
||||
// Get the first migration number
|
||||
$first = $versions[0];
|
||||
|
||||
// If the target version is before the first migration, revert all migrations
|
||||
if ($version < $first) {
|
||||
$version = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Check the target version exists
|
||||
if (0 !== $version && !isset($migrations[$version])) {
|
||||
$this->output->writeln("<error>Target version ($version) not found</error>");
|
||||
return;
|
||||
}
|
||||
|
||||
// Revert the migration(s)
|
||||
krsort($migrations);
|
||||
foreach ($migrations as $migration) {
|
||||
if ($migration->getVersion() <= $version) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (in_array($migration->getVersion(), $versions)) {
|
||||
if (isset($versionLog[$migration->getVersion()]) && 0 != $versionLog[$migration->getVersion()]['breakpoint'] && !$force) {
|
||||
$this->output->writeln('<error>Breakpoint reached. Further rollbacks inhibited.</error>');
|
||||
break;
|
||||
}
|
||||
$this->executeMigration($migration, MigrationInterface::DOWN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function rollbackToDateTime(\DateTime $dateTime, $force = false)
|
||||
{
|
||||
$versions = $this->getVersions();
|
||||
$dateString = $dateTime->format('YmdHis');
|
||||
sort($versions);
|
||||
|
||||
$earlierVersion = null;
|
||||
$availableMigrations = array_filter($versions, function ($version) use ($dateString, &$earlierVersion) {
|
||||
if ($version <= $dateString) {
|
||||
$earlierVersion = $version;
|
||||
}
|
||||
return $version >= $dateString;
|
||||
});
|
||||
|
||||
if (count($availableMigrations) > 0) {
|
||||
if (is_null($earlierVersion)) {
|
||||
$this->output->writeln('Rolling back all migrations');
|
||||
$migration = 0;
|
||||
} else {
|
||||
$this->output->writeln('Rolling back to version ' . $earlierVersion);
|
||||
$migration = $earlierVersion;
|
||||
}
|
||||
$this->rollback($migration, $force);
|
||||
}
|
||||
}
|
||||
}
|
||||
140
extend/think/migration/command/migrate/Run.php
Normal file
140
extend/think/migration/command/migrate/Run.php
Normal file
@@ -0,0 +1,140 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | TopThink [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016 http://www.topthink.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: zhangyajun <448901948@qq.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think\migration\command\migrate;
|
||||
|
||||
use Phinx\Migration\MigrationInterface;
|
||||
use think\console\Input;
|
||||
use think\console\input\Option as InputOption;
|
||||
use think\console\Output;
|
||||
use think\migration\command\Migrate;
|
||||
|
||||
class Run extends Migrate
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('migrate:run')
|
||||
->setDescription('Migrate the database')
|
||||
->addOption('--target', '-t', InputOption::VALUE_REQUIRED, 'The version number to migrate to')
|
||||
->addOption('--date', '-d', InputOption::VALUE_REQUIRED, 'The date to migrate to')
|
||||
->setHelp(<<<EOT
|
||||
The <info>migrate:run</info> command runs all available migrations, optionally up to a specific version
|
||||
|
||||
<info>php think migrate:run</info>
|
||||
<info>php think migrate:run -t 20110103081132</info>
|
||||
<info>php think migrate:run -d 20110103</info>
|
||||
<info>php think migrate:run -v</info>
|
||||
|
||||
EOT
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Migrate the database.
|
||||
*
|
||||
* @param Input $input
|
||||
* @param Output $output
|
||||
*/
|
||||
protected function execute(Input $input, Output $output)
|
||||
{
|
||||
$version = $input->getOption('target');
|
||||
$date = $input->getOption('date');
|
||||
|
||||
// run the migrations
|
||||
$start = microtime(true);
|
||||
if (null !== $date) {
|
||||
$this->migrateToDateTime(new \DateTime($date));
|
||||
} else {
|
||||
$this->migrate($version);
|
||||
}
|
||||
$end = microtime(true);
|
||||
|
||||
$output->writeln('');
|
||||
$output->writeln('<comment>All Done. Took ' . sprintf('%.4fs', $end - $start) . '</comment>');
|
||||
}
|
||||
|
||||
public function migrateToDateTime(\DateTime $dateTime)
|
||||
{
|
||||
$versions = array_keys($this->getMigrations());
|
||||
$dateString = $dateTime->format('YmdHis');
|
||||
|
||||
$outstandingMigrations = array_filter($versions, function ($version) use ($dateString) {
|
||||
return $version <= $dateString;
|
||||
});
|
||||
|
||||
if (count($outstandingMigrations) > 0) {
|
||||
$migration = max($outstandingMigrations);
|
||||
$this->output->writeln('Migrating to version ' . $migration);
|
||||
$this->migrate($migration);
|
||||
}
|
||||
}
|
||||
|
||||
protected function migrate($version = null)
|
||||
{
|
||||
$migrations = $this->getMigrations();
|
||||
$versions = $this->getVersions();
|
||||
$current = $this->getCurrentVersion();
|
||||
|
||||
if (empty($versions) && empty($migrations)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (null === $version) {
|
||||
$version = max(array_merge($versions, array_keys($migrations)));
|
||||
} else {
|
||||
if (0 != $version && !isset($migrations[$version])) {
|
||||
$this->output->writeln(sprintf('<comment>warning</comment> %s is not a valid version', $version));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// are we migrating up or down?
|
||||
$direction = $version > $current ? MigrationInterface::UP : MigrationInterface::DOWN;
|
||||
|
||||
if ($direction === MigrationInterface::DOWN) {
|
||||
// run downs first
|
||||
krsort($migrations);
|
||||
foreach ($migrations as $migration) {
|
||||
if ($migration->getVersion() <= $version) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (in_array($migration->getVersion(), $versions)) {
|
||||
$this->executeMigration($migration, MigrationInterface::DOWN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ksort($migrations);
|
||||
foreach ($migrations as $migration) {
|
||||
if ($migration->getVersion() > $version) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!in_array($migration->getVersion(), $versions)) {
|
||||
$this->executeMigration($migration, MigrationInterface::UP);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function getCurrentVersion()
|
||||
{
|
||||
$versions = $this->getVersions();
|
||||
$version = 0;
|
||||
|
||||
if (!empty($versions)) {
|
||||
$version = end($versions);
|
||||
}
|
||||
|
||||
return $version;
|
||||
}
|
||||
}
|
||||
126
extend/think/migration/command/migrate/Status.php
Normal file
126
extend/think/migration/command/migrate/Status.php
Normal file
@@ -0,0 +1,126 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | TopThink [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016 http://www.topthink.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: zhangyajun <448901948@qq.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think\migration\command\migrate;
|
||||
|
||||
use think\console\input\Option as InputOption;
|
||||
use think\console\Input;
|
||||
use think\console\Output;
|
||||
use think\migration\command\Migrate;
|
||||
|
||||
class Status extends Migrate
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('migrate:status')
|
||||
->setDescription('Show migration status')
|
||||
->addOption('--format', '-f', InputOption::VALUE_REQUIRED, 'The output format: text or json. Defaults to text.')
|
||||
->setHelp(<<<EOT
|
||||
The <info>migrate:status</info> command prints a list of all migrations, along with their current status
|
||||
|
||||
<info>php think migrate:status</info>
|
||||
<info>php think migrate:status -f json</info>
|
||||
EOT
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the migration status.
|
||||
*
|
||||
* @param Input $input
|
||||
* @param Output $output
|
||||
* @return integer 0 if all migrations are up, or an error code
|
||||
*/
|
||||
protected function execute(Input $input, Output $output)
|
||||
{
|
||||
$format = $input->getOption('format');
|
||||
|
||||
if (null !== $format) {
|
||||
$output->writeln('<info>using format</info> ' . $format);
|
||||
}
|
||||
|
||||
// print the status
|
||||
return $this->printStatus($format);
|
||||
}
|
||||
|
||||
protected function printStatus($format = null)
|
||||
{
|
||||
$output = $this->output;
|
||||
$migrations = [];
|
||||
if (count($this->getMigrations())) {
|
||||
// TODO - rewrite using Symfony Table Helper as we already have this library
|
||||
// included and it will fix formatting issues (e.g drawing the lines)
|
||||
$output->writeln('');
|
||||
$output->writeln(' Status Migration ID Started Finished Migration Name ');
|
||||
$output->writeln('----------------------------------------------------------------------------------');
|
||||
|
||||
$versions = $this->getVersionLog();
|
||||
$maxNameLength = $versions ? max(array_map(function ($version) {
|
||||
return strlen($version['migration_name']);
|
||||
}, $versions)) : 0;
|
||||
|
||||
foreach ($this->getMigrations() as $migration) {
|
||||
$version = array_key_exists($migration->getVersion(), $versions) ? $versions[$migration->getVersion()] : false;
|
||||
if ($version) {
|
||||
$status = ' <info>up</info> ';
|
||||
} else {
|
||||
$status = ' <error>down</error> ';
|
||||
$version = [];
|
||||
$version['start_time'] = $version['end_time'] = $version['breakpoint'] = '';
|
||||
}
|
||||
$maxNameLength = max($maxNameLength, strlen($migration->getName()));
|
||||
|
||||
$output->writeln(sprintf('%s %14.0f %19s %19s <comment>%s</comment>', $status, $migration->getVersion(), $version['start_time'], $version['end_time'], $migration->getName()));
|
||||
|
||||
if ($version && $version['breakpoint']) {
|
||||
$output->writeln(' <error>BREAKPOINT SET</error>');
|
||||
}
|
||||
|
||||
$migrations[] = [
|
||||
'migration_status' => trim(strip_tags($status)),
|
||||
'migration_id' => sprintf('%14.0f', $migration->getVersion()),
|
||||
'migration_name' => $migration->getName()
|
||||
];
|
||||
unset($versions[$migration->getVersion()]);
|
||||
}
|
||||
|
||||
if (count($versions)) {
|
||||
foreach ($versions as $missing => $version) {
|
||||
$output->writeln(sprintf(' <error>up</error> %14.0f %19s %19s <comment>%s</comment> <error>** MISSING **</error>', $missing, $version['start_time'], $version['end_time'], str_pad($version['migration_name'], $maxNameLength, ' ')));
|
||||
|
||||
if ($version && $version['breakpoint']) {
|
||||
$output->writeln(' <error>BREAKPOINT SET</error>');
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// there are no migrations
|
||||
$output->writeln('');
|
||||
$output->writeln('There are no available migrations. Try creating one using the <info>create</info> command.');
|
||||
}
|
||||
|
||||
// write an empty line
|
||||
$output->writeln('');
|
||||
if ($format !== null) {
|
||||
switch ($format) {
|
||||
case 'json':
|
||||
$output->writeln(json_encode([
|
||||
'pending_count' => count($this->getMigrations()),
|
||||
'migrations' => $migrations
|
||||
]));
|
||||
break;
|
||||
default:
|
||||
$output->writeln('<info>Unsupported format: ' . $format . '</info>');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
83
extend/think/migration/command/seed/Create.php
Normal file
83
extend/think/migration/command/seed/Create.php
Normal file
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | TopThink [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016 http://www.topthink.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: zhangyajun <448901948@qq.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think\migration\command\seed;
|
||||
|
||||
use Phinx\Util\Util;
|
||||
use think\console\Input;
|
||||
use think\console\input\Argument as InputArgument;
|
||||
use think\console\Output;
|
||||
use think\migration\command\Seed;
|
||||
|
||||
class Create extends Seed
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('seed:create')
|
||||
->setDescription('Create a new database seeder')
|
||||
->addArgument('name', InputArgument::REQUIRED, 'What is the name of the seeder?')
|
||||
->setHelp(sprintf('%sCreates a new database seeder%s', PHP_EOL, PHP_EOL));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the new seeder.
|
||||
*
|
||||
* @param Input $input
|
||||
* @param Output $output
|
||||
* @return void
|
||||
* @throws \InvalidArgumentException
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
protected function execute(Input $input, Output $output)
|
||||
{
|
||||
$path = $this->getPath();
|
||||
|
||||
if (!file_exists($path)) {
|
||||
mkdir($path, 0755, true);
|
||||
}
|
||||
|
||||
$this->verifyMigrationDirectory($path);
|
||||
|
||||
$path = realpath($path);
|
||||
|
||||
$className = $input->getArgument('name');
|
||||
|
||||
if (!Util::isValidPhinxClassName($className)) {
|
||||
throw new \InvalidArgumentException(sprintf('The seed class name "%s" is invalid. Please use CamelCase format', $className));
|
||||
}
|
||||
|
||||
// Compute the file path
|
||||
$filePath = $path . DIRECTORY_SEPARATOR . $className . '.php';
|
||||
|
||||
if (is_file($filePath)) {
|
||||
throw new \InvalidArgumentException(sprintf('The file "%s" already exists', basename($filePath)));
|
||||
}
|
||||
|
||||
// inject the class names appropriate to this seeder
|
||||
$contents = file_get_contents($this->getTemplate());
|
||||
$classes = [
|
||||
'SeederClass' => $className,
|
||||
];
|
||||
$contents = strtr($contents, $classes);
|
||||
|
||||
if (false === file_put_contents($filePath, $contents)) {
|
||||
throw new \RuntimeException(sprintf('The file "%s" could not be written to', $path));
|
||||
}
|
||||
|
||||
$output->writeln('<info>created</info> .' . str_replace(getcwd(), '', $filePath));
|
||||
}
|
||||
|
||||
protected function getTemplate()
|
||||
{
|
||||
return __DIR__ . '/../stubs/seed.stub';
|
||||
}
|
||||
}
|
||||
107
extend/think/migration/command/seed/Run.php
Normal file
107
extend/think/migration/command/seed/Run.php
Normal file
@@ -0,0 +1,107 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | TopThink [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016 http://www.topthink.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: zhangyajun <448901948@qq.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think\migration\command\seed;
|
||||
|
||||
use Phinx\Seed\SeedInterface;
|
||||
use think\console\Input;
|
||||
use think\console\input\Option as InputOption;
|
||||
use think\console\Output;
|
||||
use think\migration\command\Seed;
|
||||
|
||||
class Run extends Seed
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('seed:run')
|
||||
->setDescription('Run database seeders')
|
||||
->addOption('--seed', '-s', InputOption::VALUE_REQUIRED, 'What is the name of the seeder?')
|
||||
->setHelp(<<<EOT
|
||||
The <info>seed:run</info> command runs all available or individual seeders
|
||||
|
||||
<info>php think seed:run</info>
|
||||
<info>php think seed:run -s UserSeeder</info>
|
||||
<info>php think seed:run -v</info>
|
||||
|
||||
EOT
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run database seeders.
|
||||
*
|
||||
* @param Input $input
|
||||
* @param Output $output
|
||||
* @return void
|
||||
*/
|
||||
protected function execute(Input $input, Output $output)
|
||||
{
|
||||
$seed = $input->getOption('seed');
|
||||
|
||||
// run the seed(ers)
|
||||
$start = microtime(true);
|
||||
$this->seed($seed);
|
||||
$end = microtime(true);
|
||||
|
||||
$output->writeln('');
|
||||
$output->writeln('<comment>All Done. Took ' . sprintf('%.4fs', $end - $start) . '</comment>');
|
||||
}
|
||||
|
||||
public function seed($seed = null)
|
||||
{
|
||||
$seeds = $this->getSeeds();
|
||||
|
||||
if (null === $seed) {
|
||||
// run all seeders
|
||||
foreach ($seeds as $seeder) {
|
||||
if (array_key_exists($seeder->getName(), $seeds)) {
|
||||
$this->executeSeed($seeder);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// run only one seeder
|
||||
if (array_key_exists($seed, $seeds)) {
|
||||
$this->executeSeed($seeds[$seed]);
|
||||
} else {
|
||||
throw new \InvalidArgumentException(sprintf('The seed class "%s" does not exist', $seed));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function executeSeed(SeedInterface $seed)
|
||||
{
|
||||
$this->output->writeln('');
|
||||
$this->output->writeln(' ==' . ' <info>' . $seed->getName() . ':</info>' . ' <comment>seeding</comment>');
|
||||
|
||||
// Execute the seeder and log the time elapsed.
|
||||
$start = microtime(true);
|
||||
$seed->setAdapter($this->getAdapter());
|
||||
|
||||
// begin the transaction if the adapter supports it
|
||||
if ($this->getAdapter()->hasTransactions()) {
|
||||
$this->getAdapter()->beginTransaction();
|
||||
}
|
||||
|
||||
// Run the seeder
|
||||
if (method_exists($seed, SeedInterface::RUN)) {
|
||||
$seed->run();
|
||||
}
|
||||
|
||||
// commit the transaction if the adapter supports it
|
||||
if ($this->getAdapter()->hasTransactions()) {
|
||||
$this->getAdapter()->commitTransaction();
|
||||
}
|
||||
$end = microtime(true);
|
||||
|
||||
$this->output->writeln(' ==' . ' <info>' . $seed->getName() . ':</info>' . ' <comment>seeded' . ' ' . sprintf('%.4fs', $end - $start) . '</comment>');
|
||||
}
|
||||
}
|
||||
11
extend/think/migration/command/stubs/factory.stub
Normal file
11
extend/think/migration/command/stubs/factory.stub
Normal file
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
use Faker\Generator as Faker;
|
||||
use think\migration\Factory;
|
||||
|
||||
/** @var Factory $factory */
|
||||
$factory->define("ModelClass", function (Faker $faker) {
|
||||
return [
|
||||
//
|
||||
];
|
||||
});
|
||||
33
extend/think/migration/command/stubs/migrate.stub
Normal file
33
extend/think/migration/command/stubs/migrate.stub
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
use think\migration\Migrator;
|
||||
use think\migration\db\Column;
|
||||
|
||||
class MigratorClass extends Migrator
|
||||
{
|
||||
/**
|
||||
* Change Method.
|
||||
*
|
||||
* Write your reversible migrations using this method.
|
||||
*
|
||||
* More information on writing migrations is available here:
|
||||
* http://docs.phinx.org/en/latest/migrations.html#the-abstractmigration-class
|
||||
*
|
||||
* The following commands can be used in this method and Phinx will
|
||||
* automatically reverse them when rolling back:
|
||||
*
|
||||
* createTable
|
||||
* renameTable
|
||||
* addColumn
|
||||
* renameColumn
|
||||
* addIndex
|
||||
* addForeignKey
|
||||
*
|
||||
* Remember to call "create()" or "update()" and NOT "save()" when working
|
||||
* with the Table class.
|
||||
*/
|
||||
public function change()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
19
extend/think/migration/command/stubs/seed.stub
Normal file
19
extend/think/migration/command/stubs/seed.stub
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
use think\migration\Seeder;
|
||||
|
||||
class SeederClass extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run Method.
|
||||
*
|
||||
* Write your database seeder using this method.
|
||||
*
|
||||
* More information on writing seeders is available here:
|
||||
* http://docs.phinx.org/en/latest/seeding.html
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
171
extend/think/migration/db/Column.php
Normal file
171
extend/think/migration/db/Column.php
Normal file
@@ -0,0 +1,171 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: yunwuxin <448901948@qq.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think\migration\db;
|
||||
|
||||
use Phinx\Db\Adapter\AdapterInterface;
|
||||
use Phinx\Db\Adapter\MysqlAdapter;
|
||||
|
||||
class Column extends \Phinx\Db\Table\Column
|
||||
{
|
||||
protected $unique = false;
|
||||
|
||||
public function setNullable()
|
||||
{
|
||||
return $this->setNull(true);
|
||||
}
|
||||
|
||||
public function setUnsigned()
|
||||
{
|
||||
return $this->setSigned(false);
|
||||
}
|
||||
|
||||
public function setUnique()
|
||||
{
|
||||
$this->unique = true;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getUnique()
|
||||
{
|
||||
return $this->unique;
|
||||
}
|
||||
|
||||
public function isUnique()
|
||||
{
|
||||
return $this->getUnique();
|
||||
}
|
||||
|
||||
public static function make($name, $type, $options = [])
|
||||
{
|
||||
$column = new self();
|
||||
$column->setName($name);
|
||||
$column->setType($type);
|
||||
$column->setOptions($options);
|
||||
return $column;
|
||||
}
|
||||
|
||||
public static function bigInteger($name)
|
||||
{
|
||||
return self::make($name, AdapterInterface::PHINX_TYPE_BIG_INTEGER);
|
||||
}
|
||||
|
||||
public static function binary($name)
|
||||
{
|
||||
return self::make($name, AdapterInterface::PHINX_TYPE_BLOB);
|
||||
}
|
||||
|
||||
public static function boolean($name)
|
||||
{
|
||||
return self::make($name, AdapterInterface::PHINX_TYPE_BOOLEAN);
|
||||
}
|
||||
|
||||
public static function char($name, $length = 255)
|
||||
{
|
||||
return self::make($name, AdapterInterface::PHINX_TYPE_CHAR, compact('length'));
|
||||
}
|
||||
|
||||
public static function date($name)
|
||||
{
|
||||
return self::make($name, AdapterInterface::PHINX_TYPE_DATE);
|
||||
}
|
||||
|
||||
public static function dateTime($name)
|
||||
{
|
||||
return self::make($name, AdapterInterface::PHINX_TYPE_DATETIME);
|
||||
}
|
||||
|
||||
public static function decimal($name, $precision = 8, $scale = 2)
|
||||
{
|
||||
return self::make($name, AdapterInterface::PHINX_TYPE_DECIMAL, compact('precision', 'scale'));
|
||||
}
|
||||
|
||||
public static function enum($name, array $values)
|
||||
{
|
||||
return self::make($name, AdapterInterface::PHINX_TYPE_ENUM, compact('values'));
|
||||
}
|
||||
|
||||
public static function float($name)
|
||||
{
|
||||
return self::make($name, AdapterInterface::PHINX_TYPE_FLOAT);
|
||||
}
|
||||
|
||||
public static function integer($name)
|
||||
{
|
||||
return self::make($name, AdapterInterface::PHINX_TYPE_INTEGER);
|
||||
}
|
||||
|
||||
public static function json($name)
|
||||
{
|
||||
return self::make($name, AdapterInterface::PHINX_TYPE_JSON);
|
||||
}
|
||||
|
||||
public static function jsonb($name)
|
||||
{
|
||||
return self::make($name, AdapterInterface::PHINX_TYPE_JSONB);
|
||||
}
|
||||
|
||||
public static function longText($name)
|
||||
{
|
||||
return self::make($name, AdapterInterface::PHINX_TYPE_TEXT, ['length' => MysqlAdapter::TEXT_LONG]);
|
||||
}
|
||||
|
||||
public static function mediumInteger($name)
|
||||
{
|
||||
return self::make($name, AdapterInterface::PHINX_TYPE_INTEGER, ['length' => MysqlAdapter::INT_MEDIUM]);
|
||||
}
|
||||
|
||||
public static function mediumText($name)
|
||||
{
|
||||
return self::make($name, AdapterInterface::PHINX_TYPE_TEXT, ['length' => MysqlAdapter::TEXT_MEDIUM]);
|
||||
}
|
||||
|
||||
public static function smallInteger($name)
|
||||
{
|
||||
return self::make($name, AdapterInterface::PHINX_TYPE_INTEGER, ['length' => MysqlAdapter::INT_SMALL]);
|
||||
}
|
||||
|
||||
public static function string($name, $length = 255)
|
||||
{
|
||||
return self::make($name, AdapterInterface::PHINX_TYPE_STRING, compact('length'));
|
||||
}
|
||||
|
||||
public static function text($name)
|
||||
{
|
||||
return self::make($name, AdapterInterface::PHINX_TYPE_TEXT);
|
||||
}
|
||||
|
||||
public static function time($name)
|
||||
{
|
||||
return self::make($name, AdapterInterface::PHINX_TYPE_TIME);
|
||||
}
|
||||
|
||||
public static function tinyInteger($name)
|
||||
{
|
||||
return self::make($name, AdapterInterface::PHINX_TYPE_INTEGER, ['length' => MysqlAdapter::INT_TINY]);
|
||||
}
|
||||
|
||||
public static function unsignedInteger($name)
|
||||
{
|
||||
return self::integer($name)->setUnSigned();
|
||||
}
|
||||
|
||||
public static function timestamp($name)
|
||||
{
|
||||
return self::make($name, AdapterInterface::PHINX_TYPE_TIMESTAMP, ['null' => true, 'default' => null]);
|
||||
}
|
||||
|
||||
public static function uuid($name)
|
||||
{
|
||||
return self::make($name, AdapterInterface::PHINX_TYPE_UUID);
|
||||
}
|
||||
|
||||
}
|
||||
159
extend/think/migration/db/Table.php
Normal file
159
extend/think/migration/db/Table.php
Normal file
@@ -0,0 +1,159 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: yunwuxin <448901948@qq.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think\migration\db;
|
||||
|
||||
use Phinx\Db\Table\Index;
|
||||
|
||||
class Table extends \Phinx\Db\Table
|
||||
{
|
||||
|
||||
protected function setOption($name, $value)
|
||||
{
|
||||
$options = $this->getOptions();
|
||||
|
||||
$options[$name] = $value;
|
||||
|
||||
$this->table->setOptions($options);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置id
|
||||
* @param $id
|
||||
* @return $this
|
||||
*/
|
||||
public function setId($id)
|
||||
{
|
||||
return $this->setOption('id', $id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置主键
|
||||
* @param $key
|
||||
* @return $this
|
||||
*/
|
||||
public function setPrimaryKey($key)
|
||||
{
|
||||
return $this->setOption('primary_key', $key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置引擎
|
||||
* @param $engine
|
||||
* @return $this
|
||||
*/
|
||||
public function setEngine($engine)
|
||||
{
|
||||
return $this->setOption('engine', $engine);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置表注释
|
||||
* @param $comment
|
||||
* @return $this
|
||||
*/
|
||||
public function setComment($comment)
|
||||
{
|
||||
return $this->setOption('comment', $comment);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置排序比对方法
|
||||
* @param $collation
|
||||
* @return $this
|
||||
*/
|
||||
public function setCollation($collation)
|
||||
{
|
||||
return $this->setOption('collation', $collation);
|
||||
}
|
||||
|
||||
public function addSoftDelete()
|
||||
{
|
||||
$this->addColumn(Column::timestamp('delete_time')->setNullable());
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function addMorphs($name, $indexName = null)
|
||||
{
|
||||
$this->addColumn(Column::unsignedInteger("{$name}_id"));
|
||||
$this->addColumn(Column::string("{$name}_type"));
|
||||
$this->addIndex(["{$name}_id", "{$name}_type"], ['name' => $indexName]);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function addNullableMorphs($name, $indexName = null)
|
||||
{
|
||||
$this->addColumn(Column::unsignedInteger("{$name}_id")->setNullable());
|
||||
$this->addColumn(Column::string("{$name}_type")->setNullable());
|
||||
$this->addIndex(["{$name}_id", "{$name}_type"], ['name' => $indexName]);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $createdAt
|
||||
* @param string $updatedAt
|
||||
* @return $this
|
||||
*/
|
||||
public function addTimestamps($createdAt = 'create_time', $updatedAt = 'update_time', bool $withTimezone = false)
|
||||
{
|
||||
if ($createdAt) {
|
||||
$this->addColumn($createdAt, 'timestamp', [
|
||||
'null' => false,
|
||||
'default' => 'CURRENT_TIMESTAMP',
|
||||
'update' => '',
|
||||
'timezone' => $withTimezone,
|
||||
]);
|
||||
}
|
||||
if ($updatedAt) {
|
||||
$this->addColumn($updatedAt, 'timestamp', [
|
||||
'null' => true,
|
||||
'default' => null,
|
||||
'update' => '',
|
||||
'timezone' => $withTimezone,
|
||||
]);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Phinx\Db\Table\Column|string $columnName
|
||||
* @param null $type
|
||||
* @param array $options
|
||||
* @return $this
|
||||
*/
|
||||
public function addColumn($columnName, $type = null, $options = [])
|
||||
{
|
||||
if ($columnName instanceof Column && $columnName->getUnique()) {
|
||||
$index = new Index();
|
||||
$index->setColumns([$columnName->getName()]);
|
||||
$index->setType(Index::UNIQUE);
|
||||
$this->addIndex($index);
|
||||
}
|
||||
return parent::addColumn($columnName, $type, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $columnName
|
||||
* @param null $newColumnType
|
||||
* @param array $options
|
||||
* @return $this
|
||||
*/
|
||||
public function changeColumn($columnName, $newColumnType = null, $options = [])
|
||||
{
|
||||
if ($columnName instanceof \Phinx\Db\Table\Column) {
|
||||
return parent::changeColumn($columnName->getName(), $columnName, $options);
|
||||
}
|
||||
return parent::changeColumn($columnName, $newColumnType, $options);
|
||||
}
|
||||
}
|
||||
40
extend/think/migration/helper.php
Normal file
40
extend/think/migration/helper.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
use think\migration\Factory;
|
||||
use think\migration\FactoryBuilder;
|
||||
|
||||
if (!function_exists('factory')) {
|
||||
/**
|
||||
* Create a model factory builder for a given class, name, and amount.
|
||||
*
|
||||
* @param mixed class|class,name|class,amount|class,name,amount
|
||||
* @return FactoryBuilder
|
||||
*/
|
||||
function factory()
|
||||
{
|
||||
/** @var Factory $factory */
|
||||
$factory = app(Factory::class);
|
||||
|
||||
$arguments = func_get_args();
|
||||
|
||||
if (isset($arguments[1]) && is_string($arguments[1])) {
|
||||
return $factory->of($arguments[0], $arguments[1])->times($arguments[2] ?? null);
|
||||
} elseif (isset($arguments[1])) {
|
||||
return $factory->of($arguments[0])->times($arguments[1]);
|
||||
}
|
||||
|
||||
return $factory->of($arguments[0]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('database_path')) {
|
||||
/**
|
||||
* 获取数据迁移脚本地址
|
||||
* @param string $path
|
||||
* @return string
|
||||
*/
|
||||
function database_path($path = '')
|
||||
{
|
||||
return app()->getRootPath() . 'database' . DIRECTORY_SEPARATOR . $path;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user