Adds MotD and Message model as well as tests
This commit adds the MotD model for storing and retrieving messages-of-the-day. It also adds a model for messages. Messages have an author as well as a thread they belong to, the thread can be read by a specific number of authors. FUrthermore, the message model supports system messages. This commit introduces a number of needed changes: - Character is now implementing the CharacterInterface - MissingCharacter and SystemCharacter are supporting "pseudo-characters" - trait MockCharacter implements non-implemented methods for MissingCharacter and SytemCharacter - Characters are now soft-deletable. Models wanting to load soft-deleted characters need to fetch them eagerly. Closes #17
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
<?php
|
||||
|
||||
$autoloader = require __DIR__ . "/../vendor/autoload.php";
|
||||
$autoloader = require __DIR__ . "/../vendor/autoload.php";
|
||||
|
||||
\date_default_timezone_set("UTC");
|
||||
|
||||
+2
-1
@@ -7,7 +7,8 @@
|
||||
},
|
||||
"require": {
|
||||
"monolog/monolog": "1.16.0",
|
||||
"doctrine/orm": "2.5.*"
|
||||
"doctrine/orm": "2.5.*",
|
||||
"gedmo/doctrine-extensions": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "*",
|
||||
|
||||
Generated
+142
-23
@@ -4,9 +4,49 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"hash": "575df4f449ff2da32ce6665491eb6c06",
|
||||
"content-hash": "da6478b97984cb6a40ba877b477bc774",
|
||||
"hash": "ba904a6508c475cbab9d6d85a557a4fb",
|
||||
"content-hash": "f13234acbc23ca06e0181146f8aef31f",
|
||||
"packages": [
|
||||
{
|
||||
"name": "behat/transliterator",
|
||||
"version": "v1.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Behat/Transliterator.git",
|
||||
"reference": "868e05be3a9f25ba6424c2dd4849567f50715003"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Behat/Transliterator/zipball/868e05be3a9f25ba6424c2dd4849567f50715003",
|
||||
"reference": "868e05be3a9f25ba6424c2dd4849567f50715003",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.1-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Behat\\Transliterator": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"Artistic-1.0"
|
||||
],
|
||||
"description": "String transliterator",
|
||||
"keywords": [
|
||||
"i18n",
|
||||
"slug",
|
||||
"transliterator"
|
||||
],
|
||||
"time": "2015-09-28 16:26:35"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/annotations",
|
||||
"version": "v1.2.7",
|
||||
@@ -606,6 +646,85 @@
|
||||
],
|
||||
"time": "2016-01-05 21:34:58"
|
||||
},
|
||||
{
|
||||
"name": "gedmo/doctrine-extensions",
|
||||
"version": "v2.4.13",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Atlantic18/DoctrineExtensions.git",
|
||||
"reference": "5f4b6c848f0d6834a434a62a09a0935d147082e1"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Atlantic18/DoctrineExtensions/zipball/5f4b6c848f0d6834a434a62a09a0935d147082e1",
|
||||
"reference": "5f4b6c848f0d6834a434a62a09a0935d147082e1",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"behat/transliterator": "~1.0",
|
||||
"doctrine/common": "~2.4",
|
||||
"php": ">=5.3.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/common": ">=2.5.0",
|
||||
"doctrine/mongodb-odm": ">=1.0.2",
|
||||
"doctrine/orm": ">=2.5.0",
|
||||
"phpunit/phpunit": "~4.4",
|
||||
"phpunit/phpunit-mock-objects": "~2.3",
|
||||
"symfony/yaml": "~2.6"
|
||||
},
|
||||
"suggest": {
|
||||
"doctrine/mongodb-odm": "to use the extensions with the MongoDB ODM",
|
||||
"doctrine/orm": "to use the extensions with the ORM"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.4.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Gedmo\\": "lib/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "David Buchmann",
|
||||
"email": "david@liip.ch"
|
||||
},
|
||||
{
|
||||
"name": "Gediminas Morkevicius",
|
||||
"email": "gediminas.morkevicius@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Gustavo Falco",
|
||||
"email": "comfortablynumb84@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Doctrine2 behavioral extensions",
|
||||
"homepage": "http://gediminasm.org/",
|
||||
"keywords": [
|
||||
"Blameable",
|
||||
"behaviors",
|
||||
"doctrine2",
|
||||
"extensions",
|
||||
"gedmo",
|
||||
"loggable",
|
||||
"nestedset",
|
||||
"sluggable",
|
||||
"sortable",
|
||||
"timestampable",
|
||||
"translatable",
|
||||
"tree",
|
||||
"uploadable"
|
||||
],
|
||||
"time": "2016-02-18 15:33:43"
|
||||
},
|
||||
{
|
||||
"name": "monolog/monolog",
|
||||
"version": "1.16.0",
|
||||
@@ -722,16 +841,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v3.0.4",
|
||||
"version": "v3.0.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/console.git",
|
||||
"reference": "6b1175135bc2a74c08a28d89761272de8beed8cd"
|
||||
"reference": "34a214710e0714b6efcf40ba3cd1e31373a97820"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/6b1175135bc2a74c08a28d89761272de8beed8cd",
|
||||
"reference": "6b1175135bc2a74c08a28d89761272de8beed8cd",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/34a214710e0714b6efcf40ba3cd1e31373a97820",
|
||||
"reference": "34a214710e0714b6efcf40ba3cd1e31373a97820",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -778,7 +897,7 @@
|
||||
],
|
||||
"description": "Symfony Console Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2016-03-16 17:00:50"
|
||||
"time": "2016-04-28 09:48:42"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-mbstring",
|
||||
@@ -843,16 +962,16 @@
|
||||
"packages-dev": [
|
||||
{
|
||||
"name": "myclabs/deep-copy",
|
||||
"version": "1.5.0",
|
||||
"version": "1.5.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/myclabs/DeepCopy.git",
|
||||
"reference": "e3abefcd7f106677fd352cd7c187d6c969aa9ddc"
|
||||
"reference": "a8773992b362b58498eed24bf85005f363c34771"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/e3abefcd7f106677fd352cd7c187d6c969aa9ddc",
|
||||
"reference": "e3abefcd7f106677fd352cd7c187d6c969aa9ddc",
|
||||
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/a8773992b362b58498eed24bf85005f363c34771",
|
||||
"reference": "a8773992b362b58498eed24bf85005f363c34771",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -881,7 +1000,7 @@
|
||||
"object",
|
||||
"object graph"
|
||||
],
|
||||
"time": "2015-11-07 22:20:37"
|
||||
"time": "2015-11-20 12:04:31"
|
||||
},
|
||||
{
|
||||
"name": "phpdocumentor/reflection-docblock",
|
||||
@@ -1367,16 +1486,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpunit/phpunit-mock-objects",
|
||||
"version": "3.1.2",
|
||||
"version": "3.1.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git",
|
||||
"reference": "7c34c9bdde4131b824086457a3145e27dba10ca1"
|
||||
"reference": "151c96874bff6fe61a25039df60e776613a61489"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/7c34c9bdde4131b824086457a3145e27dba10ca1",
|
||||
"reference": "7c34c9bdde4131b824086457a3145e27dba10ca1",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/151c96874bff6fe61a25039df60e776613a61489",
|
||||
"reference": "151c96874bff6fe61a25039df60e776613a61489",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1419,7 +1538,7 @@
|
||||
"mock",
|
||||
"xunit"
|
||||
],
|
||||
"time": "2016-03-24 05:58:25"
|
||||
"time": "2016-04-20 14:39:26"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/code-unit-reverse-lookup",
|
||||
@@ -1584,16 +1703,16 @@
|
||||
},
|
||||
{
|
||||
"name": "sebastian/environment",
|
||||
"version": "1.3.5",
|
||||
"version": "1.3.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/environment.git",
|
||||
"reference": "dc7a29032cf72b54f36dac15a1ca5b3a1b6029bf"
|
||||
"reference": "2292b116f43c272ff4328083096114f84ea46a56"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/dc7a29032cf72b54f36dac15a1ca5b3a1b6029bf",
|
||||
"reference": "dc7a29032cf72b54f36dac15a1ca5b3a1b6029bf",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/2292b116f43c272ff4328083096114f84ea46a56",
|
||||
"reference": "2292b116f43c272ff4328083096114f84ea46a56",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1630,7 +1749,7 @@
|
||||
"environment",
|
||||
"hhvm"
|
||||
],
|
||||
"time": "2016-02-26 18:40:46"
|
||||
"time": "2016-05-04 07:59:13"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/exporter",
|
||||
@@ -1935,7 +2054,7 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/yaml",
|
||||
"version": "v3.0.4",
|
||||
"version": "v3.0.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/yaml.git",
|
||||
|
||||
@@ -6,6 +6,7 @@ namespace LotGD\Core\Exceptions;
|
||||
/**
|
||||
* Exception if a specific, required argument is missing
|
||||
*/
|
||||
class ArgumentEmptyException extends CoreException {
|
||||
class ArgumentEmptyException extends ArgumentException
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace LotGD\Core\Exceptions;
|
||||
|
||||
/**
|
||||
* Exception if a specific, required argument is missing
|
||||
*/
|
||||
class ArgumentException extends CoreException
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace LotGD\Core\Exceptions;
|
||||
|
||||
/**
|
||||
* Exception if a specific combination of model values is invalid.
|
||||
*/
|
||||
class InvalidModelException extends CoreException
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace LotGD\Core\Exceptions;
|
||||
|
||||
/**
|
||||
* Exception if a specific, required argument is missing
|
||||
*/
|
||||
class IsNullException extends CoreException {
|
||||
|
||||
}
|
||||
+52
-11
@@ -4,28 +4,34 @@ declare(strict_types=1);
|
||||
namespace LotGD\Core\Models;
|
||||
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\Mapping\Entity;
|
||||
use Doctrine\ORM\Mapping\Table;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Gedmo\Mapping\Annotation as Gedmo;
|
||||
use Gedmo\SoftDeleteable\Traits\SoftDeleteableEntity;
|
||||
|
||||
use LotGD\Core\Tools\Model\Creator;
|
||||
use LotGD\Core\Tools\Model\Deletor;
|
||||
use LotGD\Core\Tools\Model\PropertyManager;
|
||||
use LotGD\Core\Tools\Model\SoftDeletable;
|
||||
use LotGD\Core\Models\Repositories\CharacterRepository;
|
||||
|
||||
/**
|
||||
* Description of Character
|
||||
* Model for a character
|
||||
*
|
||||
* @Entity
|
||||
* @Entity(repositoryClass="LotGD\Core\Models\Repositories\CharacterRepository")
|
||||
* @Table(name="characters")
|
||||
*/
|
||||
class Character
|
||||
class Character implements CharacterInterface, CreateableInterface
|
||||
{
|
||||
use Creator;
|
||||
use Deletor;
|
||||
use SoftDeletable;
|
||||
use PropertyManager;
|
||||
|
||||
/** @Id @Column(type="integer") @GeneratedValue */
|
||||
private $id;
|
||||
/** @Column(type="string", length=50, unique=true); */
|
||||
/** @Column(type="string", length=50); */
|
||||
private $name;
|
||||
/** @Column(type="text"); */
|
||||
private $displayName;
|
||||
@@ -36,7 +42,20 @@ class Character
|
||||
/** @OneToMany(targetEntity="CharacterProperty", mappedBy="owner", cascade={"persist"}) */
|
||||
private $properties;
|
||||
/** @OneToMany(targetEntity="CharacterViewpoint", mappedBy="owner", cascade={"persist"}) */
|
||||
private $characterScene;
|
||||
private $characterViewpoint;
|
||||
/**
|
||||
* @ManyToMany(targetEntity="MessageThread", inversedBy="participants", cascade={"persist"})
|
||||
* @JoinTable(
|
||||
* name="message_threads_x_characters",
|
||||
* joinColumns={
|
||||
* @JoinColumn(name="character_id", referencedColumnName="id")
|
||||
* },
|
||||
* inverseJoinColumns={
|
||||
* @JoinColumn(name="messagethread_id", referencedColumnName="id")
|
||||
* }
|
||||
* )
|
||||
*/
|
||||
private $messageThreads;
|
||||
|
||||
/** @var array */
|
||||
private static $fillable = [
|
||||
@@ -57,7 +76,8 @@ class Character
|
||||
public function __construct()
|
||||
{
|
||||
$this->properties = new ArrayCollection();
|
||||
$this->characterScene = new ArrayCollection();
|
||||
$this->characterViewpoint = new ArrayCollection();
|
||||
$this->messageThreads = new ArrayCollection();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -146,13 +166,34 @@ class Character
|
||||
* Returns the current character scene and creates one if it is non-existant
|
||||
* @return \LotGD\Core\Models\CharacterViewpoint
|
||||
*/
|
||||
public function getCharacterScene(): CharacterViewpoint
|
||||
public function getCharacterViewpoint(): CharacterViewpoint
|
||||
{
|
||||
if (count($this->characterScene) === 0) {
|
||||
if (count($this->characterViewpoint) === 0) {
|
||||
$characterScene = CharacterViewpoint::Create(["owner" => $this]);
|
||||
$this->characterScene->add($characterScene);
|
||||
$this->characterViewpoint->add($characterScene);
|
||||
}
|
||||
|
||||
return $this->characterScene->first();
|
||||
return $this->characterViewpoint->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of message threads this user has created.
|
||||
* @return Collection
|
||||
*/
|
||||
public function getMessageThreads(): Collection
|
||||
{
|
||||
return $this->messageThreads;
|
||||
}
|
||||
|
||||
public function sendMessageTo(Character $recipient)
|
||||
{
|
||||
// ToDo: implement later
|
||||
throw new \LotGD\Core\Exceptions\NotImplementedException;
|
||||
}
|
||||
|
||||
public function receiveMessageFrom(Character $author)
|
||||
{
|
||||
// ToDo: implement later
|
||||
throw new \LotGD\Core\Exceptions\NotImplementedException;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace LotGD\Core\Models;
|
||||
|
||||
# use LotGD\Core\Tools\Optional\Optional;
|
||||
|
||||
/**
|
||||
* Interface for the character model and all objects that mimick such a model.
|
||||
*/
|
||||
interface CharacterInterface
|
||||
{
|
||||
public function getId(): int;
|
||||
public function getName(): string;
|
||||
public function getDisplayName(): string;
|
||||
public function getHealth(): int;
|
||||
public function getMaxHealth(): int;
|
||||
public function getCharacterViewpoint(): CharacterViewpoint;
|
||||
public function getProperty(string $name, $default = null);
|
||||
}
|
||||
@@ -3,6 +3,9 @@ declare(strict_types=1);
|
||||
|
||||
namespace LotGD\Core\Models;
|
||||
|
||||
use Doctrine\ORM\Mapping\Entity;
|
||||
use Doctrine\ORM\Mapping\Table;
|
||||
|
||||
use LotGD\Core\Tools\Model\Properties;
|
||||
|
||||
/**
|
||||
@@ -10,7 +13,8 @@ use LotGD\Core\Tools\Model\Properties;
|
||||
* @Entity
|
||||
* @Table(name="character_properties")
|
||||
*/
|
||||
class CharacterProperty {
|
||||
class CharacterProperty
|
||||
{
|
||||
use Properties;
|
||||
|
||||
/** @Id @ManyToOne(targetEntity="Character") */
|
||||
|
||||
@@ -3,6 +3,9 @@ declare(strict_types=1);
|
||||
|
||||
namespace LotGD\Core\Models;
|
||||
|
||||
use Doctrine\ORM\Mapping\Entity;
|
||||
use Doctrine\ORM\Mapping\Table;
|
||||
|
||||
use LotGD\Core\Tools\Model\Creator;
|
||||
use LotGD\Core\Tools\Model\SceneBasics;
|
||||
|
||||
@@ -12,7 +15,7 @@ use LotGD\Core\Tools\Model\SceneBasics;
|
||||
* @Entity
|
||||
* @Table(name="character_viewpoints")
|
||||
*/
|
||||
class CharacterViewpoint
|
||||
class CharacterViewpoint implements CreateableInterface
|
||||
{
|
||||
use Creator;
|
||||
use SceneBasics;
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace LotGD\Core\Models;
|
||||
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
/**
|
||||
* Interface for createable models
|
||||
*/
|
||||
interface CreateableInterface extends SaveableInterface
|
||||
{
|
||||
public static function create(array $arguments): CreateableInterface;
|
||||
}
|
||||
@@ -48,4 +48,4 @@ class GameConfiguration
|
||||
{
|
||||
$this->setProperty($configurationName, $configurationValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ declare(strict_types=1);
|
||||
namespace LotGD\Core\Models;
|
||||
|
||||
use LotGD\Core\Tools\Model\Properties;
|
||||
use Doctrine\ORM\Mapping\Entity;
|
||||
use Doctrine\ORM\Mapping\Table;
|
||||
|
||||
/**
|
||||
* Properties for Characters
|
||||
|
||||
@@ -0,0 +1,196 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace LotGD\Core\Models;
|
||||
|
||||
use DateTime;
|
||||
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Mapping\Entity;
|
||||
use Doctrine\ORM\Mapping\Table;
|
||||
|
||||
use LotGD\Core\Exceptions\InvalidModelException;
|
||||
use LotGD\Core\Exceptions\ArgumentException;
|
||||
use LotGD\Core\Tools\Model\Deletor;
|
||||
use LotGD\Core\Tools\Model\Saveable;
|
||||
|
||||
/**
|
||||
* Model for messages
|
||||
* @Entity
|
||||
* @Table(name="messages")
|
||||
*/
|
||||
class Message
|
||||
{
|
||||
/** @Id @Column(type="integer") @GeneratedValue */
|
||||
private $id;
|
||||
/**
|
||||
* @ManyToOne(targetEntity="Character", fetch="EAGER")
|
||||
* @JoinColumn(name="author_id", referencedColumnName="id", nullable=true)
|
||||
*/
|
||||
private $author;
|
||||
/** @Column(type="text", nullable=false) */
|
||||
private $message;
|
||||
/** @ManyToOne(targetEntity="MessageThread", inversedBy="messages", fetch="EAGER") */
|
||||
private $thread;
|
||||
/** @Column(type="datetime", nullable=false) */
|
||||
private $createdAt;
|
||||
/** @Column(type="boolean", nullable=false) */
|
||||
private $systemMessage = false;
|
||||
|
||||
/**
|
||||
* Sends a message to a MessageThread
|
||||
* @param \LotGD\Core\Models\Character $from
|
||||
* @param string $message
|
||||
* @param \LotGD\Core\Models\MessageThread $thread
|
||||
* @param bool $systemMessage
|
||||
* @return \LotGD\Core\Models\Message
|
||||
*/
|
||||
public static function send(
|
||||
Character $from,
|
||||
string $message,
|
||||
MessageThread $thread,
|
||||
bool $systemMessage = false
|
||||
) {
|
||||
$thread->addMessage(new self($from, $message, $thread, $systemMessage));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a system message to a MessageThread
|
||||
* @param string $message
|
||||
* @param \LotGD\Core\Models\MessageThread $thread
|
||||
* @return \LotGD\Core\Models\Message
|
||||
*/
|
||||
public static function sendSystemMessage(
|
||||
string $message,
|
||||
MessageThread $thread
|
||||
) {
|
||||
$thread->addMessage(new self(SystemCharacter::getInstance(), $message, $thread, true));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs the message.
|
||||
*
|
||||
* This method has been made protected to prevent from accessing it directly. Use
|
||||
* the static methods self::send() and self::sendSystemMessage() instead.
|
||||
* @param \LotGD\Core\Models\Character $from
|
||||
* @param string $message
|
||||
* @param \LotGD\Core\Models\Thread $thread
|
||||
* @param bool $systemMessage
|
||||
* @throws ArgumentException
|
||||
*/
|
||||
protected function __construct(CharacterInterface $from, string $message, MessageThread $thread, bool $systemMessage)
|
||||
{
|
||||
if ($from instanceof Character) {
|
||||
if ($from->isDeleted() === true) {
|
||||
throw new ArgumentException("A message cannot get written by a deleted character.");
|
||||
}
|
||||
$this->author = $from;
|
||||
} elseif ($systemMessage === false) {
|
||||
// This should not happen since the constructor is not a public method
|
||||
throw new ArgumentException(
|
||||
sprintf(
|
||||
'If $from is not an instance of %s, $systemMessage must be true',
|
||||
Character::class
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$this->message = $message;
|
||||
$this->thread = $thread;
|
||||
$this->createdAt = new DateTime("now");
|
||||
$this->systemMessage = $systemMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the id
|
||||
* @return int
|
||||
*/
|
||||
public function getId(): int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the true character of the message
|
||||
* @return \LotGD\Core\Models\CharacterInterface
|
||||
*/
|
||||
public function getAuthor(): CharacterInterface
|
||||
{
|
||||
if (is_null($this->author)) {
|
||||
return SystemCharacter::getInstance();
|
||||
}
|
||||
else {
|
||||
return $this->author;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the apparant character of the message.
|
||||
*
|
||||
* If a character sends a system message, this method will return the SystemCharacter message
|
||||
* instead of the true author.
|
||||
* @return \LotGD\Core\Models\CharacterInterface
|
||||
*/
|
||||
public function getApparantAuthor(): CharacterInterface
|
||||
{
|
||||
if ($this->isSystemMessage()) {
|
||||
return SystemCharacter::getInstance();
|
||||
}
|
||||
else {
|
||||
return $this->getAuthor();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the message
|
||||
* @return string
|
||||
*/
|
||||
public function getMessage(): string
|
||||
{
|
||||
return $this->message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the thread this message belongs to
|
||||
* @return \LotGD\Core\Models\MessageThread
|
||||
*/
|
||||
public function getThread(): MessageThread
|
||||
{
|
||||
return $this->thread;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the thread this message belongs to, once.
|
||||
*
|
||||
* A message that belongs to a thread needs to stay there - there is no need for messages to
|
||||
* switch the thread and end up in a complete different discussion.
|
||||
* @param \LotGD\Core\Models\MessageThread $thread
|
||||
* @throws ParentAlreadySetException
|
||||
*/
|
||||
public function setThread(MessageThread $thread)
|
||||
{
|
||||
if (is_null($this->thread) === false) {
|
||||
throw new ParentAlreadySetException("A message's thread cannot be changed.");
|
||||
}
|
||||
|
||||
$this->thread = $thread;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the datetime this message was created at
|
||||
* @return DateTime
|
||||
*/
|
||||
public function getCreatedAt(): DateTime
|
||||
{
|
||||
return $this->createdAt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the message is a system message
|
||||
* @return bool
|
||||
*/
|
||||
public function isSystemMessage(): bool
|
||||
{
|
||||
return $this->systemMessage;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace LotGD\Core\Models;
|
||||
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Mapping\Entity;
|
||||
use Doctrine\ORM\Mapping\Table;
|
||||
|
||||
use LotGD\Core\Exceptions\CoreException;
|
||||
use LotGD\Core\Tools\Model\Saveable;
|
||||
|
||||
/**
|
||||
* A Thread of messages
|
||||
*
|
||||
* @Entity(repositoryClass="LotGD\Core\Models\Repositories\MessageThreadRepository")
|
||||
* @Table(name="message_threads")
|
||||
*/
|
||||
class MessageThread implements SaveableInterface
|
||||
{
|
||||
use Saveable;
|
||||
|
||||
/** @Id @Column(type="integer") @GeneratedValue */
|
||||
private $id;
|
||||
/** @Column(type="string", length=255, unique=true) */
|
||||
private $threadKey;
|
||||
/** @Column(type="boolean", options={"default"=false}) */
|
||||
private $readonly = false;
|
||||
/** @ManyToMany(targetEntity="Character", cascade={"persist"}, mappedBy="messageThreads") */
|
||||
private $participants;
|
||||
/** @OneToMany(targetEntity="Message", mappedBy="thread", cascade={"persist"}) */
|
||||
private $messages;
|
||||
|
||||
/**
|
||||
* Constructor. Sets the (unique) threadKey.
|
||||
* @param string $threadKey
|
||||
* @param type $participants
|
||||
* @param type $readonly
|
||||
*/
|
||||
public function __construct(string $threadKey, array $participants, $readonly = false)
|
||||
{
|
||||
$this->threadKey = $threadKey;
|
||||
$this->readonly = $readonly;
|
||||
|
||||
$this->participants = new ArrayCollection();
|
||||
$this->messages = new ArrayCollection();
|
||||
|
||||
foreach ($participants as $participant) {
|
||||
$this->participants->add($participant);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the primary id of this message
|
||||
* @return int
|
||||
*/
|
||||
public function getId(): int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of messages inside this thread
|
||||
* @return Collection
|
||||
*/
|
||||
public function getMessages(): Collection
|
||||
{
|
||||
return $this->messages;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param \LotGD\Core\Models\Message $message
|
||||
* @throws CoreException
|
||||
*/
|
||||
public function addMessage(Message $message)
|
||||
{
|
||||
if ($this->isReadonly() && $message->getApparantAuthor() instanceof SystemCharacter === false) {
|
||||
throw new CoreException("Cannot write a normal message to a readonly thread");
|
||||
}
|
||||
else {
|
||||
$this->messages->add($message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a collection of participants in this thread
|
||||
* @return Collection
|
||||
*/
|
||||
public function getParticipants(): Collection
|
||||
{
|
||||
return $this->participants;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the thread is "readonly"
|
||||
* @return bool
|
||||
*/
|
||||
public function isReadonly(): bool
|
||||
{
|
||||
return $this->readonly;
|
||||
}
|
||||
|
||||
/**
|
||||
* Persists the MessageThread and adds itself to the participants.
|
||||
* @param EntityManagerInterface $em
|
||||
*/
|
||||
public function save(EntityManagerInterface $em)
|
||||
{
|
||||
foreach ($this->participants as $participant) {
|
||||
$participantsMessageThreads = $participant->getMessageThreads();
|
||||
if ($participantsMessageThreads->contains($this) === false) {
|
||||
$participantsMessageThreads->add($this);
|
||||
}
|
||||
}
|
||||
|
||||
$em->persist($this);
|
||||
$em->flush();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace LotGD\Core\Models;
|
||||
|
||||
use LotGD\Core\Tools\Model\MockCharacter;
|
||||
|
||||
/**
|
||||
* Provides a basic implementation of CharacterInterface to return the most
|
||||
* important data a missing character might still need.
|
||||
*/
|
||||
class MissingCharacter implements CharacterInterface
|
||||
{
|
||||
use MockCharacter;
|
||||
|
||||
private $displayname;
|
||||
|
||||
/**
|
||||
* Sets the name of the missing character, defautls to "Nobody"
|
||||
* @param string $displayname
|
||||
*/
|
||||
public function __construct(string $displayname = "Nobody")
|
||||
{
|
||||
$this->displayname = $displayname;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name
|
||||
* @return string
|
||||
*/
|
||||
public function getDisplayName(): string
|
||||
{
|
||||
return $this->displayname;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->displayname;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace LotGD\Core\Models;
|
||||
|
||||
use Doctrine\ORM\Mapping\Entity;
|
||||
use Doctrine\ORM\Mapping\Table;
|
||||
|
||||
use LotGD\Core\Tools\Model\Creator;
|
||||
use LotGD\Core\Tools\Model\Deletor;
|
||||
|
||||
/**
|
||||
* Model for the message of the day
|
||||
*
|
||||
* @Entity
|
||||
* @Table(name="motd")
|
||||
*/
|
||||
class MotD implements CreateableInterface
|
||||
{
|
||||
use Creator;
|
||||
use Deletor;
|
||||
|
||||
/** @Id @Column(type="integer") @GeneratedValue */
|
||||
private $id;
|
||||
/**
|
||||
* @ManyToOne(targetEntity="Character", cascade={"persist"}, fetch="EAGER")
|
||||
* @JoinColumn(name="author_id", referencedColumnName="id", nullable=false)
|
||||
*/
|
||||
private $author;
|
||||
/** @Column(type="string", length=255, nullable=false) */
|
||||
private $title;
|
||||
/** @Column(type="text", nullable=false) */
|
||||
private $body;
|
||||
/** @Column(type="datetime", nullable=false) */
|
||||
private $creationTime;
|
||||
/** @Column(type="boolean", nullable=false) */
|
||||
private $systemMessage = false;
|
||||
|
||||
/** @var array */
|
||||
private static $fillable = [
|
||||
"author",
|
||||
"title",
|
||||
"body",
|
||||
"systemMessage",
|
||||
];
|
||||
|
||||
/**
|
||||
* Constructs an entity and sets default datetime to now.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->creationTime = new \DateTime("now");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the entities ID
|
||||
* @return int
|
||||
*/
|
||||
public function getId(): int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the character who wrote this motd
|
||||
*
|
||||
* Returns always the real author of the message, even if it is a
|
||||
* system message. Use $this->getSystemMessage() to check if it is a system
|
||||
* message or $this->getAppearentAuthor() to get the appearent author.
|
||||
* @return \LotGD\Core\Models\Character
|
||||
*/
|
||||
public function getAuthor(): CharacterInterface
|
||||
{
|
||||
return $this->author;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the appearent author of this message.
|
||||
* @return \LotGD\Core\Models\CharacterInterface
|
||||
*/
|
||||
public function getApparantAuthor(): CharacterInterface
|
||||
{
|
||||
if ($this->getSystemMessage() === true) {
|
||||
return SystemCharacter::getInstance();
|
||||
} else {
|
||||
return $this->getAuthor();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the author of this motd
|
||||
* @param \LotGD\Core\Models\Character $author
|
||||
*/
|
||||
public function setAuthor(Character $author)
|
||||
{
|
||||
$this->author = $author;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the title of the message
|
||||
* @return string
|
||||
*/
|
||||
public function getTitle(): string
|
||||
{
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the title of the message
|
||||
* @param string $title
|
||||
*/
|
||||
public function setTitle(string $title)
|
||||
{
|
||||
$this->title = $title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the body of the message
|
||||
* @return string
|
||||
*/
|
||||
public function getBody(): string
|
||||
{
|
||||
return $this->body;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the body of the message
|
||||
* @param string $body
|
||||
*/
|
||||
public function setBody(string $body)
|
||||
{
|
||||
$this->body = $body;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the creation time. Modification of this has no effect.
|
||||
* @return \DateTime
|
||||
*/
|
||||
public function getCreationTime(): \DateTime
|
||||
{
|
||||
return $this->creationTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the creation time. Needs to be set to a new datetime instance.
|
||||
* @param \DateTime $creationTime
|
||||
*/
|
||||
public function setCreationTime(\DateTime $creationTime)
|
||||
{
|
||||
$this->creationTime = $creationTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the motd is a system message
|
||||
* @return bool
|
||||
*/
|
||||
public function getSystemMessage(): bool
|
||||
{
|
||||
return $this->systemMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true of the message should be a system message
|
||||
* @param bool $isSystemMessage
|
||||
*/
|
||||
public function setSystemMessage(bool $isSystemMessage = true)
|
||||
{
|
||||
$this->systemMessage = $isSystemMessage;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace LotGD\Core\Models\Repositories;
|
||||
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
use Doctrine\ORM\NoResultException;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
|
||||
use LotGD\Core\Models\Character;
|
||||
|
||||
/**
|
||||
* Description of CharacterRepository
|
||||
*/
|
||||
class CharacterRepository extends EntityRepository
|
||||
{
|
||||
const SKIP_SOFTDELETED = 0;
|
||||
const INCLUDE_SOFTDELETED = 1;
|
||||
const ONLY_SOFTDELETED = 2;
|
||||
|
||||
protected function modifyQuery(QueryBuilder $queryBuilder, int $level)
|
||||
{
|
||||
switch ($level) {
|
||||
case self::SKIP_SOFTDELETED:
|
||||
$queryBuilder->andWhere(
|
||||
$queryBuilder->expr()->orX(
|
||||
$queryBuilder->expr()->isNull('c.deletedAt'),
|
||||
$queryBuilder->expr()->gt('c.deletedAt', 'CURRENT_TIMESTAMP()')
|
||||
)
|
||||
);
|
||||
break;
|
||||
|
||||
case self::ONLY_SOFTDELETED:
|
||||
$queryBuilder->andWhere(
|
||||
$queryBuilder->expr()->lte('c.deletedAt', 'CURRENT_TIMESTAMP()')
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public function find($id, int $level = self::SKIP_SOFTDELETED)
|
||||
{
|
||||
$queryBuilder = $this->getEntityManager()->createQueryBuilder();
|
||||
$queryBuilder->select("c")
|
||||
->from(Character::class, "c")
|
||||
->where($queryBuilder->expr()->eq("c.id", ":id"))
|
||||
->setParameter("id", $id);
|
||||
|
||||
$this->modifyQuery($queryBuilder, $level);
|
||||
|
||||
try {
|
||||
return $queryBuilder->getQuery()->getSingleResult();
|
||||
} catch (NoResultException $e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public function findAll(int $level = self::SKIP_SOFTDELETED)
|
||||
{
|
||||
$queryBuilder = $this->getEntityManager()->createQueryBuilder();
|
||||
$queryBuilder->select("c")
|
||||
->from(Character::class, "c");
|
||||
|
||||
$this->modifyQuery($queryBuilder, $level);
|
||||
|
||||
return $queryBuilder->getQuery()->getResult();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace LotGD\Core\Models\Repositories;
|
||||
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
use Doctrine\ORM\NoResultException;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
|
||||
use LotGD\Core\Models\MessageThread;
|
||||
|
||||
/**
|
||||
* Repository for MessageThreads
|
||||
*/
|
||||
class MessageThreadRepository extends EntityRepository
|
||||
{
|
||||
/**
|
||||
* Creates a thread key based on the participating characters and a schema.
|
||||
* @param array $listOfCharacters
|
||||
* @param string $messageSchema
|
||||
* @return string
|
||||
*/
|
||||
public static function createThreadKey(array $listOfCharacters, string $messageSchema): string
|
||||
{
|
||||
// ToDo: Replace array with CharacterCollection
|
||||
usort(
|
||||
$listOfCharacters,
|
||||
function($a, $b) {
|
||||
return $a->getId() <=> $b->getId();
|
||||
}
|
||||
);
|
||||
|
||||
$threadParticipants = "";
|
||||
foreach($listOfCharacters as $character) {
|
||||
$threadParticipants .= $character->getId() . ".";
|
||||
}
|
||||
|
||||
return $messageSchema . "://" . md5($threadParticipants);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a messageThread
|
||||
* @param array $listOfCharacters
|
||||
* @return MessageThread
|
||||
*/
|
||||
public function findOrCreateFor(array $listOfCharacters): MessageThread
|
||||
{
|
||||
$threadKey = self::createThreadKey($listOfCharacters, "messageThread");
|
||||
|
||||
try {
|
||||
$thread = $this->getEntityManager()->createQueryBuilder()
|
||||
->select("e")
|
||||
->from($this->getEntityName(), "e")
|
||||
->where("e.threadKey = :threadKey")
|
||||
->setParameter("threadKey", $threadKey)
|
||||
->getQuery()
|
||||
->getSingleResult();
|
||||
|
||||
return $thread;
|
||||
} catch (NoResultException $e) {
|
||||
$newMessageThread = new MessageThread($threadKey, $listOfCharacters, false);
|
||||
$newMessageThread->save($this->getEntityManager());
|
||||
|
||||
return $newMessageThread;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a systemMessage or returns a newly created, read-only thread.
|
||||
* @param array $listOfCharacters
|
||||
* @return MessageThread
|
||||
*/
|
||||
public function findOrCreateReadonlyFor(array $listOfCharacters): MessageThread
|
||||
{
|
||||
$threadKey = self::createThreadKey($listOfCharacters, "systemMessage");
|
||||
|
||||
try {
|
||||
$thread = $this->getEntityManager()->createQueryBuilder()
|
||||
->select("e")
|
||||
->from($this->getEntityName(), "e")
|
||||
->where("e.threadKey = :threadKey")
|
||||
->setParameter("threadKey", $threadKey)
|
||||
->getQuery()
|
||||
->getSingleResult();
|
||||
|
||||
return $thread;
|
||||
} catch (NoResultException $e) {
|
||||
$newMessageThread = new MessageThread($threadKey, $listOfCharacters, true);
|
||||
$newMessageThread->save($this->getEntityManager());
|
||||
|
||||
return $newMessageThread;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace LotGD\Core\Models;
|
||||
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
/**
|
||||
* Interface for createable models
|
||||
*/
|
||||
interface SaveableInterface
|
||||
{
|
||||
public static function _save(SaveableInterface $object, EntityManagerInterface $em);
|
||||
public function save(EntityManagerInterface $em);
|
||||
}
|
||||
@@ -5,6 +5,9 @@ namespace LotGD\Core\Models;
|
||||
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\Mapping\Entity;
|
||||
use Doctrine\ORM\Mapping\Table;
|
||||
use Doctrine\ORM\Mapping\Column;
|
||||
|
||||
use LotGD\Core\Exceptions\NoParentSetException;
|
||||
use LotGD\Core\Exceptions\WrongParentException;
|
||||
@@ -17,7 +20,7 @@ use LotGD\Core\Tools\Model\SceneBasics;
|
||||
* @Entity
|
||||
* @Table(name="scenes")
|
||||
*/
|
||||
class Scene
|
||||
class Scene implements CreateableInterface
|
||||
{
|
||||
use Creator;
|
||||
use Deletor;
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace LotGD\Core\Models;
|
||||
|
||||
use LotGD\Core\Tools\Model\MockCharacter;
|
||||
|
||||
/**
|
||||
* Provides a basic system character to provide system information.
|
||||
*
|
||||
* Whenever a message should be sent by the System instead of a standard character,
|
||||
* this class is returned by the entity containing the message instead of a standard
|
||||
* character instance.
|
||||
*/
|
||||
class SystemCharacter implements CharacterInterface
|
||||
{
|
||||
use MockCharacter;
|
||||
|
||||
static $instance = null;
|
||||
static $characterName = "System";
|
||||
|
||||
public static function getInstance()
|
||||
{
|
||||
self::$instance = self::$instance ?? new self();
|
||||
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
private function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
public function getDisplayName(): string
|
||||
{
|
||||
return self::$characterName;
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return self::$characterName;
|
||||
}
|
||||
}
|
||||
@@ -8,12 +8,15 @@ use Doctrine\ORM\EntityManagerInterface;
|
||||
use LotGD\Core\Exceptions\AttributeMissingException;
|
||||
use LotGD\Core\Exceptions\UnexpectedArrayKeyException;
|
||||
use LotGD\Core\Exceptions\WrongTypeException;
|
||||
use LotGD\Core\Models\CreateableInterface;
|
||||
|
||||
/**
|
||||
* Provides methods for creating new entities
|
||||
*/
|
||||
trait Creator
|
||||
{
|
||||
use Saveable;
|
||||
|
||||
/**
|
||||
* Creates and returns an entity instance and fills values
|
||||
* @param array $arguments The values the instance should get
|
||||
@@ -21,7 +24,7 @@ trait Creator
|
||||
* @throws AttributeMissingException
|
||||
* @throws WrongTypeException
|
||||
*/
|
||||
public static function create(array $arguments)
|
||||
public static function create(array $arguments): CreateableInterface
|
||||
{
|
||||
if (isset(self::$fillable) === false) {
|
||||
throw new AttributeMissingException('self::$fillable is not defined.');
|
||||
@@ -34,7 +37,7 @@ trait Creator
|
||||
$entity = new self();
|
||||
|
||||
foreach (self::$fillable as $field) {
|
||||
if (isset($arguments[$field])) {
|
||||
if (array_key_exists($field, $arguments)) {
|
||||
$methodname = "set".$field;
|
||||
$value = $arguments[$field];
|
||||
|
||||
@@ -49,14 +52,4 @@ trait Creator
|
||||
|
||||
return $entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the entity as permanent and saves it into the database.
|
||||
* @param EntityManagerInterface $em The Entity Manager
|
||||
*/
|
||||
public function save(EntityManagerInterface $em)
|
||||
{
|
||||
$em->persist($this);
|
||||
$em->flush();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace LotGD\Core\Tools\Model;
|
||||
|
||||
use LotGD\Core\Exceptions\IsNullException;
|
||||
use LotGD\Core\Models\CharacterViewpoint;
|
||||
|
||||
/**
|
||||
* Provides basic implementation to mock CharacterInterface.
|
||||
*/
|
||||
trait MockCharacter
|
||||
{
|
||||
public function __call($name, $arguments) {
|
||||
throw new IsNullException();
|
||||
}
|
||||
|
||||
public function getId(): int
|
||||
{
|
||||
throw new IsNullException();
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
throw new IsNullException();
|
||||
}
|
||||
|
||||
public function getDisplayName(): string
|
||||
{
|
||||
throw new IsNullException();
|
||||
}
|
||||
|
||||
public function getHealth(): int
|
||||
{
|
||||
throw new IsNullException();
|
||||
}
|
||||
|
||||
public function getMaxHealth(): int
|
||||
{
|
||||
throw new IsNullException();
|
||||
}
|
||||
|
||||
public function getCharacterViewpoint(): CharacterViewpoint
|
||||
{
|
||||
throw new IsNullException();
|
||||
}
|
||||
|
||||
public function getProperty(string $name, $default = null)
|
||||
{
|
||||
return $default;
|
||||
}
|
||||
}
|
||||
@@ -27,20 +27,18 @@ trait PropertyManager
|
||||
|
||||
if (isset($this->propertyStorage[$name])) {
|
||||
return $this->propertyStorage[$name]->getValue();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return $default;
|
||||
}
|
||||
}
|
||||
|
||||
public function setProperty(string $name, $value)
|
||||
public function setProperty(string $name, $value)
|
||||
{
|
||||
$this->loadProperties();
|
||||
|
||||
if (isset($this->propertyStorage[$name])) {
|
||||
$this->propertyStorage[$name]->setValue($value);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
$className = $this->properties->getTypeClass()->name;
|
||||
$property = new $className();
|
||||
if (method_exists($property, "setOwner")) {
|
||||
@@ -53,4 +51,4 @@ trait PropertyManager
|
||||
$this->properties->add($property);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace LotGD\Core\Tools\Model;
|
||||
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
use LotGD\Core\Models\SaveableInterface;
|
||||
|
||||
/**
|
||||
* Provides methods for persisting Saveable entities.
|
||||
*/
|
||||
trait Saveable
|
||||
{
|
||||
/**
|
||||
* Static, protected save function to call from trait-overwriting methods.
|
||||
* @param \LotGD\Core\Tools\Model\CreateableInterface $object
|
||||
* @param EntityManagerInterface $em
|
||||
*/
|
||||
public static function _save(SaveableInterface $object, EntityManagerInterface $em)
|
||||
{
|
||||
$em->persist($object);
|
||||
$em->flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the entity as permanent and saves it into the database.
|
||||
* @param EntityManagerInterface $em The Entity Manager
|
||||
*/
|
||||
public function save(EntityManagerInterface $em)
|
||||
{
|
||||
self::_save($this, $em);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace LotGD\Core\Tools\Model;
|
||||
|
||||
use DateTime;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
/**
|
||||
* Provides methods for deleting entities.
|
||||
*/
|
||||
trait SoftDeletable
|
||||
{
|
||||
/** @Column(type="datetime", nullable=true) */
|
||||
private $deletedAt;
|
||||
|
||||
/**
|
||||
* Deletes the entity
|
||||
* @param EntityManagerInterface $em
|
||||
*/
|
||||
public function delete(EntityManagerInterface $em)
|
||||
{
|
||||
$this->setDeletedAt(new DateTime("now"));
|
||||
$em->flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores an entity back
|
||||
* @param EntityManagerInterface $em
|
||||
*/
|
||||
public function restore(EntityManagerInterface $em)
|
||||
{
|
||||
$this->setDeletedAt(null);
|
||||
$em->flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets deletedAt to a specific date
|
||||
* @param DateTime $deletedAt
|
||||
*/
|
||||
public function setDeletedAt(DateTime $deletedAt = null)
|
||||
{
|
||||
$this->deletedAt = $deletedAt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns when the entry got deleted
|
||||
* @return DateTime
|
||||
*/
|
||||
public function getDeletedAt(): DateTime
|
||||
{
|
||||
return $this->deletedAt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this entity is soft deleted
|
||||
* @return bool
|
||||
*/
|
||||
public function isDeleted(): bool
|
||||
{
|
||||
return is_null($this->deletedAt) ? false : true;
|
||||
}
|
||||
}
|
||||
+37
-13
@@ -3,32 +3,43 @@ declare(strict_types=1);
|
||||
|
||||
namespace LotGD\Core\Tests;
|
||||
|
||||
use Doctrine\ORM\{
|
||||
EntityManager,
|
||||
EntityManagerInterface,
|
||||
Mapping\AnsiQuoteStrategy,
|
||||
Tools\Setup,
|
||||
Tools\SchemaTool
|
||||
};
|
||||
use Doctrine\ORM\EntityManager;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Mapping\AnsiQuoteStrategy;
|
||||
use Doctrine\ORM\Tools\Setup;
|
||||
use Doctrine\ORM\Tools\SchemaTool;
|
||||
|
||||
/**
|
||||
* Description of ModelTestCase
|
||||
*/
|
||||
abstract class ModelTestCase extends \PHPUnit_Extensions_Database_TestCase {
|
||||
abstract class ModelTestCase extends \PHPUnit_Extensions_Database_TestCase
|
||||
{
|
||||
/** @var \PDO */
|
||||
static private $pdo = null;
|
||||
/** @var EntityManager */
|
||||
static private $em = null;
|
||||
/** @var \PHPUnit_Extensions_Database_DB_DefaultDatabaseConnection */
|
||||
private $connection = null;
|
||||
|
||||
final public function getConnection() {
|
||||
if($this->connection === null) {
|
||||
if(self::$pdo === null) {
|
||||
/**
|
||||
* Returns a connection to test models
|
||||
* @return \PHPUnit_Extensions_Database_DB_DefaultDatabaseConnection
|
||||
*/
|
||||
final public function getConnection(): \PHPUnit_Extensions_Database_DB_DefaultDatabaseConnection
|
||||
{
|
||||
if ($this->connection === null) {
|
||||
if (self::$pdo === null) {
|
||||
self::$pdo = new \PDO($GLOBALS['DB_DSN'], $GLOBALS["DB_USER"], $GLOBALS["DB_PASSWORD"]);
|
||||
|
||||
// Read db annotations from model files
|
||||
$configuration = Setup::createAnnotationMetadataConfiguration(["src/Models"], true);
|
||||
$configuration->setQuoteStrategy(new AnsiQuoteStrategy());
|
||||
|
||||
$configuration->addFilter("soft-deleteable", 'Gedmo\SoftDeleteable\Filter\SoftDeleteableFilter');
|
||||
|
||||
self::$em = EntityManager::create(["pdo" => self::$pdo], $configuration);
|
||||
self::$em->getFilters()->enable("soft-deleteable");
|
||||
self::$em->getEventManager()->addEventSubscriber(new \Gedmo\SoftDeleteable\SoftDeleteableListener());
|
||||
|
||||
// Create Schema
|
||||
$metaData = self::$em->getMetadataFactory()->getAllMetadata();
|
||||
@@ -39,16 +50,29 @@ abstract class ModelTestCase extends \PHPUnit_Extensions_Database_TestCase {
|
||||
$this->conn = $this->createDefaultDBConnection(self::$pdo, $GLOBALS["DB_NAME"]);
|
||||
}
|
||||
|
||||
// It is important to clear the cache of the entity manager every time a new test runs!
|
||||
self::$em->clear();
|
||||
|
||||
return $this->conn;
|
||||
}
|
||||
|
||||
protected function getDataSet(): \PHPUnit_Extensions_Database_DataSet_YamlDataSet {
|
||||
/**
|
||||
* Returns a .yml dataset under this name
|
||||
* @return \PHPUnit_Extensions_Database_DataSet_YamlDataSet
|
||||
*/
|
||||
protected function getDataSet(): \PHPUnit_Extensions_Database_DataSet_YamlDataSet
|
||||
{
|
||||
return new \PHPUnit_Extensions_Database_DataSet_YamlDataSet(
|
||||
__DIR__."/datasets/".$this->dataset.".yml"
|
||||
);
|
||||
}
|
||||
|
||||
protected function getEntityManager(): EntityManagerInterface {
|
||||
/**
|
||||
* Returns the current entity manager
|
||||
* @return EntityManagerInterface
|
||||
*/
|
||||
protected function getEntityManager(): EntityManagerInterface
|
||||
{
|
||||
return self::$em;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,14 +6,46 @@ namespace LotGD\Core\Tests\Models;
|
||||
use LotGD\Core\Models\Character;
|
||||
use LotGD\Core\Models\CharacterProperty;
|
||||
use LotGD\Core\Tests\ModelTestCase;
|
||||
use LotGD\Core\Models\Repositories\CharacterRepository;
|
||||
|
||||
/**
|
||||
* Tests the management of Characters
|
||||
*/
|
||||
class CharacterModelTest extends ModelTestCase {
|
||||
class CharacterModelTest extends ModelTestCase
|
||||
{
|
||||
/** @var string default data set */
|
||||
protected $dataset = "character";
|
||||
|
||||
/**
|
||||
* Tests for soft deletion
|
||||
*/
|
||||
public function testSoftDeletion()
|
||||
{
|
||||
$chars = $this->getEntityManager()->getRepository(Character::class)->find(3);
|
||||
$this->assertSame(null, $chars);
|
||||
|
||||
$allChars = $this->getEntityManager()->getRepository(Character::class)->findAll();
|
||||
$this->assertSame(2, count($allChars));
|
||||
|
||||
$char = $this->getEntityManager()->getRepository(Character::class)->find(1);
|
||||
$char->delete($this->getEntityManager());
|
||||
$this->getEntityManager()->flush();
|
||||
$this->getEntityManager()->clear();
|
||||
|
||||
|
||||
$allChars = $this->getEntityManager()
|
||||
->getRepository(Character::class)
|
||||
->findAll();
|
||||
$this->assertSame(1, count($allChars));
|
||||
|
||||
$allChars = $this->getEntityManager()
|
||||
->getRepository(Character::class)
|
||||
->findAll(CharacterRepository::INCLUDE_SOFTDELETED);
|
||||
$this->assertSame(3, count($allChars));
|
||||
|
||||
$this->getEntityManager()->getFilters()->enable("soft-deleteable");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns data to create valid characters
|
||||
* @return array $futureId => $characterData
|
||||
@@ -62,6 +94,8 @@ class CharacterModelTest extends ModelTestCase {
|
||||
$characterEntity = Character::create($characterData);
|
||||
$characterEntity->save($em);
|
||||
|
||||
$em->flush();
|
||||
|
||||
$this->assertInternalType("int", $characterEntity->getId());
|
||||
|
||||
$em->flush();
|
||||
@@ -105,6 +139,8 @@ class CharacterModelTest extends ModelTestCase {
|
||||
$character = $em->getRepository(Character::class)->find(1);
|
||||
$character->delete($em);
|
||||
|
||||
$em->clear();
|
||||
|
||||
$rowsAfter = count($em->getRepository(Character::class)->findAll());
|
||||
|
||||
$this->assertEquals($rowsBefore - 1, $rowsAfter);
|
||||
|
||||
@@ -9,20 +9,21 @@ use LotGD\Core\Models\Scene;
|
||||
use LotGD\Core\Tests\ModelTestCase;
|
||||
|
||||
/**
|
||||
* Tests the management of CharacterScenes
|
||||
* Tests the management of CharacterViewpoints
|
||||
*/
|
||||
class CharacterViewpointTest extends ModelTestCase
|
||||
{
|
||||
/** @var string default data set */
|
||||
protected $dataset = "characterViewpoints";
|
||||
|
||||
public function testGetters() {
|
||||
public function testGetters()
|
||||
{
|
||||
$em = $this->getEntityManager();
|
||||
|
||||
// Test character with a characterScene
|
||||
$testCharacter = $em->getRepository(Character::class)->find(2);
|
||||
$this->assertSame(2, $testCharacter->getId());
|
||||
$characterScene = $testCharacter->getCharacterScene();
|
||||
$characterScene = $testCharacter->getCharacterViewpoint();
|
||||
|
||||
$this->assertInstanceOf(CharacterViewpoint::class, $characterScene);
|
||||
$this->assertSame("The Village", $characterScene->getTitle());
|
||||
@@ -31,7 +32,7 @@ class CharacterViewpointTest extends ModelTestCase
|
||||
// Test character without a characterScene
|
||||
$testCharacter = $em->getRepository(Character::class)->find(1);
|
||||
$this->assertSame(1, $testCharacter->getId());
|
||||
$characterScene = $testCharacter->getCharacterScene();
|
||||
$characterScene = $testCharacter->getCharacterViewpoint();
|
||||
|
||||
$this->assertInstanceOf(CharacterViewpoint::class, $characterScene);
|
||||
|
||||
@@ -39,7 +40,8 @@ class CharacterViewpointTest extends ModelTestCase
|
||||
}
|
||||
|
||||
// Tests if a scene can be changed correctly.
|
||||
public function testSceneChange() {
|
||||
public function testSceneChange()
|
||||
{
|
||||
$em = $this->getEntityManager();
|
||||
|
||||
$testCharacters = [
|
||||
@@ -52,14 +54,14 @@ class CharacterViewpointTest extends ModelTestCase
|
||||
$em->getRepository(Scene::class)->find(2),
|
||||
];
|
||||
|
||||
$this->assertSame("{No scene set}", $testCharacters[0]->getCharacterScene()->getTitle());
|
||||
$this->assertSame("The Village", $testCharacters[1]->getCharacterScene()->getTitle());
|
||||
$this->assertSame("{No scene set}", $testCharacters[0]->getCharacterViewpoint()->getTitle());
|
||||
$this->assertSame("The Village", $testCharacters[1]->getCharacterViewpoint()->getTitle());
|
||||
|
||||
$testCharacters[0]->getCharacterScene()->changeFromScene($testScenes[0]);
|
||||
$testCharacters[1]->getCharacterScene()->changeFromScene($testScenes[1]);
|
||||
$testCharacters[0]->getCharacterViewpoint()->changeFromScene($testScenes[0]);
|
||||
$testCharacters[1]->getCharacterViewpoint()->changeFromScene($testScenes[1]);
|
||||
|
||||
$this->assertSame("The Village", $testCharacters[0]->getCharacterScene()->getTitle());
|
||||
$this->assertSame("The Forest", $testCharacters[1]->getCharacterScene()->getTitle());
|
||||
$this->assertSame("The Village", $testCharacters[0]->getCharacterViewpoint()->getTitle());
|
||||
$this->assertSame("The Forest", $testCharacters[1]->getCharacterViewpoint()->getTitle());
|
||||
|
||||
$em->flush();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,171 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace LotGD\Core\Tests\Models;
|
||||
|
||||
use LotGD\Core\Models\Character;
|
||||
use LotGD\Core\Models\MessageThread;
|
||||
use LotGD\Core\Models\Message;
|
||||
use LotGD\Core\Models\Repositories\CharacterRepository;
|
||||
use LotGD\Core\Tests\ModelTestCase;
|
||||
|
||||
/**
|
||||
* Tests the management of Characters
|
||||
*/
|
||||
class MessageModelTest extends ModelTestCase
|
||||
{
|
||||
/** @var string default data set */
|
||||
protected $dataset = "messages";
|
||||
|
||||
public function testSendMessageToSingleCharacter()
|
||||
{
|
||||
$em = $this->getEntityManager();
|
||||
|
||||
$character1 = $em->getRepository(Character::class)->find(1);
|
||||
$character2 = $em->getRepository(Character::class)->find(4);
|
||||
|
||||
$thread1 = $em->getRepository(MessageThread::class)->findOrCreateFor([$character1, $character2]);
|
||||
$thread2 = $em->getRepository(MessageThread::class)->findOrCreateFor([$character2, $character1]);
|
||||
|
||||
$this->assertSame($thread1, $thread2);
|
||||
|
||||
Message::send($character1, "Hi, how are you?", $thread1);
|
||||
Message::send($character2, "I'm fine, and you?", $thread1);
|
||||
Message::send($character1, "Sorry, I need to leave~", $thread1);
|
||||
|
||||
$this->assertSame(3, count($thread1->getMessages()));
|
||||
|
||||
// Write changes to database and clear entity cache.
|
||||
$em->flush();
|
||||
$em->clear();
|
||||
|
||||
$character1 = $em->getRepository(Character::class)->find(1);
|
||||
$character2 = $em->getRepository(Character::class)->find(4);
|
||||
|
||||
$thread1 = $em->getRepository(MessageThread::class)->findOrCreateFor([$character1, $character2]);
|
||||
|
||||
// $thread1 should come from the database
|
||||
$this->assertInternalType("int", $thread1->getId());
|
||||
|
||||
$this->assertSame(3, count($thread1->getMessages()));
|
||||
$this->assertSame(2, count($character1->getMessageThreads()));
|
||||
$this->assertSame(1, count($character2->getMessageThreads()));
|
||||
$this->assertContains($thread1, $character1->getMessageThreads());
|
||||
$this->assertContains($thread1, $character2->getMessageThreads());
|
||||
}
|
||||
|
||||
public function testSendMessageToMultipleCharacters()
|
||||
{
|
||||
$em = $this->getEntityManager();
|
||||
|
||||
$character1 = $em->getRepository(Character::class)->find(1);
|
||||
$character2 = $em->getRepository(Character::class)->find(2);
|
||||
$character3 = $em->getRepository(Character::class)->find(3, CharacterRepository::INCLUDE_SOFTDELETED);
|
||||
$character4 = $em->getRepository(Character::class)->find(4);
|
||||
|
||||
$thread1 = $em->getRepository(MessageThread::class)->findOrCreateFor([$character1, $character2, $character3, $character4]);
|
||||
$thread2 = $em->getRepository(MessageThread::class)->findOrCreateFor([$character4, $character2, $character1, $character3]);
|
||||
$this->assertSame($thread1, $thread2);
|
||||
|
||||
Message::send($character1, "Multi-User-Message", $thread1);
|
||||
Message::send($character2, "Multi-User-Message", $thread1);
|
||||
try {
|
||||
$exception = false;
|
||||
Message::send($character3, "Multi-User-Message", $thread1);
|
||||
} catch(\LotGD\Core\Exceptions\ArgumentException $e) {
|
||||
$exception = true;
|
||||
}
|
||||
Message::send($character4, "Multi-User-Message", $thread1);
|
||||
|
||||
$this->assertTrue($exception);
|
||||
$this->assertSame(3, count($thread1->getMessages()));
|
||||
$this->assertSame(2, count($character1->getMessageThreads()));
|
||||
$this->assertSame(2, count($character2->getMessageThreads()));
|
||||
$this->assertSame(1, count($character3->getMessageThreads()));
|
||||
$this->assertSame(1, count($character4->getMessageThreads()));
|
||||
|
||||
$em->flush();
|
||||
|
||||
$character1 = $em->getRepository(Character::class)->find(1);
|
||||
$character2 = $em->getRepository(Character::class)->find(2);
|
||||
$character3 = $em->getRepository(Character::class)->find(3, CharacterRepository::INCLUDE_SOFTDELETED);
|
||||
$character4 = $em->getRepository(Character::class)->find(4);
|
||||
|
||||
$thread1 = $em->getRepository(MessageThread::class)->findOrCreateFor([$character1, $character2, $character3, $character4]);
|
||||
|
||||
// $thread1 should come from the database
|
||||
$this->assertInternalType("int", $thread1->getId());
|
||||
$this->assertSame(3, count($thread1->getMessages()));
|
||||
$this->assertSame(2, count($character1->getMessageThreads()));
|
||||
$this->assertSame(2, count($character2->getMessageThreads()));
|
||||
$this->assertSame(1, count($character3->getMessageThreads()));
|
||||
$this->assertSame(1, count($character4->getMessageThreads()));
|
||||
}
|
||||
|
||||
public function testSendSystemMessageToSingleCharacter()
|
||||
{
|
||||
$em = $this->getEntityManager();
|
||||
|
||||
$character1 = $em->getRepository(Character::class)->find(1);
|
||||
$character2 = $em->getRepository(Character::class)->find(2);
|
||||
|
||||
$thread1 = $em->getRepository(MessageThread::class)->findOrCreateReadonlyFor([$character1]);
|
||||
$thread2 = $em->getRepository(MessageThread::class)->findOrCreateReadonlyFor([$character2]);
|
||||
|
||||
$this->assertNotSame($thread1, $thread2);
|
||||
|
||||
Message::sendSystemMessage("This is a Systemmessage for Character 1.", $thread1);
|
||||
Message::sendSystemMessage("This is a Systemmessage for Character 2.", $thread2);
|
||||
|
||||
$em->flush();
|
||||
$em->clear();
|
||||
|
||||
$character1 = $em->getRepository(Character::class)->find(1);
|
||||
$character2 = $em->getRepository(Character::class)->find(2);
|
||||
|
||||
$thread1 = $em->getRepository(MessageThread::class)->findOrCreateReadonlyFor([$character1]);
|
||||
$thread2 = $em->getRepository(MessageThread::class)->findOrCreateReadonlyFor([$character2]);
|
||||
|
||||
$this->assertSame(1, count($thread1->getMessages()));
|
||||
$this->assertSame(1, count($thread2->getMessages()));
|
||||
|
||||
// Test the impossibility to answer to a system message thread, but another system message
|
||||
// needs to be able to get attached
|
||||
try {
|
||||
$exception = false;
|
||||
Message::send($character1, "A normal message", $thread1);
|
||||
} catch (\LotGD\Core\Exceptions\CoreException $ex) {
|
||||
$exception = true;
|
||||
}
|
||||
|
||||
Message::sendSystemMessage("A second system Message", $thread1);
|
||||
|
||||
$this->assertTrue($exception);
|
||||
$this->assertSame(2, count($thread1->getMessages()));
|
||||
}
|
||||
|
||||
public function testSendSystemMessageToMultipleCharacters()
|
||||
{
|
||||
$em = $this->getEntityManager();
|
||||
|
||||
$character1 = $em->getRepository(Character::class)->find(1);
|
||||
$character2 = $em->getRepository(Character::class)->find(2);
|
||||
|
||||
$thread1 = $em->getRepository(MessageThread::class)->findOrCreateReadonlyFor([$character1, $character2]);
|
||||
$thread2 = $em->getRepository(MessageThread::class)->findOrCreateFor([$character1, $character2]);
|
||||
|
||||
$this->assertNotSame($thread1, $thread2);
|
||||
|
||||
Message::sendSystemMessage("A system message to 2 recipients", $thread1);
|
||||
|
||||
$em->flush();
|
||||
$em->clear();
|
||||
|
||||
$character1 = $em->getRepository(Character::class)->find(1);
|
||||
$character2 = $em->getRepository(Character::class)->find(2);
|
||||
|
||||
$thread1 = $em->getRepository(MessageThread::class)->findOrCreateReadonlyFor([$character1, $character2]);
|
||||
|
||||
$this->assertSame(1, count($thread1->getMessages()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace LotGD\Core\Tests\Models;
|
||||
|
||||
use LotGD\Core\Models\Character;
|
||||
use LotGD\Core\Models\MotD;
|
||||
use LotGD\Core\Tests\ModelTestCase;
|
||||
|
||||
/**
|
||||
* Tests the management of Characters
|
||||
*/
|
||||
class MotDModelTest extends ModelTestCase
|
||||
{
|
||||
/** @var string default data set */
|
||||
protected $dataset = "motd";
|
||||
|
||||
public function testFetching()
|
||||
{
|
||||
$em = $this->getEntityManager();
|
||||
|
||||
$author = $em->getRepository(Character::class)->find(1);
|
||||
|
||||
// Test normal message
|
||||
$motd1 = $em->getRepository(MotD::class)->find(1);
|
||||
$this->assertSame("This is the title", $motd1->getTitle());
|
||||
$this->assertSame("This is the body of the message", $motd1->getBody());
|
||||
$this->assertSame($author, $motd1->getAuthor());
|
||||
$this->assertSame($author, $motd1->getApparantAuthor());
|
||||
$this->assertFalse($motd1->getSystemMessage());
|
||||
|
||||
// Test System message
|
||||
$motd2 = $em->getRepository(MotD::class)->find(2);
|
||||
$this->assertTrue($motd2->getSystemMessage());
|
||||
$this->assertNotSame($motd2->getAuthor(), $motd2->getApparantAuthor());
|
||||
$this->assertSame($author, $motd2->getAuthor());
|
||||
$this->assertNotSame("Deleted Character Name", $motd2->getAuthor()->getDisplayName());
|
||||
|
||||
// Test message with unknown author
|
||||
$motd3 = $em->getRepository(Motd::class)->find(3);
|
||||
$this->assertSame("Deleted Testcharacter", $motd3->getAuthor()->getDisplayName());
|
||||
}
|
||||
|
||||
public function testTimezone()
|
||||
{
|
||||
$em = $this->getEntityManager();
|
||||
|
||||
$time1 = $em->getRepository(MotD::class)->find(1)->getCreationTime();
|
||||
$time2 = new \DateTime("2016-05-03 14:19:12");
|
||||
$time3 = $time2->setTimezone(new \DateTimeZone("Europe/Zurich"));
|
||||
$time4 = new \DateTime("2016-05-03 14:19:12");
|
||||
$time4->setTimezone(new \DateTimeZone("America/Los_Angeles"));
|
||||
|
||||
$this->assertSame($time1->getTimestamp(), $time2->getTimestamp());
|
||||
$this->assertEquals($time1, $time2);
|
||||
$this->assertSame($time2, $time3);
|
||||
$this->assertEquals($time2->getTimezone(), $time3->getTimezone());
|
||||
$this->assertNotEquals($time1->getTimezone(), $time2->getTimezone());
|
||||
$this->assertSame($time1->getTimestamp(), $time3->getTimestamp());
|
||||
$this->assertNotEquals($time2->getTimezone(), $time4->getTimezone());
|
||||
}
|
||||
|
||||
public function dataCreateSaveAndRetrieve(): array
|
||||
{
|
||||
return [
|
||||
[[
|
||||
"author" => 1,
|
||||
"title" => "ABC_\"EFG",
|
||||
"body" => "Lorem îpsum etc pp",
|
||||
"systemMessage" => false,
|
||||
]],
|
||||
[[
|
||||
"author" => 1,
|
||||
"title" => "AnotherOne",
|
||||
"body" => "Test a Second One",
|
||||
"systemMessage" => true,
|
||||
]],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataCreateSaveAndRetrieve
|
||||
*/
|
||||
public function testCreateSaveAndRetrieve(array $motdCreationArguments)
|
||||
{
|
||||
$em = $this->getEntityManager();
|
||||
// Set Author to the correct author instance. Cannot be moved to the dataProvider.
|
||||
$motdCreationArguments["author"] = $em->getRepository(Character::class)->find($motdCreationArguments["author"]);
|
||||
|
||||
$motd = MotD::create($motdCreationArguments);
|
||||
$motd->save($em);
|
||||
|
||||
$id = $motd->getId();
|
||||
|
||||
$em->flush();
|
||||
$em->clear();
|
||||
|
||||
$checkMotd = $this->getEntityManager()->getRepository(MotD::class)->find($id);
|
||||
|
||||
$this->assertSame($motdCreationArguments["author"]->getName(), $checkMotd->getAuthor()->getName());
|
||||
$this->assertSame($motdCreationArguments["title"], $checkMotd->getTitle());
|
||||
$this->assertSame($motdCreationArguments["body"], $checkMotd->getBody());
|
||||
$this->assertEquals($motd->getCreationTime(), $checkMotd->getCreationTime());
|
||||
|
||||
if ($motdCreationArguments["systemMessage"] === true) {
|
||||
$this->assertNotSame($motdCreationArguments["author"]->getName(), $checkMotd->getApparantAuthor()->getName());
|
||||
} else {
|
||||
$this->assertSame($motdCreationArguments["author"]->getName(), $checkMotd->getApparantAuthor()->getName());
|
||||
}
|
||||
|
||||
$em->flush();
|
||||
}
|
||||
}
|
||||
@@ -105,7 +105,9 @@ class OneToManyCollectionTest extends ModelTestCase
|
||||
$this->assertSame(5, count($collection));
|
||||
|
||||
// Test OneToManyCollection::get, remove and contains
|
||||
$testElement1 = $this->getEntityManager()->getRepository(GameConfigurationElement::class)->findByPropertyName("gameVersion")[0];
|
||||
$testElement1 = $this->getEntityManager()
|
||||
->getRepository(GameConfigurationElement::class)
|
||||
->findByPropertyName("gameVersion")[0];
|
||||
$testElement2 = $collection->get(4);
|
||||
$this->assertSame("testConfig", $testElement2->getName());
|
||||
$collection->remove(4);
|
||||
|
||||
@@ -11,6 +11,13 @@ characters:
|
||||
displayName: "Testcharacter 2"
|
||||
health: 90
|
||||
maxhealth: 90
|
||||
-
|
||||
id: 3
|
||||
name: "Testcharacter 3"
|
||||
displayName: "Testcharacter 3 (deleted)"
|
||||
health: 90
|
||||
maxhealth: 90
|
||||
deletedAt: "2011-11-11 11:11:11"
|
||||
character_properties:
|
||||
-
|
||||
owner_id: 1
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
characters:
|
||||
-
|
||||
id: 1
|
||||
name: "Testcharacter 1"
|
||||
displayName: "Testcharacter 1"
|
||||
-
|
||||
id: 2
|
||||
name: "Testcharacter 2"
|
||||
displayName: "Testcharacter 2"
|
||||
-
|
||||
id: 3
|
||||
name: "Testcharacter 1"
|
||||
displayName: "Deleted Testcharacter"
|
||||
deletedAt: "2011-11-11 11:11:11"
|
||||
-
|
||||
id: 4
|
||||
name: "Testcharacter 3"
|
||||
displayName: "Testcharacter 3"
|
||||
message_threads:
|
||||
-
|
||||
id: 1
|
||||
threadKey: "messageThread://94ed406c5b7809bbdbf1e092cdbc2e4a"
|
||||
messages:
|
||||
-
|
||||
id: 1
|
||||
author_id: 1
|
||||
thread_id: 1
|
||||
message: "Hi!"
|
||||
createdAt: "2000-01-01 00:00:01"
|
||||
systemMessage: false
|
||||
message_threads_x_characters:
|
||||
-
|
||||
messagethread_id: 1
|
||||
character_id: 1
|
||||
-
|
||||
messagethread_id: 1
|
||||
character_id: 2
|
||||
@@ -0,0 +1,43 @@
|
||||
characters:
|
||||
-
|
||||
id: 1
|
||||
name: "Testcharacter 1"
|
||||
displayName: "Testcharacter 1"
|
||||
health: 0
|
||||
maxhealth: 100
|
||||
-
|
||||
id: 2
|
||||
name: "Testcharacter 2"
|
||||
displayName: "Testcharacter 2"
|
||||
health: 90
|
||||
maxhealth: 90
|
||||
-
|
||||
id: 3
|
||||
name: "Testcharacter 1"
|
||||
displayName: "Deleted Testcharacter"
|
||||
health: 200
|
||||
maxhealth: 200
|
||||
deletedAt: "2011-11-11 11:11:11"
|
||||
motd:
|
||||
-
|
||||
id: 1
|
||||
author_id: 1
|
||||
title: "This is the title"
|
||||
body: "This is the body of the message"
|
||||
creationTime: "2016-05-03 14:19:12"
|
||||
systemMessage: false
|
||||
-
|
||||
id: 2
|
||||
author_id: 1
|
||||
title: "This is a system message"
|
||||
body: "This is the body of the system message"
|
||||
creationTime: "2016-05-04 14:19:12"
|
||||
systemMessage: true
|
||||
-
|
||||
id: 3
|
||||
author_id: 3
|
||||
title: "This is an old message."
|
||||
body: "This is an old message."
|
||||
creationTime: "2002-12-09 15:13:59"
|
||||
systemMessage: false
|
||||
|
||||
Reference in New Issue
Block a user