Introduces a SceneAttachment model for registering attachments.
This commit is contained in:
+91
-6
@@ -7,17 +7,26 @@ use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\Mapping\Entity;
|
||||
use Doctrine\ORM\Mapping\Id;
|
||||
use Doctrine\ORM\Mapping\JoinTable;
|
||||
use Doctrine\ORM\Mapping\ManyToMany;
|
||||
use Doctrine\ORM\Mapping\OneToMany;
|
||||
use Doctrine\ORM\Mapping\Table;
|
||||
use Doctrine\ORM\Mapping\Column;
|
||||
|
||||
use JetBrains\PhpStorm\Deprecated;
|
||||
use LotGD\Core\Exceptions\ArgumentException;
|
||||
use LotGD\Core\Exceptions\AttributeMissingException;
|
||||
use LotGD\Core\Exceptions\UnexpectedArrayKeyException;
|
||||
use LotGD\Core\Exceptions\WrongTypeException;
|
||||
use LotGD\Core\Tools\Model\Creator;
|
||||
use LotGD\Core\Tools\Model\Deletor;
|
||||
use LotGD\Core\Tools\Model\PropertyManager;
|
||||
use LotGD\Core\Tools\Model\Saveable;
|
||||
use LotGD\Core\Tools\Model\SceneBasics;
|
||||
use Ramsey\Uuid\Uuid;
|
||||
|
||||
use function array_merge;
|
||||
use function count;
|
||||
|
||||
/**
|
||||
* A scene is a location within the game, such as the Village or the Tavern. Designed
|
||||
* to be a kind of "template" for generating the specific location information for
|
||||
@@ -27,7 +36,7 @@ use Ramsey\Uuid\Uuid;
|
||||
*/
|
||||
class Scene implements CreateableInterface, SceneConnectable
|
||||
{
|
||||
use Creator;
|
||||
use Saveable;
|
||||
use Deletor;
|
||||
use SceneBasics;
|
||||
use PropertyManager;
|
||||
@@ -65,6 +74,20 @@ class Scene implements CreateableInterface, SceneConnectable
|
||||
*/
|
||||
private ?Collection $properties;
|
||||
|
||||
/**
|
||||
* @ManyToMany(targetEntity="SceneAttachment", inversedBy="scenes", cascade={"persist"})
|
||||
* @JoinTable(
|
||||
* name="scenes_x_scene_attachments",
|
||||
* joinColumns={
|
||||
* @JoinColumn(name="scene_id", referencedColumnName="id")
|
||||
* },
|
||||
* inverseJoinColumns={
|
||||
* @JoinColumn(name="attachment_id", referencedColumnName="class")
|
||||
* }
|
||||
* )
|
||||
*/
|
||||
private ?Collection $attachments;
|
||||
|
||||
// required for PropertyManager to now which class the properties belong to.
|
||||
private string $propertyClass = SceneProperty::class;
|
||||
|
||||
@@ -80,15 +103,45 @@ class Scene implements CreateableInterface, SceneConnectable
|
||||
private ?Collection $connectedScenes = null;
|
||||
|
||||
/**
|
||||
* Constructor for a scene.
|
||||
* Creates and returns an entity instance and fills values.
|
||||
* @param array $arguments The values the instance should get
|
||||
* @return CreateableInterface The created Entity
|
||||
* @throws WrongTypeException|UnexpectedArrayKeyException
|
||||
* @throws AttributeMissingException
|
||||
*/
|
||||
public function __construct()
|
||||
#[Deprecated("Use constructor directly.")]
|
||||
public static function create(array $arguments): CreateableInterface
|
||||
{
|
||||
if (isset(self::$fillable) === false) {
|
||||
throw new AttributeMissingException('self::$fillable is not defined.');
|
||||
}
|
||||
|
||||
if (\is_array(self::$fillable) === false) {
|
||||
throw new WrongTypeException('self::$fillable needs to be an array.');
|
||||
}
|
||||
|
||||
$entity = new self($arguments["title"], $arguments["description"], $arguments["template"]);
|
||||
|
||||
return $entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for a scene.
|
||||
* @param string $title
|
||||
* @param string $description
|
||||
* @param SceneTemplate|null $template
|
||||
*/
|
||||
public function __construct(string $title, string $description, ?SceneTemplate $template = null)
|
||||
{
|
||||
$this->id = Uuid::uuid4()->toString();
|
||||
$this->setTitle($title);
|
||||
$this->setDescription($description);
|
||||
$this->setTemplate($template);
|
||||
|
||||
$this->connectionGroups = new ArrayCollection();
|
||||
$this->outgoingConnections = new ArrayCollection();
|
||||
$this->incomingConnections = new ArrayCollection();
|
||||
$this->attachments = new ArrayCollection();
|
||||
}
|
||||
|
||||
public function __toString(): string
|
||||
@@ -143,7 +196,7 @@ class Scene implements CreateableInterface, SceneConnectable
|
||||
*/
|
||||
public function hasConnectionGroup(string $name): bool
|
||||
{
|
||||
return \count($this->filterConnectionGroupCollectionByName($name)) === 1;
|
||||
return count($this->filterConnectionGroupCollectionByName($name)) === 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -259,6 +312,11 @@ class Scene implements CreateableInterface, SceneConnectable
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a connection to another scene if it exists. Returns null if it does not exist.
|
||||
* @param Scene $scene
|
||||
* @return SceneConnection|null
|
||||
*/
|
||||
public function getConnectionTo(self $scene): ?SceneConnection
|
||||
{
|
||||
foreach ($this->outgoingConnections as $outgoingConnection) {
|
||||
@@ -283,7 +341,7 @@ class Scene implements CreateableInterface, SceneConnectable
|
||||
public function getConnections(): Collection
|
||||
{
|
||||
return new ArrayCollection(
|
||||
\array_merge(
|
||||
array_merge(
|
||||
$this->outgoingConnections->toArray(),
|
||||
$this->incomingConnections->toArray()
|
||||
)
|
||||
@@ -363,4 +421,31 @@ class Scene implements CreateableInterface, SceneConnectable
|
||||
|
||||
return $connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function getAttachments(): Collection
|
||||
{
|
||||
return $this->attachments;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param SceneAttachment $sceneAttachment
|
||||
* @return bool
|
||||
*/
|
||||
public function hasAttachment(SceneAttachment $sceneAttachment): bool
|
||||
{
|
||||
return $this->attachments->contains($sceneAttachment);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param SceneAttachment $attachmentClass
|
||||
*/
|
||||
public function addAttachment(SceneAttachment $attachmentClass): void
|
||||
{
|
||||
if (!$this->hasAttachment($attachmentClass)) {
|
||||
$this->attachments->add($attachmentClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace LotGD\Core\Models;
|
||||
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\Mapping\Column;
|
||||
use Doctrine\ORM\Mapping\Entity;
|
||||
use Doctrine\ORM\Mapping\Id;
|
||||
use Doctrine\ORM\Mapping\ManyToMany;
|
||||
use Doctrine\ORM\Mapping\Table;
|
||||
use LotGD\Core\Attachment;
|
||||
use LotGD\Core\Exceptions\ArgumentException;
|
||||
|
||||
/**
|
||||
* A SceneAttachment is a registered Attachment class to keep track of
|
||||
* (a) generally all available attachments, and
|
||||
* (b) which scene contains which attachment.
|
||||
* @Entity
|
||||
* @Table(name="scene_attachments")
|
||||
*/
|
||||
class SceneAttachment
|
||||
{
|
||||
/**
|
||||
* @Id
|
||||
* @Column(type="string", length=36, unique=True, name="class", options={"fixed"=true})
|
||||
*/
|
||||
protected string $class;
|
||||
|
||||
/** @Column(type="string", length=255) */
|
||||
protected string $title;
|
||||
|
||||
/** @ManyToMany(targetEntity="Scene", mappedBy="attachments") */
|
||||
private ?Collection $scenes;
|
||||
|
||||
/**
|
||||
* SceneAttachment constructor.
|
||||
* @param string $class A class inheriting from Attachment.
|
||||
* @param string $title
|
||||
* @throws ArgumentException if $class does not implement Attachment
|
||||
*/
|
||||
public function __construct(string $class, string $title) {
|
||||
if (!is_subclass_of($class, Attachment::class)) {
|
||||
throw new ArgumentException("The class '{$class}' must inherit from " . Attachment::class);
|
||||
}
|
||||
|
||||
$this->class = $class;
|
||||
$this->title = $title;
|
||||
|
||||
$this->scenes = new ArrayCollection();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getClass(): string
|
||||
{
|
||||
return $this->class;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getTitle(): string
|
||||
{
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function getScenes(): Collection
|
||||
{
|
||||
return $this->scenes;
|
||||
}
|
||||
}
|
||||
@@ -18,9 +18,9 @@ trait Creator
|
||||
/**
|
||||
* Creates and returns an entity instance and fills values.
|
||||
* @param array $arguments The values the instance should get
|
||||
* @throws AttributeMissingException
|
||||
* @throws WrongTypeException
|
||||
* @return CreateableInterface The created Entity
|
||||
* @throws WrongTypeException|UnexpectedArrayKeyException
|
||||
* @throws AttributeMissingException
|
||||
*/
|
||||
public static function create(array $arguments): CreateableInterface
|
||||
{
|
||||
|
||||
@@ -17,7 +17,7 @@ trait SceneBasics
|
||||
private string $title = "{No scene set}";
|
||||
/** @Column(type="text") */
|
||||
private string $description = "{No scene set}";
|
||||
/** @Column(type="string", length=255) */
|
||||
|
||||
/**
|
||||
* @ManyToOne(targetEntity="SceneTemplate", fetch="EAGER")
|
||||
* @JoinColumn(name="template", referencedColumnName="class", nullable=true)
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace LotGD\Core\Tests\Models;
|
||||
|
||||
use LotGD\Core\Attachment;
|
||||
use LotGD\Core\Exceptions\ArgumentException;
|
||||
use LotGD\Core\Models\{Scene, SceneAttachment, SceneConnection, SceneConnectionGroup, SceneTemplate};
|
||||
use LotGD\Core\Tests\CoreModelTestCase;
|
||||
use LotGD\Core\Tests\SceneTemplates\NewSceneSceneTemplate;
|
||||
|
||||
class TestAttachment extends Attachment
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
class InvalidTestAttachment
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests for creating scenes and moving them around.
|
||||
*/
|
||||
class SceneAttachmentTest extends CoreModelTestCase
|
||||
{
|
||||
/** @var string default data set */
|
||||
protected $dataset = "scene";
|
||||
|
||||
public function testSceneAttachmentCreationWithValidParameters()
|
||||
{
|
||||
$sceneAttachment = new SceneAttachment(TestAttachment::class, "Test Attachment");
|
||||
|
||||
$this->assertInstanceOf(SceneAttachment::class, $sceneAttachment);
|
||||
}
|
||||
|
||||
public function testIfSceneAttachmentCreationFailsIfAttachmentIsNotSubclassOfAttachment()
|
||||
{
|
||||
$this->expectException(ArgumentException::class);
|
||||
|
||||
$sceneAttachment = new SceneAttachment(InvalidTestAttachment::class, "Invalid Test Attachment");
|
||||
}
|
||||
|
||||
public function testIfValidSceneAttachmentCanBePersistedAndGottenBackFromTheDatabase()
|
||||
{
|
||||
$em = $this->getEntityManager();
|
||||
$sceneAttachment = new SceneAttachment(TestAttachment::class, "Test Attachment");
|
||||
|
||||
// persist
|
||||
$em->persist($sceneAttachment);
|
||||
$em->flush();
|
||||
$em->clear();
|
||||
|
||||
// retrieve
|
||||
$retrievedSceneAttachment = $em->getRepository(SceneAttachment::class)->find(TestAttachment::class);
|
||||
|
||||
$this->assertInstanceOf(SceneAttachment::class, $retrievedSceneAttachment);
|
||||
|
||||
// Delete again
|
||||
$em->remove($retrievedSceneAttachment);
|
||||
$em->flush();
|
||||
}
|
||||
|
||||
public function testIfSceneGettersReturnGivenValuesProperly()
|
||||
{
|
||||
$sceneAttachment = new SceneAttachment(TestAttachment::class, "Test Attachment");
|
||||
|
||||
$this->assertSame($sceneAttachment->getClass(), TestAttachment::class);
|
||||
$this->assertSame($sceneAttachment->getTitle(), "Test Attachment");
|
||||
}
|
||||
|
||||
public function testIfPersistingASceneAlsoPersistsASceneAttachment()
|
||||
{
|
||||
$em = $this->getEntityManager();
|
||||
|
||||
$scene = new Scene("Test scene", "A test scene");
|
||||
$sceneAttachment = new SceneAttachment(TestAttachment::class, "Test Attachment");
|
||||
|
||||
$scene->addAttachment($sceneAttachment);
|
||||
$sceneId = $scene->getId();
|
||||
|
||||
// persist
|
||||
$em->persist($scene);
|
||||
$em->flush();
|
||||
$em->clear();
|
||||
|
||||
// retrieve
|
||||
$retrievedSceneAttachment = $em->getRepository(SceneAttachment::class)->find(TestAttachment::class);
|
||||
|
||||
// assert
|
||||
$this->assertInstanceOf(SceneAttachment::class, $retrievedSceneAttachment);
|
||||
$this->assertCount(1, $retrievedSceneAttachment->getScenes());
|
||||
|
||||
// remove scene
|
||||
$scene = $retrievedSceneAttachment->getScenes()[0];
|
||||
$em->remove($scene);
|
||||
$em->flush();
|
||||
$em->clear();
|
||||
|
||||
// retrieve
|
||||
$retrievedSceneAttachment = $em->getRepository(SceneAttachment::class)->find(TestAttachment::class);
|
||||
|
||||
// assert
|
||||
$this->assertInstanceOf(SceneAttachment::class, $retrievedSceneAttachment);
|
||||
$this->assertCount(0, $retrievedSceneAttachment->getScenes());
|
||||
|
||||
// remove attachment
|
||||
$em->remove($retrievedSceneAttachment);
|
||||
$em->flush();
|
||||
$em->clear();
|
||||
|
||||
// retrieve
|
||||
$retrievedSceneAttachment = $em->getRepository(SceneAttachment::class)->find(TestAttachment::class);
|
||||
|
||||
// assert
|
||||
$this->assertNull($retrievedSceneAttachment);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user