Made definition of columns based on objects

This commit is contained in:
Christian Wolf 2019-05-29 17:55:30 +02:00
parent 8dbbb4d245
commit d93a02e779
10 changed files with 291 additions and 125 deletions

View File

@ -6,9 +6,6 @@ use Joomla\CMS\Factory;
// No direct access. // No direct access.
defined('_JEXEC') or die; defined('_JEXEC') or die;
class AssociatedObjectUnsavedException extends Exception
{}
abstract class AbstractCommonClubsModel abstract class AbstractCommonClubsModel
{ {
// TODO Add data validator // TODO Add data validator
@ -103,10 +100,9 @@ abstract class AbstractCommonClubsModel
$db = Factory::getDbo(); $db = Factory::getDbo();
$q = $db->getQuery(true); $q = $db->getQuery(true);
foreach($attribs as $k => $v) foreach($attribs as $a)
{ {
$rawColName = isset($v['col']) ? $v['col'] : $k; $a->select($q);
$q->select($q->qn($rawColName, $k));
} }
$q->from($factory->getTableName()); $q->from($factory->getTableName());
$q->where("id = {$this->id}"); $q->where("id = {$this->id}");
@ -123,22 +119,10 @@ abstract class AbstractCommonClubsModel
private function packExternalReferencesAsKeys($vals) private function packExternalReferencesAsKeys($vals)
{ {
foreach($this->getFactory()->getAttributes() as $k => $v) foreach($this->getFactory()->getAttributes() as $a)
{ {
if($v['type'] !== 'ref') $alias = $a->getAlias();
continue; $vals[$alias] = $a->packValue($vals[$alias]);
if(is_null($vals[$k]))
continue;
$id = $vals[$k]->getId();
if($id === 'new')
{
throw new AssociatedObjectUnsavedException();
}
$vals[$k] = $id;
} }
return $vals; return $vals;
@ -146,64 +130,20 @@ abstract class AbstractCommonClubsModel
private function unpackExternalReferencesFromKeys($vals) private function unpackExternalReferencesFromKeys($vals)
{ {
foreach($this->getFactory()->getAttributes() as $k => $v) foreach($this->getFactory()->getAttributes() as $a)
{ {
if(empty($v['type']) || $v['type'] !== 'ref') $alias = $a->getAlias();
continue; $vals[$alias] = $a->unpackValue($vals[$alias]);
if(empty($v['ref']))
throw new Exception('External reference of unknown class found.');
if(empty($vals[$k]))
continue;
$vals[$k] = $this->loadExternalReferenceAsObject($v['ref'], $vals[$k]);
} }
return $vals; return $vals;
} }
private function loadExternalReferenceAsObject($className, $value)
{
if(is_string($value) && preg_match('/^[0-9]+$/', $value))
$value = (int) $value;
if(! is_int($value))
throw new Exception('Reference with non-integer value');
$factoryName = $this->getFactoryNameOfClass($className);
$factory = new $factoryName();
return $factory->loadById($value);
}
private const CLASSNAME_MAP = array(
);
/**
* @todo This must be done better and more cleanly
* @param string $className
* @return AbstractCommonClubsModelFactory
*/
private function getFactoryNameOfClass($className)
{
if(empty(self::CLASSNAME_MAP[$className]))
{
$parts = array();
if(preg_match('/^CommonClubsModel(.*)/', $className, $parts))
{
return "CommonClubsModelFactory{$parts[1]}";
}
throw new Exception("Unknown mapping of class $className");
}
return self::CLASSNAME_MAP[$className];
}
/** /**
* *
* @param array $rawData * @param array $rawData
* @param array $attribs * @param AbstractCommonClubsModelColumn[] $attribs
* @param JDatabaseQuery $q * @param JDatabaseQuery $q
* @return string[]|number[]|NULL[] * @return string[]|number[]|NULL[]
*/ */
@ -211,38 +151,10 @@ abstract class AbstractCommonClubsModel
{ {
$quotedData = array(); $quotedData = array();
foreach($attribs as $k => $v) foreach($attribs as $a)
{ {
if(empty($v['type'])) $alias = $a->getAlias();
$v['type'] = 'string'; $quotedData[$alias] = $a->getQuotedValue($q, $rawData[$alias]);
if($rawData[$k] === NULL)
{
$quotedData[$k] = 'NULL';
continue;
}
switch($v['type'])
{
case 'string':
$quotedData[$k] = $q->q($rawData[$k]);
break;
case 'int':
$quotedData[$k] = (int) $rawData[$k];
break;
case 'float':
$quotedData[$k] = (float) $rawData[$k];
break;
case 'ref':
if($v['ref'] === null)
$quotedData[$k] = 'NULL';
else
$quotedData[$k] = $rawData[$k]->getId();
break;
}
} }
return $quotedData; return $quotedData;
@ -277,7 +189,7 @@ abstract class AbstractCommonClubsModel
/** /**
* *
* @param array $attribs * @param AbstractCommonClubsModelColumn[] $attribs
* @param AbstractCommonClubsModelFactory $factory * @param AbstractCommonClubsModelFactory $factory
* @param JDatabaseQuery $q * @param JDatabaseQuery $q
*/ */
@ -286,9 +198,9 @@ abstract class AbstractCommonClubsModel
$q->insert($factory->getTableName()); $q->insert($factory->getTableName());
$dbcols = array(); $dbcols = array();
foreach($attribs as $k => $v) foreach($attribs as $a)
{ {
$dbcols[] = isset($v['col']) ? $v['col'] : $k; $dbcols[] = $a->getColumn();
} }
$q->columns($q->qn($dbcols)); $q->columns($q->qn($dbcols));
@ -310,7 +222,7 @@ abstract class AbstractCommonClubsModel
/** /**
* *
* @param array $attribs * @param AbstractCommonClubsModelColumn[] $attribs
* @param AbstractCommonClubsModelFactory $factory * @param AbstractCommonClubsModelFactory $factory
* @param JDatabaseQuery $q * @param JDatabaseQuery $q
*/ */
@ -319,8 +231,8 @@ abstract class AbstractCommonClubsModel
$q->update($factory->getTableName()); $q->update($factory->getTableName());
$dbcols = array(); $dbcols = array();
foreach($attribs as $k => $v) foreach($attribs as $a)
$dbcols[] = isset($v['col']) ? $v['col'] : $k; $dbcols[] = $a->getColumn();
$quotedData = $this->getQuotedData($attribs, $q); $quotedData = $this->getQuotedData($attribs, $q);

View File

@ -0,0 +1,74 @@
<?php
// No direct access.
defined('_JEXEC') or die;
abstract class AbstractCommonClubsModelColumn
{
protected $alias;
protected $column;
protected $required;
public function getAlias()
{
return $this->alias;
}
public function getColumn()
{
return $this->column;
}
public function isRequired()
{
return $this->required;
}
public abstract function isSimpleType();
public function __construct($alias, $required = true, $column = null)
{
$this->alias = $alias;
$this->required = $required;
if(isset($column))
$this->column = $column;
else
$this->column = $alias;
}
/**
* @param JDatabaseQuery $q
*/
public function select($q)
{
$q->select($q->qn($this->column, $this->alias));
}
/**
*
* @param JDatabaseQuery $q
* @param mixed $value
*/
public abstract function getQuotedValue($q,$value);
/**
*
* @param JDatabaseQuery $q
*/
public function getQuotedColumnName($q)
{
return $q->qn($this->column);
}
public function packValue($value)
{
return $value;
}
public function unpackValue($value)
{
return $value;
}
}

View File

@ -36,6 +36,10 @@ abstract class AbstractCommonClubsModelFactory
protected abstract function fetchAttributes(); protected abstract function fetchAttributes();
private $attributes = null; private $attributes = null;
/**
* @param boolean $force
* @return AbstractCommonClubsModelColumn[]
*/
public function getAttributes($force = False) public function getAttributes($force = False)
{ {
if($this->attributes === null || $force) if($this->attributes === null || $force)
@ -164,10 +168,15 @@ abstract class AbstractCommonClubsModelFactory
$obj = $this->generatePlainObject('new'); $obj = $this->generatePlainObject('new');
$obj->markAsNew(true); $obj->markAsNew(true);
$attribs = array_map(function($v){ $values = array();
return Null; foreach($this->getAttributes() as $a)
}, $this->getAttributes()); {
$obj->setValues($attribs); $values[$a->getAlias()] = null;
}
// $attribs = array_map(function($v){
// return Null;
// }, $this->getAttributes());
$obj->setValues($values);
$obj->fillDefaultValues(); $obj->fillDefaultValues();

View File

@ -0,0 +1,22 @@
<?php
// No direct access.
defined('_JEXEC') or die;
class CommonClubsModelColumnFloat extends AbstractCommonClubsModelColumn
{
public function isSimpleType()
{
return true;
}
public function getQuotedValue($q, $value)
{
if(is_null($value))
return 'NULL';
else
return (float) $value;
}
}

View File

@ -0,0 +1,22 @@
<?php
// No direct access.
defined('_JEXEC') or die;
class CommonClubsModelColumnInt extends AbstractCommonClubsModelColumn
{
public function isSimpleType()
{
return true;
}
public function getQuotedValue($q, $value)
{
if(is_null($value))
return 'NULL';
else
return (int) $value;
}
}

View File

@ -0,0 +1,105 @@
<?php
// No direct access.
defined('_JEXEC') or die;
class WrongRefTypeException extends Exception
{}
class AssociatedObjectUnsavedException extends Exception
{}
class CommonClubsModelColumnRef extends AbstractCommonClubsModelColumn
{
protected $className;
public function __construct($alias, $className, $required=true, $column=null)
{
parent::__construct($alias, $required, $column);
if(empty($className))
throw new Exception('Classname must be non-empty.');
$this->className = $className;
}
public function isSimpleType()
{
return false;
}
public function getQuotedValue($q, $value)
{
if(is_null($value))
return 'NULL';
else
{
if(! ( $value instanceof $this->className ) )
throw new WrongRefTypeException();
$id = $value->getId();
if($id === 'new')
throw new AssociatedObjectUnsavedException();
return $id;
}
}
public function packValue($value)
{
if(is_null($value))
return null;
if(! ($value instanceof $this->className) )
throw new WrongRefTypeException();
$id = $value->getId();
if($id === 'new')
throw new AssociatedObjectUnsavedException();
return (int) $id;
}
public function unpackValue($value)
{
if(empty($value))
return null;
if(is_string($value) && preg_match('/^[0-9]+$/', $value))
$value = (int) $value;
if(! is_int($value))
throw new Exception('Reference with non-integer value');
$factoryName = $this->getFactoryNameOfClass($this->className); // XXX Use attribute?
$factory = new $factoryName();
return $factory->loadById($value);
}
private const CLASSNAME_MAP = array(
);
/**
* @todo This must be done better and more cleanly
* @param string $className
* @return AbstractCommonClubsModelFactory
*/
private function getFactoryNameOfClass($className)
{
if(empty(self::CLASSNAME_MAP[$className]))
{
$parts = array();
if(preg_match('/^CommonClubsModel(.*)/', $className, $parts))
{
return "CommonClubsModelFactory{$parts[1]}";
}
throw new Exception("Unknown mapping of class $className");
}
return self::CLASSNAME_MAP[$className];
}
}

View File

@ -0,0 +1,22 @@
<?php
// No direct access.
defined('_JEXEC') or die;
class CommonClubsModelColumnString extends AbstractCommonClubsModelColumn
{
public function isSimpleType()
{
return true;
}
public function getQuotedValue($q, $value)
{
if(is_null($value))
return 'NULL';
else
return $q->q($value);
}
}

View File

@ -8,15 +8,15 @@ class CommonClubsModelFactoryClub extends AbstractCommonClubsModelFactory
public function fetchAttributes() public function fetchAttributes()
{ {
return array( return array(
'name'=>array(), new CommonClubsModelColumnString('name'),
'address'=>array(), new CommonClubsModelColumnString('address'),
'city'=>array(), new CommonClubsModelColumnString('city'),
'homepage'=>array(), new CommonClubsModelColumnString('homepage'),
'mail'=>array(), new CommonClubsModelColumnString('mail'),
'iban'=>array(), new CommonClubsModelColumnString('iban'),
'bic'=>array(), new CommonClubsModelColumnString('bic'),
'charitable'=>array('type'=>'int'), new CommonClubsModelColumnInt('charitable'),
'president'=>array('type'=>'ref', 'ref'=>'CommonClubsModelUser') new CommonClubsModelColumnRef('president', 'CommonClubsModelUser')
); );
} }

View File

@ -8,9 +8,9 @@ class CommonClubsModelFactoryPlace extends AbstractCommonClubsModelFactory
public function fetchAttributes() public function fetchAttributes()
{ {
return array( return array(
'name'=>array(), new CommonClubsModelColumnString('name'),
'club'=>array('col'=>'clubid', 'type'=>'ref', 'ref'=>'CommonClubsModelClub'), new CommonClubsModelColumnRef('club', 'CommonClubsModelClub', true, 'clubid'),
'area'=>array('type'=>'int', 'optional'=>true) new CommonClubsModelColumnInt('area', false)
); );
} }

View File

@ -8,8 +8,8 @@ class CommonClubsModelFactoryUser extends AbstractCommonClubsModelFactory
public function fetchAttributes() public function fetchAttributes()
{ {
return array( return array(
'user'=>array(), new CommonClubsModelColumnString('user'),
'name'=>array() new CommonClubsModelColumnString('name')
); );
} }