Skip to content

Commit

Permalink
Fixes #2 Implemented xtype system and eloquent drivers
Browse files Browse the repository at this point in the history
  • Loading branch information
mtils committed May 21, 2017
1 parent 7b8f54a commit e31092b
Show file tree
Hide file tree
Showing 13 changed files with 1,461 additions and 30 deletions.
3 changes: 1 addition & 2 deletions src/Ems/Contracts/XType/SelfExplanatory.php
@@ -1,6 +1,5 @@
<?php


namespace Ems\Contracts\XType;


Expand All @@ -19,5 +18,5 @@ interface SelfExplanatory
*
* @return array|\Ems\XType\ObjectType
**/
public function myXType();
public function xTypeConfig();
}
208 changes: 208 additions & 0 deletions src/Ems/XType/Eloquent/ModelReflector.php
@@ -0,0 +1,208 @@
<?php

namespace Ems\XType\Eloquent;


use Ems\Testing\Cheat;
use Illuminate\Database\Eloquent\Model;
use ReflectionClass;

class ModelReflector
{
/**
* @var array
**/
protected $castsCache = [];

/**
* @var array
**/
protected $xTypeToCasts = [
'number|nativeType:int' => ['int', 'integer'],
'number|nativeType:float' => ['real', 'float', 'double'],
'bool' => ['bool', 'boolean'],
'object|class:stdClass' => ['object'],
'array-access' => ['array', 'json'],
'object|class:Illuminate\Support\Collection' => ['collection'],
'temporal' => ['date', 'datetime']
];

/**
* Guess the available keys by standard eloquent mechanisms like casts,
* timestamps, fillable,...
*
* @param Model $model
*
* @return array
**/
public function keys(Model $model)
{
$pk = $model->getKeyName();

$pool = [
[$pk],
$model->getVisible(),
$model->getHidden(),
$model->getFillable(),
$model->getGuarded(),
$model->getDates(),
array_keys($this->getCasts($model))
];

// SoftDeletingTrait
if (method_exists($model, 'getDeletedAtColumn')) {
$pool[] = [$model->getDeletedAtColumn()];
}

$keysByKey = [];

foreach ($pool as $i=>$keys) {
foreach ($keys as $key) {
if ($keys == ['*'] || $keys == '*') {
continue;
}

$keysByKey[$key] = true;
}
}

return array_keys($keysByKey);
}

/**
* Calculate a type rule string for $key in $model
*
* @param Model $model
* @param string $key
*
* @return string
**/
public function typeString(Model $model, $key)
{
$config = $this->baseTypeString($model, $key);

if ($this->isAutoGenerated($model, $key)) {
$config .= '|readonly';
}

return $config;
}

/**
* Return the basic type rule string for $key in $model
*
* @param Model $model
* @param string $key
*
* @return string
**/
protected function baseTypeString(Model $model, $key)
{
if ($config = $this->getFromCasts($model, $key)) {
return $config;
}

if ($this->isCastedToDateTime($model, $key)) {
return 'temporal';
}

if ($key == $model->getKeyName()) {
return 'number|nativeType:int';
}

return 'string';
}

/**
* Check if a $key in $model is casted to datetime (timestamps, casts,...)
*
* @param Model $model
* @param string $key
*
* @return bool
**/
protected function isCastedToDateTime(Model $model, $key)
{
if (in_array($key, $model->getDates())) {
return true;
}

if (method_exists($model, 'getDeletedAtColumn')) {
return $key == $model->getDeletedAtColumn();
}

return false;
}

/**
* Get the typename from the casts array
*
* @param Model $model
* @param string $key
*
* @return string The type name
**/
protected function getFromCasts(Model $model, $key)
{
$casts = $this->getCasts($model);

if (!isset($casts[$key])) {
return;
}

$cast = $casts[$key];

foreach ($this->xTypeToCasts as $xType=>$casts) {
if (in_array($cast, $casts)) {
return $xType;
}
}

return 'string';
}

/**
* Return the model casts. (By cheat, I did found another method)
*
* @param Model $model
*
* @return array
**/
protected function getCasts(Model $model)
{
$class = get_class($model);

if (!isset($this->castsCache[$class])) {
$this->castsCache[$class] = Cheat::get($model, 'casts');
}

return $this->castsCache[$class];
}

/**
* Return if a key is auto generated (like timestamps, autoincrements,...)
*
* @param Model $model
* @param string $key
*
* @return bool
**/
protected function isAutoGenerated(Model $model, $key)
{
if ($key == $model->getKeyName() && $model->getIncrementing()) {
return true;
}

$constants = (new ReflectionClass($model))->getConstants();

if (in_array($key, [$constants['CREATED_AT'], $constants['UPDATED_AT']]) && $model->usesTimestamps()) {
return true;
}

if (!method_exists($model, 'getDeletedAtColumn')) {
return false;
}

return $key == $model->getDeletedAtColumn();
}
}

0 comments on commit e31092b

Please sign in to comment.