Introduction of the GameConfiguration model
This commit introduces the GameConfiguration, a model that is not an entity. It also introduces GameConfigurationElement which is a doctrine entity. The two models make use of the traits introduced for CharacterProperty. They also use the new OneToManyCollection class, which implements the doctrine collection interface to a certain, limited extend. It mimicks doctrine's PersisentCollection.
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace LotGD\Core\Exceptions;
|
||||
|
||||
/**
|
||||
* Exception if a specific, required argument is missing
|
||||
*/
|
||||
class ClassNotFoundException extends CoreException {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace LotGD\Core\Exceptions;
|
||||
|
||||
/**
|
||||
* Exception if a specific, required argument is missing
|
||||
*/
|
||||
class KeyNotFoundException extends CoreException {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace LotGD\Core\Exceptions;
|
||||
|
||||
/**
|
||||
* Exception if a specific, required argument is missing
|
||||
*/
|
||||
class NotImplementedException extends CoreException {
|
||||
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace LotGD\Core\Models;
|
||||
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace LotGD\Core\Models;
|
||||
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
use LotGD\Core\Models\GameConfigurationElement;
|
||||
use LotGD\Core\Tools\OneToManyCollection;
|
||||
use LotGD\Core\Tools\Model\PropertyManager;
|
||||
|
||||
/**
|
||||
* Provides an interface to access properties
|
||||
*/
|
||||
class GameConfiguration
|
||||
{
|
||||
use PropertyManager;
|
||||
|
||||
/** @var ArrayCollection */
|
||||
private $properties;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param EntityManagerInterface $em
|
||||
*/
|
||||
public function __construct(EntityManagerInterface $entityManager)
|
||||
{
|
||||
$this->properties = new OneToManyCollection($entityManager, GameConfigurationElement::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a configuration value or the default one if the configuration name has not been set yet.
|
||||
* @param string $configurationName
|
||||
* @param mixed $configurationDefault
|
||||
* @return mixed
|
||||
*/
|
||||
public function get(string $configurationName, $configurationDefault)
|
||||
{
|
||||
return $this->getProperty($configurationName, $configurationDefault);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets and overwrites a configuration value saved by the name
|
||||
* @param string $configurationName
|
||||
* @param type $configurationValue
|
||||
*/
|
||||
public function set(string $configurationName, $configurationValue)
|
||||
{
|
||||
$this->setProperty($configurationName, $configurationValue);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace LotGD\Core\Models;
|
||||
|
||||
use LotGD\Core\Tools\Model\Properties;
|
||||
|
||||
/**
|
||||
* Properties for Characters
|
||||
* @Entity
|
||||
* @Table(name="game_configuration")
|
||||
*/
|
||||
class GameConfigurationElement
|
||||
{
|
||||
use Properties;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
trait BaseSetting
|
||||
{
|
||||
/** @Id @Column(type="string", length=255) */
|
||||
private $settingName;
|
||||
/** @Column(type="text") */
|
||||
private $settingValue;
|
||||
}
|
||||
@@ -43,7 +43,9 @@ trait PropertyManager
|
||||
else {
|
||||
$className = $this->properties->getTypeClass()->name;
|
||||
$property = new $className();
|
||||
$property->setOwner($this);
|
||||
if (method_exists($property, "setOwner")) {
|
||||
$property->setOwner($this);
|
||||
}
|
||||
$property->setName($name);
|
||||
$property->setValue($value);
|
||||
|
||||
|
||||
@@ -0,0 +1,314 @@
|
||||
<?php
|
||||
|
||||
namespace LotGD\Core\Tools;
|
||||
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
|
||||
|
||||
use LotGD\Core\Exceptions\ClassNotFoundException;
|
||||
use LotGD\Core\Exceptions\KeyNotFoundException;
|
||||
use LotGD\Core\Exceptions\NotImplementedException;
|
||||
use LotGD\Core\Exceptions\WrongTypeException;
|
||||
|
||||
class OneToManyCollection implements Collection
|
||||
{
|
||||
/** @var string */
|
||||
private $typeClass;
|
||||
/** @var EntityManagerInterface */
|
||||
private $entityManager = null;
|
||||
/** @var array */
|
||||
private $collection;
|
||||
/** @var int */
|
||||
private $numberOfRows;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param EntityManagerInterface $entityManager
|
||||
* @param string $typeClass
|
||||
* @throws ClassNotFoundException
|
||||
*/
|
||||
public function __construct(EntityManagerInterface $entityManager, string $typeClass)
|
||||
{
|
||||
if(class_exists($typeClass) === false) {
|
||||
throw new ClassNotFoundException(sprintf("The class %s has not been found.", $typeClass));
|
||||
}
|
||||
|
||||
$this->entityManager = $entityManager;
|
||||
$this->typeClass = $typeClass;
|
||||
|
||||
// Load eagerly everything.
|
||||
$this->collection = $this->entityManager->getRepository($this->typeClass)->findAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the class this collection consists of.
|
||||
* @return string
|
||||
*/
|
||||
public function getTypeClass(): ClassMetadata
|
||||
{
|
||||
return $this->entityManager->getClassMetadata($this->typeClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts the number of settings stored
|
||||
* @return int
|
||||
*/
|
||||
public function count(): int
|
||||
{
|
||||
// If the collection has not been loaded yet, we should query the db directly
|
||||
if ($this->collection === null and $this->numberOfRows === null) {
|
||||
$this->numberOfRows = (int)$this->entityManager->createQueryBuilder()
|
||||
->from($this->typeClass, "p")
|
||||
->select("COUNT(p.propertyName)")
|
||||
->getQuery()
|
||||
->getSingleScalarResult();
|
||||
}
|
||||
|
||||
if ($this->collection === null) {
|
||||
return $this->numberOfRows;
|
||||
}
|
||||
else {
|
||||
return count($this->collection);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the element matches the typeClass of this collection
|
||||
* @param mixed $element
|
||||
* @throws WrongTypeException
|
||||
*/
|
||||
private function checkElementType($element)
|
||||
{
|
||||
if ($element instanceof $this->typeClass === false) {
|
||||
throw new WrongTypeException(sprintf('$element needs to be of type %s', $this->typeClass));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an element to the collection
|
||||
* @param mixed $element
|
||||
*/
|
||||
public function add($element)
|
||||
{
|
||||
$this->checkElementType($element);
|
||||
|
||||
if ($this->collection === null) {
|
||||
$this->collection = [];
|
||||
}
|
||||
|
||||
$this->collection[] = $element;
|
||||
$this->entityManager->persist($element);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the collection
|
||||
*/
|
||||
public function clear()
|
||||
{
|
||||
$this->entityManager->createQueryBuilder()
|
||||
->delete($this->typeClass, "p")
|
||||
->getQuery()
|
||||
->execute();
|
||||
$this->collection = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a item is contained in this collection
|
||||
* @param type $element
|
||||
* @return bool
|
||||
*/
|
||||
public function contains($element): bool
|
||||
{
|
||||
$this->checkElementType($element);
|
||||
return in_array($element, $this->collection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this the collection is empty
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmpty(): bool
|
||||
{
|
||||
return empty($this->collection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an element from this collection by the given key
|
||||
* @param int|string $key
|
||||
*/
|
||||
public function remove($key)
|
||||
{
|
||||
if (isset($this->collection[$key])) {
|
||||
$element = $this->collection[$key];
|
||||
$this->removeElement($element);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an element from this collection
|
||||
* @param type $element
|
||||
*/
|
||||
public function removeElement($element)
|
||||
{
|
||||
if ($this->contains($element)) {
|
||||
$key = array_search($element, $this->collection);
|
||||
$this->entityManager->remove($element);
|
||||
unset($this->collection[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this collection contains a certain key
|
||||
* @param int|string $key
|
||||
*/
|
||||
public function containsKey($key)
|
||||
{
|
||||
return isset($this->collection[$key]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the element saved at the given position
|
||||
* @param int|string $key
|
||||
* @return type
|
||||
* @throws KeyNotFoundException
|
||||
*/
|
||||
public function get($key)
|
||||
{
|
||||
if (isset($this->collection[$key])) {
|
||||
return $this->collection[$key];
|
||||
}
|
||||
else {
|
||||
throw new KeyNotFoundException(sprintf("The key %s has not been found within the collection", $key));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all collection keys
|
||||
* @return array
|
||||
*/
|
||||
public function getKeys(): array
|
||||
{
|
||||
return array_keys($this->collection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all collection values
|
||||
* @return array
|
||||
*/
|
||||
public function getValues(): array
|
||||
{
|
||||
return array_values($this->collection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the element at position $key to $value.
|
||||
* @param int|string $key
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function set($key, $element)
|
||||
{
|
||||
$this->checkElementType($element);
|
||||
$this->collection[$key] = $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array representation of this collection
|
||||
* @return array
|
||||
*/
|
||||
public function toArray(): array
|
||||
{
|
||||
return $this->collection;
|
||||
}
|
||||
|
||||
public function first()
|
||||
{
|
||||
return first($this->collection);
|
||||
}
|
||||
|
||||
public function last()
|
||||
{
|
||||
return last($this->collection);
|
||||
}
|
||||
|
||||
public function key()
|
||||
{
|
||||
return key($this->collection);
|
||||
}
|
||||
|
||||
public function next()
|
||||
{
|
||||
return next($this->collection);
|
||||
}
|
||||
|
||||
public function current()
|
||||
{
|
||||
return current($this->collection);
|
||||
}
|
||||
|
||||
public function exists(\Closure $p): bool
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public function filter(\Closure $p)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public function forAll(\Closure $p)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public function map(\Closure $p)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public function partition(\Closure $p)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of a specific element
|
||||
* @param mixed $element
|
||||
* @return int|string
|
||||
*/
|
||||
public function indexOf($element)
|
||||
{
|
||||
$this->checkElementType($element);
|
||||
return array_search($element, $this->collection);
|
||||
}
|
||||
|
||||
public function slice($offset, $length = null)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a Iterator over this collection
|
||||
* @return \ArrayIterator
|
||||
*/
|
||||
public function getIterator()
|
||||
{
|
||||
return new \ArrayIterator($this->collection);
|
||||
}
|
||||
|
||||
public function offsetGet($key) {
|
||||
return $this->get($key);
|
||||
}
|
||||
|
||||
public function offsetSet($key, $element) {
|
||||
$this->set($key, $element);
|
||||
}
|
||||
|
||||
public function offsetUnset($key) {
|
||||
$this->remove($key);
|
||||
}
|
||||
|
||||
public function offsetExists($key) {
|
||||
return isset($this->collection[$key]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace LotGD\Core\Tests\Models;
|
||||
|
||||
use LotGD\Core\Models\GameConfiguration;
|
||||
use LotGD\Core\Tests\ModelTestCase;
|
||||
|
||||
/**
|
||||
* Tests the management of CharacterScenes
|
||||
*/
|
||||
class GameConfigurationTest extends ModelTestCase
|
||||
{
|
||||
/** @var string default data set */
|
||||
protected $dataset = "gameConfiguration";
|
||||
|
||||
public function testGetConfiguration()
|
||||
{
|
||||
$configuration = new GameConfiguration($this->getEntityManager());
|
||||
|
||||
$this->assertSame("hallo", $configuration->get("default_test", "hallo"));
|
||||
$this->assertSame(87897, $configuration->get("default_test_int", 87897));
|
||||
|
||||
$this->assertSame("Legend of the Green Dragon", $configuration->get("gameName", "Daenerys"));
|
||||
$this->assertSame("1.0.5.6", $configuration->get("gameVersion", "1.0"));
|
||||
$this->assertSame(30, $configuration->get("maxPlayerOnline", 100));
|
||||
$this->assertSame(30.4, $configuration->get("testFloat", 100.123512));
|
||||
|
||||
$this->getEntityManager()->flush();
|
||||
}
|
||||
|
||||
public function datasetSetAndGet() {
|
||||
return [
|
||||
["testOne", 15],
|
||||
["testTwo", "256"]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests setting settings and fetching them back from the database
|
||||
* @dataProvider datasetSetAndGet
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function testSetAndGet(string $key, $value)
|
||||
{
|
||||
$configuration = new GameConfiguration($this->getEntityManager());
|
||||
|
||||
$configuration->set($key, $value);
|
||||
$this->getEntityManager()->flush();
|
||||
$this->getEntityManager()->clear();
|
||||
$this->assertSame($value, $configuration->get($key, null));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
game_configuration:
|
||||
-
|
||||
propertyName: "gameName"
|
||||
propertyValue: 's:26:"Legend of the Green Dragon";'
|
||||
-
|
||||
propertyName: "gameVersion"
|
||||
propertyValue: 's:7:"1.0.5.6";'
|
||||
-
|
||||
propertyName: "maxPlayerOnline"
|
||||
propertyValue: 'i:30;'
|
||||
-
|
||||
propertyName: "testFloat"
|
||||
propertyValue: 'd:30.4;'
|
||||
Reference in New Issue
Block a user