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,12 +6,9 @@ use Joomla\CMS\Factory;
// No direct access.
defined('_JEXEC') or die;
class AssociatedObjectUnsavedException extends Exception
{}
abstract class AbstractCommonClubsModel
{
// TODO Adddata validator
// TODO Add data validator
// TODO Make setting of values attribute fail in case of problems
// FIXME Add Joins in select statements
@ -103,10 +100,9 @@ abstract class AbstractCommonClubsModel
$db = Factory::getDbo();
$q = $db->getQuery(true);
foreach($attribs as $k => $v)
foreach($attribs as $a)
{
$rawColName = isset($v['col']) ? $v['col'] : $k;
$q->select($q->qn($rawColName, $k));
$a->select($q);
}
$q->from($factory->getTableName());
$q->where("id = {$this->id}");
@ -123,22 +119,10 @@ abstract class AbstractCommonClubsModel
private function packExternalReferencesAsKeys($vals)
{
foreach($this->getFactory()->getAttributes() as $k => $v)
foreach($this->getFactory()->getAttributes() as $a)
{
if($v['type'] !== 'ref')
continue;
if(is_null($vals[$k]))
continue;
$id = $vals[$k]->getId();
if($id === 'new')
{
throw new AssociatedObjectUnsavedException();
}
$vals[$k] = $id;
$alias = $a->getAlias();
$vals[$alias] = $a->packValue($vals[$alias]);
}
return $vals;
@ -146,64 +130,20 @@ abstract class AbstractCommonClubsModel
private function unpackExternalReferencesFromKeys($vals)
{
foreach($this->getFactory()->getAttributes() as $k => $v)
foreach($this->getFactory()->getAttributes() as $a)
{
if(empty($v['type']) || $v['type'] !== 'ref')
continue;
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]);
$alias = $a->getAlias();
$vals[$alias] = $a->unpackValue($vals[$alias]);
}
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 $attribs
* @param AbstractCommonClubsModelColumn[] $attribs
* @param JDatabaseQuery $q
* @return string[]|number[]|NULL[]
*/
@ -211,38 +151,10 @@ abstract class AbstractCommonClubsModel
{
$quotedData = array();
foreach($attribs as $k => $v)
foreach($attribs as $a)
{
if(empty($v['type']))
$v['type'] = 'string';
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;
}
$alias = $a->getAlias();
$quotedData[$alias] = $a->getQuotedValue($q, $rawData[$alias]);
}
return $quotedData;
@ -277,7 +189,7 @@ abstract class AbstractCommonClubsModel
/**
*
* @param array $attribs
* @param AbstractCommonClubsModelColumn[] $attribs
* @param AbstractCommonClubsModelFactory $factory
* @param JDatabaseQuery $q
*/
@ -286,9 +198,9 @@ abstract class AbstractCommonClubsModel
$q->insert($factory->getTableName());
$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));
@ -310,7 +222,7 @@ abstract class AbstractCommonClubsModel
/**
*
* @param array $attribs
* @param AbstractCommonClubsModelColumn[] $attribs
* @param AbstractCommonClubsModelFactory $factory
* @param JDatabaseQuery $q
*/
@ -319,8 +231,8 @@ abstract class AbstractCommonClubsModel
$q->update($factory->getTableName());
$dbcols = array();
foreach($attribs as $k => $v)
$dbcols[] = isset($v['col']) ? $v['col'] : $k;
foreach($attribs as $a)
$dbcols[] = $a->getColumn();
$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();
private $attributes = null;
/**
* @param boolean $force
* @return AbstractCommonClubsModelColumn[]
*/
public function getAttributes($force = False)
{
if($this->attributes === null || $force)
@ -164,10 +168,15 @@ abstract class AbstractCommonClubsModelFactory
$obj = $this->generatePlainObject('new');
$obj->markAsNew(true);
$attribs = array_map(function($v){
return Null;
}, $this->getAttributes());
$obj->setValues($attribs);
$values = array();
foreach($this->getAttributes() as $a)
{
$values[$a->getAlias()] = null;
}
// $attribs = array_map(function($v){
// return Null;
// }, $this->getAttributes());
$obj->setValues($values);
$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()
{
return array(
'name'=>array(),
'address'=>array(),
'city'=>array(),
'homepage'=>array(),
'mail'=>array(),
'iban'=>array(),
'bic'=>array(),
'charitable'=>array('type'=>'int'),
'president'=>array('type'=>'ref', 'ref'=>'CommonClubsModelUser')
new CommonClubsModelColumnString('name'),
new CommonClubsModelColumnString('address'),
new CommonClubsModelColumnString('city'),
new CommonClubsModelColumnString('homepage'),
new CommonClubsModelColumnString('mail'),
new CommonClubsModelColumnString('iban'),
new CommonClubsModelColumnString('bic'),
new CommonClubsModelColumnInt('charitable'),
new CommonClubsModelColumnRef('president', 'CommonClubsModelUser')
);
}

View File

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

View File

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