Skip to content

Commit

Permalink
[ADD] Feature Auto connect models
Browse files Browse the repository at this point in the history
  • Loading branch information
dedensaka committed Mar 4, 2017
1 parent d239e67 commit c50722a
Show file tree
Hide file tree
Showing 20 changed files with 744 additions and 382 deletions.
2 changes: 2 additions & 0 deletions src/Flipbox/OrmManager/BothRelations/BothRelation.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ public function __construct(Command $command,
$toModel=null,
array $options=[])
{
$this->options = $options;

parent::__construct($command, $manager, $model, $toModel, $options);

$this->options = array_merge($this->defaultOptions, $this->options);
Expand Down
7 changes: 5 additions & 2 deletions src/Flipbox/OrmManager/BothRelations/ManyToMany.php
Original file line number Diff line number Diff line change
Expand Up @@ -126,9 +126,12 @@ public function buildRelations()
{
$this->command->buildMethod($this->model, 'belongsToMany', $this->toModel, $this->options);

$this->options['foreign_key'] = $this->options['related_key'];
$this->options['related_key'] = $this->options['foreign_key'];
$foreignKey = $this->options['foreign_key'];
$relatedKey = $this->options['related_key'];
$this->options['foreign_key'] = $relatedKey;
$this->options['related_key'] = $foreignKey;
$this->options['relation'] = $this->model->getTable();

$this->command->buildMethod($this->toModel, 'belongsToMany', $this->model, $this->options);
}
}
2 changes: 1 addition & 1 deletion src/Flipbox/OrmManager/BothRelations/MorphOneToMany.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class MorphOneToMany extends MorphOneToOne
*/
public function buildRelations()
{
$this->command->buildMethod($this->model, 'morphTo', $this->toModel, $this->options);
$this->command->buildMethod($this->model, 'morphTo', null, $this->options);

foreach ($this->toModels as $key => $toModel) {
$options = $this->options;
Expand Down
10 changes: 7 additions & 3 deletions src/Flipbox/OrmManager/BothRelations/MorphOneToOne.php
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,13 @@ protected function setDefaultOptions(array $options=[])
{
$this->text['relation_name_text'] = $this->command->paintString('relation name', 'brown');

$refModel = new ReflectionClass($this->model);
$name = $this->getRelationName(strtolower($refModel->getShortName()));
$name = $this->command->ask("What {$this->text['relation_name_text']} do you use?", $name);
if (! isset($options['name'])) {
$refModel = new ReflectionClass($this->model);
$name = $this->getRelationName(strtolower($refModel->getShortName()));
$name = $this->command->ask("What {$this->text['relation_name_text']} do you use?", $name);
} else {
$name = $options['name'];
}

$this->defaultOptions = [
'name' => $name,
Expand Down
24 changes: 18 additions & 6 deletions src/Flipbox/OrmManager/Consoles/Command.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public function success($string)
{
$string = $this->paintString("{$string}", 'green');

print("{$string}\n");
$this->print($string);
}

/**
Expand All @@ -76,11 +76,11 @@ public function success($string)
* @param string $string
* @return void
*/
public function title($string)
public function title($string, $backgorund='blue', $forgeground='white')
{
$string = $this->paintString(" {$string} ", 'white', 'blue');
$string = $this->paintString(" {$string} ", $forgeground, $backgorund);

print("{$string}\n");
$this->print($string);
}

/**
Expand All @@ -91,9 +91,9 @@ public function title($string)
*/
public function danger($string)
{
$string = $this->paintString(" Error : {$string} ", 'white', 'red', 'italic');
$string = $this->paintString("{$string}", 'red');

print("{$string}\n");
$this->print($string);
}

/**
Expand All @@ -107,6 +107,18 @@ public function warn($string, $verbosity = null)
{
$string = $this->paintString(" Warning : {$string} ", 'white', 'yellow', 'italic');

$this->print($string);
}

/**
* Write a string as warning output.
*
* @param string $string
* @param null|int|string $verbosity
* @return void
*/
public function print($string)
{
print($string)."\r\n";
}

Expand Down
250 changes: 250 additions & 0 deletions src/Flipbox/OrmManager/Consoles/ModelAutoConnect.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,250 @@
<?php

namespace Flipbox\OrmManager\Consoles;

use Exception;
use Illuminate\Support\Str;
use Illuminate\Config\Repository;
use Flipbox\OrmManager\ModelManager;
use Illuminate\Database\Eloquent\Model;
use Flipbox\OrmManager\DatabaseConnection;
use Flipbox\OrmManager\Exceptions\ModelNotFound;
use Flipbox\OrmManager\Exceptions\TableNotExists;

class ModelAutoConnect extends ModelBothConnect
{

/**
* model manager
*
* @var ModelManager
*/
protected $manager;

/**
* database
*
* @var ModelManager
*/
protected $db;

/**
* The console command name.
*
* @var string
*/
protected $signature = 'orm:auto-connect';

/**
* The console command description.
*
* @var string
*/
protected $description = 'Auto detect primary or foreign or related key then generate connections method of class model';

/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
if (! $this->db->isConnected() OR count($tables = $this->db->getTables()) === 0) {
return $this->error('Auto connect only if you has been created your database and connected.');
}

try {
$this->checkTables();
$this->searchOnModels();
$this->searchOnTables();
} catch (Exception $e) {
return $this->error($e->getMessage());
}
}

/**
* check tables
*
* @return void
*/
protected function checkTables()
{
foreach ($this->manager->getModels() as $model) {
if (! $this->db->isTableExists($table = $model->getTable())) {
throw new TableNotExists($table, $this->manager->getClassName($model));
}
}
}

/**
* search relations on the models
*
* @return void
*/
protected function searchOnModels()
{
foreach ($this->manager->getModels() as $model) {
foreach ($this->manager->getModels() as $toModel) {
if ($this->db->isFieldExists($toModel->getTable(),
$model->getForeignKey())) {
$this->buildOneToOneOrMany($model, $toModel);

foreach ($this->manager->getModels() as $intermediateModel) {
if ($this->db->isFieldExists($intermediateModel->getTable(),
$toModel->getForeignKey())) {
$this->buildhasManyThrough($model, $toModel, $intermediateModel);
}
}
}

$pivotTable = implode('_', array_map('strtolower', [
$this->manager->getClassName($model),
$this->manager->getClassName($toModel)
]));

if ($this->db->isTableExists($pivotTable)
AND $this->db->isFieldExists($pivotTable, $model->getForeignKey())
AND $this->db->isFieldExists($pivotTable, $toModel->getForeignKey())) {
$this->buildManyToMany($model, $toModel);
}
}
}
}

/**
* search on the tables
*
* @return void
*/
protected function searchOnTables()
{
$tables = $this->db->getTables();
unset($tables['migrations']);

foreach ($tables as $name => $table) {
$type = false;
foreach ($table as $filed) {
if (Str::contains($filed['name'], '_type')) $type = $filed['name'];
}

$id = false;
foreach ($table as $filed) {
if (Str::contains($filed['name'], '_id')) $id = $filed['name'];
}

if ($type AND $id) {
$type = str_replace('_type', '', $type);
$id = str_replace('_id', '', $id);
}

if ($type !== false AND $id !== false) {
try {
$model = $this->manager->tableToModel($name);
$this->buildMorphOneToOneOrMany($model, $type);
} catch (ModelNotFound $e) {
foreach ($this->manager->getModels() as $model) {
if ($this->db->isFieldExists($name, $model->getForeignKey())) {
$this->buildMorphManyToMany($model, $type);
}
}
} catch (Exception $e) {
throw $e;
}
}
}
}

/**
* build relation one to one or many
*
* @param Model $model
* @param Model $toModel
* @return void
*/
protected function buildOneToOneOrMany(Model $model, Model $toModel)
{
$modelName = $this->manager->getClassName($model);
$toModelName = $this->manager->getClassName($toModel);

$this->title(" >>> Relation {$modelName} and {$toModelName} are detected. ", 'light_gray', 'red');

$bothRelation = $this->choice("What relation between {$modelName} and {$toModelName}?", ['oneToOne', 'oneToMany']);

return $this->buildRelations($model, $bothRelation, $toModel);
}

/**
* build relation has many through
*
* @param Model $model
* @param Model $toModel
* @param Model $intermediateModel
* @return void
*/
protected function buildhasManyThrough(Model $model, Model $intermediateModel, Model $toModel)
{
$modelName = $this->manager->getClassName($model);
$intermediateModelName = $this->manager->getClassName($intermediateModel);
$toModelName = $this->manager->getClassName($toModel);

$this->title(" >>> Relation {$modelName} has many {$toModelName} through {$intermediateModelName} are detected. ", 'light_gray', 'red');

return $this->buildMethod($model, 'hasManyThrough', $toModel, ['intermediate_model'=>$intermediateModel]);
}

/**
* build relation many to many
*
* @param Model $model
* @param Model $toModel
* @return void
*/
protected function buildManyToMany(Model $model, Model $toModel)
{
$modelName = $this->manager->getClassName($model);
$toModelName = $this->manager->getClassName($toModel);

$this->title(" >>> Relation many to many between {$modelName} and {$toModelName} are detected. ", 'light_gray', 'red');

return $this->buildRelations($model, 'manyToMany', $toModel);
}

/**
* build relation morph one to one or many
*
* @param Model $model
* @param string $name
* @return void
*/
protected function buildMorphOneToOneOrMany(Model $model, $name)
{
$modelName = $this->manager->getClassName($model);

$this->title(" >>> Polymorphic Relations {$modelName} are detected. ", 'light_gray', 'red');

$bothRelation = $this->choice("{$modelName} morph relation will be?", ['morphOneToOne', 'morphOneToMany']);
$toModels = $this->choice("choice multiple models (comma sparated) that will be morph connected with {$modelName}!", $this->manager->getModels()->keys()->toArray(), null, null, true);
$toModels = array_map([$this->manager, 'getModel'], $toModels);

return $this->buildRelations($model, $bothRelation, $toModels, ['name'=>$name]);
}

/**
* build relation morph many to many
*
* @param Model $model
* @param string $name
* @return void
*/
protected function buildMorphManyToMany(Model $model, $name)
{
$modelName = $this->manager->getClassName($model);

$this->title(" >>> Polymorphic Relations {$name} of model {$modelName} are detected. ", 'light_gray', 'red');

$toModels = $this->choice("choice multiple models (comma sparated) that will be morph many to many with {$modelName}!", $this->manager->getModels()->keys()->toArray(), null, null, true);
$toModels = array_map([$this->manager, 'getModel'], $toModels);

return $this->buildRelations($model, 'morphManyToMany', $toModels, ['name'=>$name]);
}
}
12 changes: 7 additions & 5 deletions src/Flipbox/OrmManager/Consoles/ModelBothConnect.php
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ protected function isRequiredArgFulfilled($arguments)
*/
protected function runInteractiveConnect()
{
$models = $this->manager->getModels()->pluck('name')->toArray();
$models = $this->manager->getModels()->keys()->toArray();

$search = array_search($this->argument('model'), $models);
$default = $search === false ? null : $search;
Expand Down Expand Up @@ -141,12 +141,13 @@ protected function getRelation($relation)
* @param Model $model
* @param string $relation
* @param mixed $toModel
* @param array $options
* @return void
*/
protected function buildRelations(Model $model, $relation, $toModel)
protected function buildRelations(Model $model, $relation, $toModel, array $options=[])
{
try {
$bothRelation = $this->newBothRelationInstance($relation, $model, $toModel);
$bothRelation = $this->newBothRelationInstance($relation, $model, $toModel, $options);

$bothRelation->buildRelations();
} catch (Exception $e) {
Expand All @@ -160,12 +161,13 @@ protected function buildRelations(Model $model, $relation, $toModel)
* @param string $relation
* @param Model $model
* @param mix Model|null $toModel
* @param array $options
* @return Model
*/
protected function newBothRelationInstance($relation, Model $model, $toModel)
protected function newBothRelationInstance($relation, Model $model, $toModel, array $options=[])
{
$class = 'Flipbox\OrmManager\BothRelations\\'.Str::studly($relation);

return new $class($this, $this->manager, $model, $toModel);
return new $class($this, $this->manager, $model, $toModel, $options);
}
}
Loading

0 comments on commit c50722a

Please sign in to comment.