From 7b21baee37af9a6e9d9a8a1d3523886cc1f32b23 Mon Sep 17 00:00:00 2001 From: Basilius Sauter Date: Wed, 27 Apr 2016 22:51:16 +0200 Subject: [PATCH] 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. --- src/Exceptions/ClassNotFoundException.php | 11 + src/Exceptions/KeyNotFoundException.php | 11 + src/Exceptions/NotImplementedException.php | 11 + src/Models/CharacterProperty.php | 1 + src/Models/GameConfiguration.php | 51 ++++ src/Models/GameConfigurationElement.php | 16 ++ src/Tools/Model/BaseSetting.php | 9 + src/Tools/Model/PropertyManager.php | 4 +- src/Tools/OneToManyCollection.php | 314 +++++++++++++++++++++ tests/Models/GameConfigurationTest.php | 54 ++++ tests/datasets/gameConfiguration.yml | 13 + 11 files changed, 494 insertions(+), 1 deletion(-) create mode 100644 src/Exceptions/ClassNotFoundException.php create mode 100644 src/Exceptions/KeyNotFoundException.php create mode 100644 src/Exceptions/NotImplementedException.php create mode 100644 src/Models/GameConfiguration.php create mode 100644 src/Models/GameConfigurationElement.php create mode 100644 src/Tools/Model/BaseSetting.php create mode 100644 src/Tools/OneToManyCollection.php create mode 100644 tests/Models/GameConfigurationTest.php create mode 100644 tests/datasets/gameConfiguration.yml diff --git a/src/Exceptions/ClassNotFoundException.php b/src/Exceptions/ClassNotFoundException.php new file mode 100644 index 0000000..f8b02d8 --- /dev/null +++ b/src/Exceptions/ClassNotFoundException.php @@ -0,0 +1,11 @@ +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); + } +} \ No newline at end of file diff --git a/src/Models/GameConfigurationElement.php b/src/Models/GameConfigurationElement.php new file mode 100644 index 0000000..e0fa03b --- /dev/null +++ b/src/Models/GameConfigurationElement.php @@ -0,0 +1,16 @@ +properties->getTypeClass()->name; $property = new $className(); - $property->setOwner($this); + if (method_exists($property, "setOwner")) { + $property->setOwner($this); + } $property->setName($name); $property->setValue($value); diff --git a/src/Tools/OneToManyCollection.php b/src/Tools/OneToManyCollection.php new file mode 100644 index 0000000..2133f15 --- /dev/null +++ b/src/Tools/OneToManyCollection.php @@ -0,0 +1,314 @@ +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]); + } +} \ No newline at end of file diff --git a/tests/Models/GameConfigurationTest.php b/tests/Models/GameConfigurationTest.php new file mode 100644 index 0000000..0980ca3 --- /dev/null +++ b/tests/Models/GameConfigurationTest.php @@ -0,0 +1,54 @@ +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)); + } +} diff --git a/tests/datasets/gameConfiguration.yml b/tests/datasets/gameConfiguration.yml new file mode 100644 index 0000000..5854116 --- /dev/null +++ b/tests/datasets/gameConfiguration.yml @@ -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;' \ No newline at end of file