Page MenuHomeDevCentral

No OneTemporary

diff --git a/workspaces/src/Engines/Apps/Application.php b/workspaces/src/Engines/Apps/Application.php
index 889e4de..a1c5e20 100644
--- a/workspaces/src/Engines/Apps/Application.php
+++ b/workspaces/src/Engines/Apps/Application.php
@@ -1,95 +1,94 @@
<?php
/**
* _, __, _, _ __, _ _, _, _
* / \ |_) (_ | | \ | /_\ |\ |
* \ / |_) , ) | |_/ | | | | \|
* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*
* Application class
*
* @package ObsidianWorkspaces
* @subpackage Apps
* @author Sébastien Santoro aka Dereckson <dereckson@espace-win.org>
* @license http://www.opensource.org/licenses/bsd-license.php BSD
* @filesource
*/
namespace Waystone\Workspaces\Engines\Apps;
+use Waystone\Workspaces\Engines\Collection\Collection;
use Waystone\Workspaces\Engines\Controller\Controller;
use Waystone\Workspaces\Engines\Errors\ErrorHandling;
use Waystone\Workspaces\Engines\Workspaces\WorkspaceConfiguration;
-use Collection;
-
use Exception;
/**
* Application class
*
* This class describes an application
*/
abstract class Application extends Controller {
/**
* @var string The application name
*/
public static $name;
/**
* @var ApplicationContext The current application context
*/
public $context;
/**
* @var Collection[] The collections, keys as collections roles and values as
* collections names.
*/
public $collections = [];
/**
* Initializes the controller resources
*/
public function initialize () {
$this->collections = $this->loadCollections();
try {
$this->onAfterInitialize();
} catch (Exception $ex) {
ErrorHandling::messageAndDie(GENERAL_ERROR, $ex->getMessage(), "Can't load application");
}
}
/**
* Loads the collection
*/
private function loadCollections () : array {
$loadedCollections = [];
$workspaceCollections =
$this->context->workspace->configuration->collections;
foreach (
$this->context->configuration->useCollections as $role => $name
) {
if (!array_key_exists($name, $workspaceCollections)) {
$name =
WorkspaceConfiguration::getCollectionNameWithPrefix($this->context->workspace,
$name);
if (!array_key_exists($name, $workspaceCollections)) {
throw new Exception("Collection not found: $name");
}
}
$loadedCollections[$role] =
Collection::load($name, $workspaceCollections[$name]);
}
return $loadedCollections;
}
protected function onAfterInitialize () : void {
}
}
diff --git a/workspaces/src/includes/collection/Collection.php b/workspaces/src/Engines/Collection/Collection.php
similarity index 93%
rename from workspaces/src/includes/collection/Collection.php
rename to workspaces/src/Engines/Collection/Collection.php
index 164a3af..dcffff1 100644
--- a/workspaces/src/includes/collection/Collection.php
+++ b/workspaces/src/Engines/Collection/Collection.php
@@ -1,142 +1,158 @@
<?php
/**
* _, __, _, _ __, _ _, _, _
* / \ |_) (_ | | \ | /_\ |\ |
* \ / |_) , ) | |_/ | | | | \|
* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*
* Collection class
*
* @package ObsidianWorkspaces
* @subpackage Collection
* @author Sébastien Santoro aka Dereckson <dereckson@espace-win.org>
* @license http://www.opensource.org/licenses/bsd-license.php BSD
* @filesource
*/
+namespace Waystone\Workspaces\Engines\Collection;
+
+use Exception;
+use Traversable;
+
/**
* Collection class
*
* This abstract class represents a collection of documents
*/
abstract class Collection {
+
///
/// Common properties
///
/**
* @var string The collection identifiant
*/
public $id;
/**
* @var string the name of the document collection class to use
*/
public $documentType = 'CollectionDocument';
///
/// Factory
///
/**
* Loads a new instance of the collection
*
* @param string $id The collection identifiant
- * @param string $documentType The type, inheriting from CollectionDocumt to use for ollection's documents
- * @return Collection The collection, of the type specified in the storage configuration
+ * @param string $documentType The type, inheriting from CollectionDocumt
+ * to use for ollection's documents
+ *
+ * @return Collection The collection, of the type specified in the storage
+ * configuration
*/
public static function load ($id, $documentType = null) {
global $Config;
if (!array_key_exists(('DocumentStorage'), $Config)) {
throw new Exception("Configuration required parameter missing: DocumentStorage");
}
if (!array_key_exists(('Type'), $Config['DocumentStorage'])) {
throw new Exception("Configuration required parameter missing in DocumentStorage array: Type");
}
$collectionClass = $Config['DocumentStorage']['Type'] . 'Collection';
if (!class_exists($collectionClass)) {
throw new Exception("Storage class not found: $collectionClass");
}
$instance = new $collectionClass($id);
if ($documentType !== null) {
$instance->documentType = $documentType;
}
+
return $instance;
}
///
/// CRUD features
///
/**
* Adds a document to the collection
*
* @param CollectionDocument $document The document to add
+ *
* @return boolean true if the operation succeeded; otherwise, false.
*/
public abstract function add (CollectionDocument &$document);
/**
* Deletes a document from the collection
*
* @param string $documentId The identifiant of the document to delete
+ *
* @return boolean true if the operation succeeded; otherwise, false.
*/
public abstract function delete ($documentId);
/**
* Determines if a document exists
*
* @param CollectionDocument $document The document to check
+ *
* @return boolean true if the document exists; otherwise, false.
*/
public abstract function exists (CollectionDocument $document);
/**
* Updates a document in the collection
*
* @param CollectionDocument $document The document to update
+ *
* @return boolean true if the operation succeeded; otherwise, false.
*/
public abstract function update (CollectionDocument &$document);
/**
* Gets a document from the collection
*
* @param string $documentId The identifiant of the document to get
* @param CollectionDocument $document The document
*/
public abstract function get ($documentId);
/**
* Gets a count of the documents in the collection
*
* @return int The number of documents
*/
public abstract function count ();
/**
* Gets all the documents from the collection
*
- * @return Traversable An iterator to the documents, each item an instance of CollectionDocument
+ * @return Traversable An iterator to the documents, each item an instance
+ * of CollectionDocument
*/
public abstract function getAll ();
/**
* Adds or updates a document in the collection
*
* @param CollectionDocument $document The document to set
+ *
* @return boolean true if the operation succeeded; otherwise, false.
*/
public function set (CollectionDocument &$document) {
if ($document->id !== null && $this->exists($document)) {
return $this->update($document);
} else {
return $this->add($document);
}
}
}
diff --git a/workspaces/src/includes/collection/CollectionDocument.php b/workspaces/src/Engines/Collection/CollectionDocument.php
similarity index 85%
rename from workspaces/src/includes/collection/CollectionDocument.php
rename to workspaces/src/Engines/Collection/CollectionDocument.php
index 9a448b1..7b348ad 100644
--- a/workspaces/src/includes/collection/CollectionDocument.php
+++ b/workspaces/src/Engines/Collection/CollectionDocument.php
@@ -1,59 +1,64 @@
<?php
/**
* _, __, _, _ __, _ _, _, _
* / \ |_) (_ | | \ | /_\ |\ |
* \ / |_) , ) | |_/ | | | | \|
* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*
* Collection document class
*
* @package ObsidianWorkspaces
* @subpackage Collection
* @author Sébastien Santoro aka Dereckson <dereckson@espace-win.org>
* @license http://www.opensource.org/licenses/bsd-license.php BSD
* @filesource
*/
+namespace Waystone\Workspaces\Engines\Collection;
+
use Waystone\Workspaces\Engines\Serialization\ObjectDeserializable;
+use JsonSerializable;
+
/**
* Collection document class
*
* This class represents a document, inside a collection.
*/
class CollectionDocument implements JsonSerializable, ObjectDeserializable {
+
/**
* @var string The document identifier
*/
public $id = '';
/**
* Specifies data which should be serialized to JSON
- *
- * @return moxed data which can be serialized by json_encode()
*/
- public function jsonSerialize () {
+ public function jsonSerialize () : static {
return $this;
}
/**
* Loads a CollectionDocument instance from a generic object.
*
* @param object $data The object to deserialize
- * @return object The deserialized instance
+ *
+ * @return self The deserialized instance
*/
- public static function loadFromObject ($data) {
+ public static function loadFromObject (object $data) : static {
$instance = new static;
foreach ($data as $key => $value) {
if ($key == '_id') {
//Kludge to let MongoCollection directly use this method
//without having to create an intermediary object or to
//browse each property twice, one to substitute _id, then here.
$instance->id = $value;
}
$instance->$key = $value;
}
+
return $instance;
}
}
diff --git a/workspaces/src/includes/collection/FilesCollection.php b/workspaces/src/Engines/Collection/FilesCollection.php
similarity index 92%
rename from workspaces/src/includes/collection/FilesCollection.php
rename to workspaces/src/Engines/Collection/FilesCollection.php
index 94196b1..ece7e8e 100644
--- a/workspaces/src/includes/collection/FilesCollection.php
+++ b/workspaces/src/Engines/Collection/FilesCollection.php
@@ -1,231 +1,255 @@
<?php
/**
* _, __, _, _ __, _ _, _, _
* / \ |_) (_ | | \ | /_\ |\ |
* \ / |_) , ) | |_/ | | | | \|
* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*
* Files Collection class
*
* @package ObsidianWorkspaces
* @subpackage Collection
* @author Sébastien Santoro aka Dereckson <dereckson@espace-win.org>
* @license http://www.opensource.org/licenses/bsd-license.php BSD
* @filesource
*/
+namespace Waystone\Workspaces\Engines\Collection;
+
+use Exception;
+use Generator;
+
/**
* Files Collection class
*
* This class represents a collection of documents, stored on the filesystem.
*/
class FilesCollection extends Collection {
+
///
/// Helper methods
///
/**
- * Gets the path to the folder where the specified collection documents are stored.
+ * Gets the path to the folder where the specified collection documents are
+ * stored.
*
* @param string $collectionId The collection identifiant
+ *
* @return string The path to the specified collection folder
*/
public static function getCollectionPath ($collectionId) {
global $Config;
- if (!array_key_exists('DocumentStorage', $Config) || !array_key_exists('Path', $Config['DocumentStorage'])) {
+ if (!array_key_exists('DocumentStorage', $Config)
+ || !array_key_exists('Path', $Config['DocumentStorage'])) {
throw new Exception("Configuration parameter missing: \$Config['DocumentStorage']['Path']. Expected value for this parameter is the path to the collections folders.");
}
- $path = $Config['DocumentStorage']['Path'] . DIRECTORY_SEPARATOR . $collectionId;
+ $path = $Config['DocumentStorage']['Path'] . DIRECTORY_SEPARATOR
+ . $collectionId;
//Ensure directory exists. If not, creates it or throws an exception
if (!file_exists($path) && !mkdir($path, 0700, true)) {
throw new Exception("Directory doesn't exist and couldn't be created: $path");
}
return $path;
}
/**
* Gets the path to the file where the specified document is stored.
*
* @param string $documentId The document identifiant
+ *
* @return string The path to the specified document file
*/
public function getDocumentPath ($documentId) {
- return static::getCollectionPath($this->id) . DIRECTORY_SEPARATOR . $documentId . '.json';
+ return static::getCollectionPath($this->id) . DIRECTORY_SEPARATOR
+ . $documentId . '.json';
}
-
+
/**
* Gets the path to the folder where the current collection is stored.
*
* @return string The path to the specified collection folder
*/
public function getCurrentCollectionPath () {
return static::getCollectionPath($this->id);
}
///
/// Constructor
///
/**
* Initializes a new instance of MongoCollection
*
* @param string the database identifiant
*/
public function __construct ($id) {
$this->id = $id;
}
///
/// CRUD features
///
/**
* Adds a document to the collection
*
* @param CollectionDocument $document The document to add
+ *
* @return boolean true if the operation succeeded; otherwise, false.
*/
public function add (CollectionDocument &$document) {
if ($document->id === '') {
$document->id = uniqid();
}
$filename = $this->getDocumentPath($document->id);
if (file_exists($filename)) {
throw new Exception("A document with the same identifiant is already in the collection, stored at $filename");
}
$data = json_encode($document);
file_put_contents($filename, $data);
}
/**
* Deletes a document from the collection
*
* @param string $documentId The identifiant of the document to delete
+ *
* @return boolean true if the operation succeeded; otherwise, false.
*/
public function delete ($documentId) {
$filename = $this->getDocumentPath($documentId);
unlink($filename);
}
/**
* Determines if a document exists
*
* @param CollectionDocument $document The document to check
+ *
* @return boolean true if the document exists; otherwise, false.
*/
public function exists (CollectionDocument $document) {
$filename = $this->getDocumentPath($document->id);
+
return file_exists($filename);
}
/**
* Updates a document in the collection
*
* @param CollectionDocument $document The document to update
+ *
* @return boolean true if the operation succeeded; otherwise, false.
*/
public function update (CollectionDocument &$document) {
if ($document->id === '') {
$document->id = uniqid();
- user_error("An ID were expected for an update operation, but not provided. We'll use $document->id.", E_USER_WARNING);
+ user_error("An ID were expected for an update operation, but not provided. We'll use $document->id.",
+ E_USER_WARNING);
}
$filename = $this->getDocumentPath($document->id);
if (!file_exists($filename)) {
- user_error("File $filename doesn't exist. The update operation has became an insert one.", E_USER_WARNING);
+ user_error("File $filename doesn't exist. The update operation has became an insert one.",
+ E_USER_WARNING);
}
$data = json_encode($document);
file_put_contents($filename, $data);
}
/**
* Gets a document from the collection
*
* @param string $documentId The identifiant of the document to get
* @param CollectionDocument $document The document
*/
public function get ($documentId) {
$type = $this->documentType;
if (!class_exists($type)) {
throw new Exception("Can't create an instance of $type. If the class exists, did you register a SPL autoloader or updated includes/autoload.php?");
}
$filename = $this->getDocumentPath($documentId);
$data = json_decode(file_get_contents($filename));
+
return $type::loadFromObject($data);
}
/**
* Adds or updates a document in the collection
*
* @param CollectionDocument $document The document to set
+ *
* @return boolean true if the operation succeeded; otherwise, false.
*/
public function set (CollectionDocument &$document) {
if ($document->id === '') {
$document->id = uniqid();
}
$filename = $this->getDocumentPath($document->id);
$data = json_encode($document);
file_put_contents($filename, $data);
}
/**
* Gets a count of the documents in the collection
*
* @return int The number of documents
*/
public function count () {
$dir = $this->getCurrentCollectionPath();
$count = 0;
$files = scandir($dir);
foreach ($files as $file) {
if (get_extension($file) == 'json') {
$count++;
}
}
+
return $count;
}
/**
* Gets all the documents from the collection
*
- * @return Generator An iterator to the documents, each item an instance of CollectionDocument
+ * @return Generator An iterator to the documents, each item an instance of
+ * CollectionDocument
*/
public function getAll () {
$dir = $this->getCurrentCollectionPath();
$files = scandir($dir);
foreach ($files as $file) {
if (get_extension($file) == 'json') {
$documentId = get_filename($file);
yield $this->get($documentId);
}
}
}
/**
* Gets documents list
*
* @return array The documents list
*/
public function getDocumentsList () {
$dir = $this->getFilePath('');
$files = scandir($dir);
$documents = [];
foreach ($files as $file) {
if (get_extension($file) == 'json') {
$documents[] = get_filename($file);
}
}
+
return $documents;
}
}
diff --git a/workspaces/src/includes/collection/MongoDBCollection.php b/workspaces/src/Engines/Collection/MongoDBCollection.php
similarity index 82%
rename from workspaces/src/includes/collection/MongoDBCollection.php
rename to workspaces/src/Engines/Collection/MongoDBCollection.php
index 27e8a7d..72c47f3 100644
--- a/workspaces/src/includes/collection/MongoDBCollection.php
+++ b/workspaces/src/Engines/Collection/MongoDBCollection.php
@@ -1,263 +1,289 @@
<?php
/**
* _, __, _, _ __, _ _, _, _
* / \ |_) (_ | | \ | /_\ |\ |
* \ / |_) , ) | |_/ | | | | \|
* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*
* MongoDB Collection class
*
* @package ObsidianWorkspaces
* @subpackage Collection
* @author Sébastien Santoro aka Dereckson <dereckson@espace-win.org>
* @license http://www.opensource.org/licenses/bsd-license.php BSD
* @filesource
*/
-define('MONGO_DEFAULT_HOST', 'localhost');
-define('MONGO_DEFAULT_PORT', 27017);
+namespace Waystone\Workspaces\Engines\Collection;
+
+use Exception;
+use Iterator;
+use MongoClient;
+
+define('MONGO_DEFAULT_HOST', 'localhost');
+define('MONGO_DEFAULT_PORT', 27017);
define('MONGO_DEFAULT_DATABASE', 'obsidian');
/**
* MongoDB Collection class
*
* This class represents a collection of documents, stored on MongoDB.
*/
class MongoDBCollection extends Collection {
+
/**
* @var MongoCollection the Mongo collection
*/
public $mongoCollection;
///
/// Singleton pattern to get or initialize the MongoClient instance
///
/**
- * @var MongoClient The mongo client to the database the collection is hosted
+ * @var MongoClient The mongo client to the database the collection is
+ * hosted
*/
public static $mongoClient = null;
/**
- * Gets the existing MongoClient instance, or if not available, initializes one.
+ * Gets the existing MongoClient instance, or if not available, initializes
+ * one.
*
* @return MongoClient The MongoClient instance
*/
public static function getMongoClient () {
if (self::$mongoClient === null) {
self::$mongoClient = self::initializeMongoClient();
}
+
return self::$mongoClient;
}
///
/// Mongo objects initialization and helper methods
///
/**
* Gets the MongoDB connection string
*
* @return string The connection string
*/
private static function getConnectionString () {
global $Config;
//Protocol
- $connectionString = 'mongodb://';
+ $connectionString = 'mongodb://';
//Host
- if (isset($Config['DocumentStorage']) && array_key_exists('Host', $Config['DocumentStorage'])) {
+ if (isset($Config['DocumentStorage'])
+ && array_key_exists('Host', $Config['DocumentStorage'])) {
$connectionString .= $Config['DocumentStorage']['Host'];
} else {
$connectionString .= MONGO_DEFAULT_HOST;
}
//Port
$connectionString .= ':';
- if (isset($Config['DocumentStorage']) && array_key_exists('Port', $Config['DocumentStorage'])) {
+ if (isset($Config['DocumentStorage'])
+ && array_key_exists('Port', $Config['DocumentStorage'])) {
$connectionString .= $Config['DocumentStorage']['Port'];
} else {
$connectionString .= MONGO_DEFAULT_PORT;
}
return $connectionString;
}
/**
* Initializes a new MongoClient instance
*
* @return MongoClient the client
*/
public static function initializeMongoClient () {
global $Config;
- $connectionString = self::getConnectionString();
- if (isset($Config['DocumentStorage']) && array_key_exists('SSL', $Config['DocumentStorage']) && $Config['DocumentStorage']['SSL'] !== null) {
+ $connectionString = self::getConnectionString();
+ if (isset($Config['DocumentStorage'])
+ && array_key_exists('SSL', $Config['DocumentStorage'])
+ && $Config['DocumentStorage']['SSL'] !== null) {
$context = stream_context_create(
- [ 'ssl' => $Config['DocumentStorage']['SSL'] ]
+ ['ssl' => $Config['DocumentStorage']['SSL']],
);
$m = new MongoClient(
$connectionString,
- [ 'ssl' => true ],
- [ 'context' => $context ]
+ ['ssl' => true],
+ ['context' => $context],
);
} else {
$m = new MongoClient($connectionString);
}
return $m;
}
/**
* Gets the database to use for the current collection
*/
public static function getDatabase () {
global $Config;
- if (isset($Config['DocumentStorage']) && array_key_exists('Database', $Config['DocumentStorage'])) {
+ if (isset($Config['DocumentStorage'])
+ && array_key_exists('Database', $Config['DocumentStorage'])) {
return $Config['DocumentStorage']['Database'];
}
return MONGO_DEFAULT_DATABASE;
}
///
/// Constructor
///
/**
* Initializes a new instance of MongoCollection
*
* @param string $id the collection identifiant
*/
public function __construct ($id) {
$this->id = $id;
$m = self::getMongoClient();
$this->mongoCollection = $m->selectCollection(self::getDatabase(), $id);
}
///
/// Mongo BSON
///
/**
- * Gets an associative array with document collection properties as key and values.
+ * Gets an associative array with document collection properties as key and
+ * values.
*
* @param CollectionDocument $document The document
+ *
* @return array The array representation of the document
*/
public function getArrayFromDocument (CollectionDocument $document) {
foreach ($document as $key => $value) {
if ($key == 'id') {
if ($value !== '') {
$array['_id'] = $value;
}
} else {
$array[$key] = $value;
}
}
+
return $array;
}
///
/// CRUD features
///
/**
* Adds a document to the collection
*
* @param CollectionDocument $document The document to add
+ *
* @return boolean true if the operation succeeded; otherwise, false.
*/
public function add (CollectionDocument &$document) {
$object = static::getArrayFromDocument($document);
$this->mongoCollection->save($object);
$document->id = $object['_id'];
}
/**
* Deletes a document from the collection
*
* @param string $documentId The identifiant of the document to delete
+ *
* @return boolean true if the operation succeeded; otherwise, false.
*/
public function delete ($documentId) {
$this->mongoCollection->remove(
- [ '_id' => $documentId ]
+ ['_id' => $documentId],
);
}
/**
* Determines if a document exists
*
* @param CollectionDocument $document The document to check
+ *
* @return boolean true if the document exists; otherwise, false.
*/
public function exists (CollectionDocument $document) {
//According https://blog.serverdensity.com/checking-if-a-document-exists-mongodb-slow-findone-vs-find/
//this is more efficient to use find than findOne() to determine existence.
$cursor = $this->mongoCollection->find(
- [ '_id' => $document->id ]
+ ['_id' => $document->id],
)->limit(1);
+
return $cursor->hasNext();
}
/**
* Updates a document in the collection
*
* @param CollectionDocument $document The document to update
+ *
* @return boolean true if the operation succeeded; otherwise, false.
*/
public function update (CollectionDocument &$document) {
$object = static::getArrayFromDocument($document);;
$this->mongoCollection->update(
- [ '_id' => $document->id ],
- $object
+ ['_id' => $document->id],
+ $object,
);
}
/**
* Gets a document from the collection
*
* @param string $documentId The identifiant of the document to get
* @param CollectionDocument $document The document
*/
public function get ($documentId) {
$data = $this->mongoCollection->findOne(
- [ '_id' => $documentId ]
+ ['_id' => $documentId],
);
+
return $this->getDocumentFromArray($data);
}
/**
* Gets a document of the relevant collection documents type from an array.
*/
- public function getDocumentFromArray($documentArray) {
+ public function getDocumentFromArray ($documentArray) {
$type = $this->documentType;
if (!class_exists($type)) {
throw new Exception("Can't create an instance of $type. If the class exists, did you register a SPL autoloader or updated includes/autoload.php?");
}
+
return $type::loadFromObject($documentArray);
}
/**
* Gets a count of the documents in the collection
*
* @return int The number of documents
*/
public function count () {
return $this->mongoCollection->count();
}
/**
* Gets all the documents from the collection
*
- * @return Iterator An iterator to the documents, each item an instance of CollectionDocument
+ * @return Iterator An iterator to the documents, each item an instance of
+ * CollectionDocument
*/
public function getAll () {
return new MongoDBCollectionIterator($this);
}
}
diff --git a/workspaces/src/includes/collection/MongoDBCollectionIterator.php b/workspaces/src/Engines/Collection/MongoDBCollectionIterator.php
similarity index 87%
rename from workspaces/src/includes/collection/MongoDBCollectionIterator.php
rename to workspaces/src/Engines/Collection/MongoDBCollectionIterator.php
index e69434d..9ae1856 100644
--- a/workspaces/src/includes/collection/MongoDBCollectionIterator.php
+++ b/workspaces/src/Engines/Collection/MongoDBCollectionIterator.php
@@ -1,89 +1,99 @@
<?php
/**
* _, __, _, _ __, _ _, _, _
* / \ |_) (_ | | \ | /_\ |\ |
* \ / |_) , ) | |_/ | | | | \|
* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*
* MongoDB collection iterator class
*
* @package ObsidianWorkspaces
* @subpackage Collection
* @author Sébastien Santoro aka Dereckson <dereckson@espace-win.org>
* @license http://www.opensource.org/licenses/bsd-license.php BSD
* @filesource
*/
+namespace Waystone\Workspaces\Engines\Collection;
+
+use Iterator;
+use MongoCursor;
+
/**
* Iterator for MongoDBCollection::getAll()
*/
class MongoDBCollectionIterator implements Iterator {
+
/**
* @var MongoCursor The MongoDB cursor
*/
private $cursor;
/**
- * @var MongoDBCollection The collection attached to the current iterator instance
+ * @var MongoDBCollection The collection attached to the current iterator
+ * instance
*/
private $collection;
/**
* Initializes a new instance of the MongoDBCollectionIterator object
*
* @param MongoDBCollection $collection The collection to iterate
* @param ?MongoCursor $cursor The cursor to the results [optional]
*/
- public function __construct (MongoDBCollection $collection, ?MongoCursor $cursor = null) {
+ public function __construct (
+ MongoDBCollection $collection,
+ ?MongoCursor $cursor = null,
+ ) {
$this->collection = $collection;
if ($cursor === null) {
$this->cursor = $collection->mongoCollection->find();
} else {
$this->cursor = $cursor;
}
}
/**
* Returns a collection document from the current result
*
* @return CollectionDocument the current result's document
*/
public function current () {
return $this->collection->getDocumentFromArray(
- $this->cursor->current()
+ $this->cursor->current(),
);
}
/**
* Returns the key of the current element
*
* @return string the current result's _id
*/
public function key () {
return $this->cursor->key();
}
/**
* Moves forward to next element
*/
- public function next () {
+ public function next () {
$this->cursor->next();
}
/**
* Rewinds the iterator to the first element
*/
public function rewind () {
$this->cursor->rewind();
}
/**
* Checks if current position is valid
*
* @return boolean true if the current position is valid ; otherwise, false
*/
public function valid () {
return $this->cursor->valid();
}
}
diff --git a/workspaces/src/includes/collection/MySQLCollection.php b/workspaces/src/Engines/Collection/MySQLCollection.php
similarity index 83%
rename from workspaces/src/includes/collection/MySQLCollection.php
rename to workspaces/src/Engines/Collection/MySQLCollection.php
index 30fb724..fc87034 100644
--- a/workspaces/src/includes/collection/MySQLCollection.php
+++ b/workspaces/src/Engines/Collection/MySQLCollection.php
@@ -1,169 +1,192 @@
<?php
/**
* _, __, _, _ __, _ _, _, _
* / \ |_) (_ | | \ | /_\ |\ |
* \ / |_) , ) | |_/ | | | | \|
* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*
* MySQL Collection class
*
* @package ObsidianWorkspaces
* @subpackage Collection
* @author Sébastien Santoro aka Dereckson <dereckson@espace-win.org>
* @license http://www.opensource.org/licenses/bsd-license.php BSD
* @filesource
*/
+namespace Waystone\Workspaces\Engines\Collection;
+
use Waystone\Workspaces\Engines\Framework\Context;
+use Exception;
+use InvalidArgumentException;
+use Iterator;
+
/**
* MySQL Collection class
*
* This class represents a collection of documents, stored on MySQL.
*/
class MySQLCollection extends SQLCollection {
+
///
/// Singleton pattern to get the MySQLDatabase instance
///
/**
- * @var MySQLDatabase The mongo client to the database the collection is hosted
+ * @var MySQLDatabase The mongo client to the database the collection is
+ * hosted
*/
public static $client = null;
/**
- * Gets the existing MySQLDatabase instance, or if not available, initializes one.
+ * Gets the existing MySQLDatabase instance, or if not available,
+ * initializes one.
*
* @param Context $context
+ *
* @return MySQLDatabase The MySQLDatabase instance
*/
public static function getCurrentSiteDatabaseClient () {
if (self::$client === null) {
$client = Database::load();
if ($candidateClient instanceof MySQLDatabase) {
self::$client = $client;
} else {
throw new InvalidArgumentException("The MySQLDatabase driver is intended to be used when your main database product is MySQL. We recommend whether you pick the same engine for collections and other db use, whether you use a key/store storage solution for collections, like MongoDB.");
}
}
+
return self::$client;
}
///
/// Constructor
///
/**
* Initializes a new instance of MongoCollection
*
* @param string $id the collection identifiant
*/
- public function __construct ($id, ?MySQLDatabase $client = null, $table = '') {
+ public function __construct (
+ $id,
+ ?MySQLDatabase $client = null,
+ $table = '',
+ ) {
global $Config;
if ($client === null) {
self::getCurrentSiteDatabaseClient();
} else {
self::$client = $client;
}
if ($table == '') {
- if (!array_key_exists('DocumentStorage', $Config) || !array_key_exists('Table', $Config['DocumentStorage'])) {
+ if (!array_key_exists('DocumentStorage', $Config)
+ || !array_key_exists('Table', $Config['DocumentStorage'])) {
throw new Exception("Configuration parameter missing: \$Config['DocumentStorage']['Table']. Expected value for this parameter is the table to store the collections documents.");
}
$this->table = $Config['DocumentStorage']['Table'];
} else {
$this->table = $table;
}
$this->id = $id;
$this->initializeCollectionsTable();
}
///
/// Helper to create schema if required
///
/**
* Initializes collections table
*/
protected function initializeCollectionsTable () {
- if (defined('COLLECTIONS_MYSQL_DATABASE_READY') && COLLECTIONS_MYSQL_DATABASE_READY) {
+ if (defined('COLLECTIONS_MYSQL_DATABASE_READY')
+ && COLLECTIONS_MYSQL_DATABASE_READY) {
return;
}
self::$client->query("
CREATE TABLE if not exists $this->table (
collection_id VARCHAR(255),
document_id VARCHAR(255),
document_value BLOB,
PRIMARY KEY (collection_id, document_id)
- );"
+ );",
);
define('COLLECTIONS_MYSQL_DATABASE_READY', true);
}
///
/// SqlCollection implementation
///
/**
* Executes a SQL query
*
* @param string $sql The SQL query
- * @return mixed If the query doesn't return any result, null. If the query return a row with one field, the scalar value. Otherwise, an associative array, the fields as keys, the row as values.
+ *
+ * @return mixed If the query doesn't return any result, null. If the query
+ * return a row with one field, the scalar value. Otherwise, an
+ * associative array, the fields as keys, the row as values.
*/
public function query ($sql) {
if ($sql == "") {
return null;
}
$db = self::$client;
if (!$result = $db->query($sql, MYSQL_ASSOC)) {
throw new Exception("Can't execute collection query.");
}
if (!$row = $db->fetchRow($result)) {
return null;
}
if (count($row) == 1) {
return array_shift($row);
} else {
return $row;
}
}
/**
* Escapes the SQL string
*
* @param string $value The value to escape
+ *
* @return string The escaped value
*/
public function escape ($value) {
return self::$client->escape($value);
}
/**
* Gets all the documents from the collection
*
- * @return Iterator An iterator to the documents, each item an instance of CollectionDocument
+ * @return Iterator An iterator to the documents, each item an instance of
+ * CollectionDocument
*/
public function getAll () {
$db = self::$client;
$collectionId = $this->escape($this->id);
- $sql = "SELECT * FROM $this->table WHERE collection_id = '$collectionId'";
+ $sql =
+ "SELECT * FROM $this->table WHERE collection_id = '$collectionId'";
if (!$result = $db->query($sql, MYSQL_ASSOC)) {
throw new Exception("Can't get each collection documents.");
}
$type = $this->documentType;
while ($row = $db->fetchRow($result)) {
$data = json_decode($row['document_value']);
yield $type::loadFromObject($data);
}
}
}
diff --git a/workspaces/src/includes/collection/SQLCollection.php b/workspaces/src/Engines/Collection/SQLCollection.php
similarity index 76%
rename from workspaces/src/includes/collection/SQLCollection.php
rename to workspaces/src/Engines/Collection/SQLCollection.php
index 8494c5f..09d9b82 100644
--- a/workspaces/src/includes/collection/SQLCollection.php
+++ b/workspaces/src/Engines/Collection/SQLCollection.php
@@ -1,139 +1,160 @@
<?php
/**
* _, __, _, _ __, _ _, _, _
* / \ |_) (_ | | \ | /_\ |\ |
* \ / |_) , ) | |_/ | | | | \|
* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*
* SQL Collection abstract class
*
* @package ObsidianWorkspaces
* @subpackage Collection
* @author Sébastien Santoro aka Dereckson <dereckson@espace-win.org>
* @license http://www.opensource.org/licenses/bsd-license.php BSD
* @filesource
*/
+namespace Waystone\Workspaces\Engines\Collection;
+
+use Exception;
+
/**
- * Abstract class with SQL standard implementation of CRUD features for collections using a SQL database.
+ * Abstract class with SQL standard implementation of CRUD features for
+ * collections using a SQL database.
*/
abstract class SQLCollection extends Collection {
+
/**
* @var string The SQL collections table
*/
public $table;
/**
* Executes a SQL query
*
* @param string $sql The SQL query
- * @return mixed If the query doesn't return any null, nothing. If the query return a row with one field, the scalar value. Otherwise, an associative array, the fields as keys, the row as values.
+ *
+ * @return mixed If the query doesn't return any null, nothing. If the
+ * query return a row with one field, the scalar value. Otherwise, an
+ * associative array, the fields as keys, the row as values.
*/
public abstract function query ($sql);
/**
* Escapes the SQL string
*
* @param string $value The value to escape
+ *
* @return string The escaped value
*/
public abstract function escape ($value);
/**
* Adds a document to the collection
*
* @param CollectionDocument $document The document to add
+ *
* @return boolean true if the operation succeeded; otherwise, false.
*/
public function add (CollectionDocument &$document) {
if ($document->id === '') {
$document->id = uniqid();
}
$collectionId = $this->escape($this->id);
$documentId = $this->escape($document->id);
$value = $this->escape(json_encode($document));
$sql = "INSERT INTO $this->table "
- . "(collection_id, document_id, document_value) VALUES "
- . "('$collectionId', '$documentId', '$value')";
+ . "(collection_id, document_id, document_value) VALUES "
+ . "('$collectionId', '$documentId', '$value')";
$this->query($sql);
}
/**
* Deletes a document from the collection
*
* @param string $documentId The identifiant of the document to delete
+ *
* @return boolean true if the operation succeeded; otherwise, false.
*/
public function delete ($documentId) {
$collectionId = $this->escape($this->id);
$documentId = $this->escape($documentId);
- $sql = "DELETE FROM $this->table WHERE collection_id = '$collectionId' AND document_id = '$documentId'";
+ $sql =
+ "DELETE FROM $this->table WHERE collection_id = '$collectionId' AND document_id = '$documentId'";
$this->query($sql);
}
/**
* Determines if a document exists
*
* @param CollectionDocument $document The document to check
+ *
* @return boolean true if the document exists; otherwise, false.
*/
public function exists (CollectionDocument $document) {
$collectionId = $this->escape($this->id);
$documentId = $this->escape($document->id);
- $sql = "SELECT count(*) FROM $this->table WHERE collection_id = '$collectionId' AND document_id = '$documentId'";
+ $sql =
+ "SELECT count(*) FROM $this->table WHERE collection_id = '$collectionId' AND document_id = '$documentId'";
+
return $this->query($sql) == 1;
}
/**
* Updates a document in the collection
*
* @param CollectionDocument $document The document to update
+ *
* @return boolean true if the operation succeeded; otherwise, false.
*/
public function update (CollectionDocument &$document) {
$collectionId = $this->escape($this->id);
$documentId = $this->escape($document->id);
$value = $this->escape(json_encode($document));
- $sql = "UPDATE $this->table SET document_value = '$value' WHERE collection_id = '$collectionId' AND document_id = '$documentId'";
+ $sql =
+ "UPDATE $this->table SET document_value = '$value' WHERE collection_id = '$collectionId' AND document_id = '$documentId'";
$this->query($sql);
}
/**
* Gets a document from the collection
*
* @param string $documentId The identifiant of the document to get
* @param CollectionDocument $document The document
*/
- public function get ($documentId){
+ public function get ($documentId) {
$type = $this->documentType;
if (!class_exists($type)) {
throw new Exception("Can't create an instance of $type. If the class exists, did you registered a SPL autoloader or updated includes/autoload.php?");
}
$collectionId = $this->escape($this->id);
$documentId = $this->escape($documentId);
- $sql = "SELECT document_value FROM $this->table WHERE collection_id = '$collectionId' AND document_id = '$documentId'";
+ $sql =
+ "SELECT document_value FROM $this->table WHERE collection_id = '$collectionId' AND document_id = '$documentId'";
$data = $this->query($sql);
$data = json_decode($data);
return $type::loadFromObject($data);
}
/**
* Gets a count of the documents in the collection
*
* @return int The number of documents
*/
public function count () {
$collectionId = $this->escape($this->id);
- $sql = "SELECT count(*) FROM $this->table WHERE collection_id = '$collectionId'";
+ $sql =
+ "SELECT count(*) FROM $this->table WHERE collection_id = '$collectionId'";
+
return $this->query($sql);
}
}
diff --git a/workspaces/src/includes/collection/SQLiteCollection.php b/workspaces/src/Engines/Collection/SQLiteCollection.php
similarity index 85%
rename from workspaces/src/includes/collection/SQLiteCollection.php
rename to workspaces/src/Engines/Collection/SQLiteCollection.php
index 1545f99..3b1677e 100644
--- a/workspaces/src/includes/collection/SQLiteCollection.php
+++ b/workspaces/src/Engines/Collection/SQLiteCollection.php
@@ -1,184 +1,200 @@
<?php
/**
* _, __, _, _ __, _ _, _, _
* / \ |_) (_ | | \ | /_\ |\ |
* \ / |_) , ) | |_/ | | | | \|
* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*
* SQLite Collection class
*
* @package ObsidianWorkspaces
* @subpackage Collection
* @author Sébastien Santoro aka Dereckson <dereckson@espace-win.org>
* @license http://www.opensource.org/licenses/bsd-license.php BSD
* @filesource
*/
+namespace Waystone\Workspaces\Engines\Collection;
+
+use SQLite3;
+
/**
* SQLite Collection class
*
* This class represents a collection of documents, stored on MySQL.
*/
class SQLiteCollection extends SQLCollection {
///
/// Singleton pattern to get or initialize the SQLite instance
///
/**
* @var SQLite3 The SQLite client to the database the collection is hosted
*/
public static $client = null;
/**
* Gets the existing SQLite3 instance, or if not available, initializes one.
*
* @return SQLite3 The SQLite3 instance
*/
public static function getClient () {
if (self::$client === null) {
self::$client = self::initializeClient();
}
+
return self::$client;
}
/**
* Initializes a new SQLite3 instance
*
* @return SQLite3 the client
*/
public static function initializeClient () {
global $Config;
- if (!array_key_exists('DocumentStorage', $Config) || !array_key_exists('File', $Config['DocumentStorage'])) {
+ if (!array_key_exists('DocumentStorage', $Config)
+ || !array_key_exists('File', $Config['DocumentStorage'])) {
throw new Exception("Configuration parameter missing: \$Config['DocumentStorage']['File']. Expected value for this parameter is the path to the SQLite database file.");
}
return new SQLite3($Config['DocumentStorage']['File']);
}
///
/// Constructor
///
/**
* Initializes a new instance of MongoCollection
*
* @param string $id the collection identifiant
*/
public function __construct ($id) {
$this->table = 'collections';
$this->id = $id;
$this->initializeCollectionsTable();
}
///
/// Helper to create SQLite3 schema if required
///
/**
* Initializes collections table
*/
protected function initializeCollectionsTable () {
- if (defined('COLLECTIONS_SQLITE_DATABASE_READY') && COLLECTIONS_SQLITE_DATABASE_READY) {
+ if (defined('COLLECTIONS_SQLITE_DATABASE_READY')
+ && COLLECTIONS_SQLITE_DATABASE_READY) {
return;
}
$client = static::getClient();
$client->exec("
CREATE TABLE if not exists $this->table (
collection_id TEXT,
document_id TEXT,
document_value BLOB,
PRIMARY KEY (collection_id, document_id)
- );"
+ );",
);
define('COLLECTIONS_SQLITE_DATABASE_READY', true);
}
///
/// SqlCollection implementation
///
/**
* Determines if the SQL query is a statement
*
* @return boolean true is a SELECT one; otherwise, false.
- * @todo To use this outside the Collection scope, adds the other cases where a query is indicated.
+ * @todo To use this outside the Collection scope, adds the other cases
+ * where a query is indicated.
*/
public static function isStatement ($sql) {
$instruction = strtoupper(strstr($sql, ' ', true));
+
return $instruction != "SELECT" && $instruction != "PRAGMA";
}
/**
* Executes a SQL query
*
* @param string $sql The SQL query
- * @return mixed If the query doesn't return any result, null. If the query return a row with one field, the scalar value. Otherwise, an associative array, the fields as keys, the row as values.
+ *
+ * @return mixed If the query doesn't return any result, null. If the query
+ * return a row with one field, the scalar value. Otherwise, an
+ * associative array, the fields as keys, the row as values.
*/
public function query ($sql) {
$client = static::getClient();
if (static::isStatement($sql)) {
if (!$client->exec($sql)) {
throw new Exception(
"Can't execute collection query. "
- . $client->lastErrorMsg()
+ . $client->lastErrorMsg(),
);
}
+
return null;
}
$result = $client->query($sql);
if ($result === true) {
return null;
}
if ($result === false) {
throw new Exception(
"Can't execute collection query. "
- . $client->lastErrorMsg()
+ . $client->lastErrorMsg(),
);
}
$row = $result->fetchArray(SQLITE3_ASSOC);
$scalar = ($result->numColumns() == 1);
$result->finalize();
if ($scalar) {
return array_shift($row);
} else {
return $row;
}
}
/**
* Escapes the SQL string
*
* @param string $value The value to escape
+ *
* @return string The escaped value
*/
public function escape ($value) {
return SQLite3::escapeString($value);
}
/**
* Gets all the documents from the collection
*
- * @return Iterator An iterator to the documents, each item an instance of CollectionDocument
+ * @return Iterator An iterator to the documents, each item an instance of
+ * CollectionDocument
*/
public function getAll () {
$collectionId = $this->escape($this->id);
- $sql = "SELECT document_value FROM $this->table WHERE collection_id = '$collectionId'";
+ $sql =
+ "SELECT document_value FROM $this->table WHERE collection_id = '$collectionId'";
$client = static::getClient();
$type = $this->documentType;
$result = $client->query($sql);
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
$data = json_decode($row['document_value']);
yield $type::loadFromObject($data);
}
}
}
diff --git a/workspaces/tests/Engines/Collection/BookDocument.php b/workspaces/tests/Engines/Collection/BookDocument.php
index 5b03b20..d91ea41 100644
--- a/workspaces/tests/Engines/Collection/BookDocument.php
+++ b/workspaces/tests/Engines/Collection/BookDocument.php
@@ -1,30 +1,30 @@
<?php
namespace Waystone\Workspaces\Tests\Engines\Collection;
-use CollectionDocument;
+use Waystone\Workspaces\Engines\Collection\CollectionDocument;
require_once(__DIR__ . '/../../../src/includes/autoload.php');
/**
* A CollectionDocument class, for our tests.
*/
class BookDocument extends CollectionDocument {
/**
* @var string The book title
*/
public $title;
/**
* @var string The book author
*/
public $author;
/**
* Initializes a new instance of the BookDocument object
*/
public function __construct ($author = null, $title = null) {
if ($title !== null) $this->title = $title;
if ($author !== null) $this->author = $author;
}
}
diff --git a/workspaces/tests/Engines/Collection/CRUDTestTrait.php b/workspaces/tests/Engines/Collection/CRUDTestTrait.php
index 10efea4..8ab6760 100644
--- a/workspaces/tests/Engines/Collection/CRUDTestTrait.php
+++ b/workspaces/tests/Engines/Collection/CRUDTestTrait.php
@@ -1,215 +1,215 @@
<?php
/**
* _, __, _, _ __, _ _, _, _
* / \ |_) (_ | | \ | /_\ |\ |
* \ / |_) , ) | |_/ | | | | \|
* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*
* CRUD features tests for each Collection class.
*
* @package ObsidianWorkspaces
* @subpackage Tests
* @author Sébastien Santoro aka Dereckson <dereckson@espace-win.org>
* @license http://www.opensource.org/licenses/bsd-license.php BSD
* @filesource
*/
namespace Waystone\Workspaces\Tests\Engines\Collection;
-use CollectionDocument;
+use Waystone\Workspaces\Engines\Collection\CollectionDocument;
/**
* The tests for our basic, non storage engine specific CRUD features
*
* For coverage purposes, it requires a coversDefaultClass annotation in the classes using this trait.
*/
trait CRUDTestTrait {
/**
* @var BookDocument The document to test every CRUD feature
*/
protected $redBook;
/**
* @var BookDocument A second document to test Set in two scenarii
*/
protected $blueBook;
/**
* Initializes two documents for the tests
*/
public function initializeDocuments() {
$this->blueBook = new BookDocument('Isaac Asimov', 'Foundation');
$this->redBook = new BookDocument('Iain Banks', 'Matter'); //M. will be added in update test
$this->redBook->id = 'redBook';
}
/**
* Tests if the constructor correctly initializes the id property
*
* @covers ::_construct()
*/
public function testId () {
$this->assertEquals('quux', $this->collection->id, "The collection constructor should have initialized the Collection::id property.");
}
/**
* Tests CRUD methods
*
* @covers ::add
* @covers ::exists
* @covers ::update
* @covers ::get
* @covers ::set
* @covers ::delete
* @covers ::count
* @covers ::getAll
*/
public function testCRUD () {
global $Config;
$Config = static::getConfig();
//::count
$this->assertEquals(
0, $this->collection->count(),
"The test collection isn't empty. Check the last test run cleaned correctly the resources."
);
//::add
$this->collection->add($this->redBook);
$this->assertNotEmpty(
$this->redBook->id,
"After a document has been added, the id has been deleted."
);
$this->assertEquals(
'redBook',
$this->redBook->id,
"After a document has been added, the id has been modified."
);
//:ccount
$this->assertEquals(1, $this->collection->count());
//::exists
$this->assertFalse(
$this->collection->exists($this->blueBook),
"A non added document has been marked existing."
);
$this->assertTrue(
$this->collection->exists($this->redBook),
"An added document hasn't been found as existing."
);
//::update
$this->redBook->author = 'Iain M. Banks';
$this->collection->update($this->redBook);
$this->assertEquals(
'redBook',
$this->redBook->id,
"The document ID has been modified during an update operation. It should stay the same. Old id: redBook. New id: " . $this->redBook->id
);
//::count
$this->assertEquals(1, $this->collection->count());
//::get - when our collection uses the generic CollectionDocument class
$newDocument = $this->collection->get($this->redBook->id);
$this->assertInstanceOf(CollectionDocument::class, $newDocument);
$this->assertNotInstanceOf(BookDocument::class, $newDocument);
//::set - when our collection uses a proper CollectionDocument descendant
$this->collection->documentType = BookDocument::class;
$newBook = $this->collection->get($this->redBook->id);
$this->assertInstanceOf(BookDocument::class, $newBook);
$this->assertObjectHasProperty('title', $newBook);
$this->assertObjectHasProperty('author', $newBook);
$this->assertObjectHasProperty('id', $newBook);
$this->assertEquals('Matter', $newBook->title);
$this->assertEquals('Iain M. Banks', $newBook->author);
$this->assertEquals('redBook', $newBook->id);
//::set - an existing document as parameter
$previousId = $this->redBook->id;
$this->collection->set($this->redBook);
$this->assertEquals(
$previousId,
$this->redBook->id,
"The document ID has been modified during a set operation on an already added dcoument. It should stay the same. Old id: $previousId. New id: " . $this->redBook->id
);
//::count
$this->assertEquals(1, $this->collection->count());
//::set - a new document as parameter
$this->collection->set($this->blueBook);
$this->assertNotEmpty(
$this->blueBook->id,
"After a document has been added, the expected behavior is the id property is filled with the generated identifiant."
);
$this->assertTrue(
$this->collection->exists($this->blueBook),
"An added document with set hasn't been found as existing."
);
//::count
$this->assertEquals(2, $this->collection->count());
//::getAll
$documents = $this->collection->getAll();
$count = 0;
foreach ($documents as $document) {
switch ($document->id) {
case $this->blueBook->id:
$this->assertInstanceOf(BookDocument::class, $document);
$this->assertObjectHasProperty('title', $document);
$this->assertObjectHasProperty('author', $document);
$this->assertObjectHasProperty('id', $document);
$this->assertEquals('Foundation', $document->title);
$this->assertEquals('Isaac Asimov', $document->author);
break;
case 'redBook':
$this->assertInstanceOf(BookDocument::class, $document);
$this->assertObjectHasProperty('title', $document);
$this->assertObjectHasProperty('author', $document);
$this->assertObjectHasProperty('id', $document);
$this->assertEquals('Matter', $document->title);
$this->assertEquals('Iain M. Banks', $document->author);
break;
case '':
$this->fail("An object without id has been returned by the getAll method.");
break;
default:
$this->fail("A document with an id nor 'redBook', nor the blueBook generated id ('{$this->blueBook->id}') has been returned: $document->id.");
}
$count++;
}
$this->assertEquals(2, $count);
//::delete
$this->collection->delete($this->blueBook->id);
$this->assertFalse(
$this->collection->exists($this->blueBook),
"A deleted document has been marked existing."
);
$this->assertTrue(
$this->collection->exists($this->redBook),
"An unexpected document has been deleted."
);
//::count
$this->assertEquals(1, $this->collection->count());
//::delete, ::count
$this->collection->delete($this->redBook->id);
$this->assertEquals(0, $this->collection->count());
//::getAll
$documents = $this->collection->getAll();
$count = iterator_count($documents);
$this->assertEquals(0, $count, "We expected each collection document would have been deleted.");
}
}
diff --git a/workspaces/tests/Engines/Collection/FilesCollectionTest.php b/workspaces/tests/Engines/Collection/FilesCollectionTest.php
index 91752e8..8632029 100644
--- a/workspaces/tests/Engines/Collection/FilesCollectionTest.php
+++ b/workspaces/tests/Engines/Collection/FilesCollectionTest.php
@@ -1,170 +1,170 @@
<?php
/**
* _, __, _, _ __, _ _, _, _
* / \ |_) (_ | | \ | /_\ |\ |
* \ / |_) , ) | |_/ | | | | \|
* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*
* Unit testing — FilesCollection class
*
* @package ObsidianWorkspaces
* @subpackage Tests
* @author Sébastien Santoro aka Dereckson <dereckson@espace-win.org>
* @license http://www.opensource.org/licenses/bsd-license.php BSD
* @filesource
*/
namespace Waystone\Workspaces\Tests\Engines\Collection;
+use Waystone\Workspaces\Engines\Collection\FilesCollection;
+
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\TestCase;
-use FilesCollection;
-
use Exception;
require_once(__DIR__ . '/../../../src//includes/GlobalFunctions.php');
/**
* Tests FilesCollection class
*/
#[CoversClass(FilesCollection::class)]
class FilesCollectionTest extends TestCase {
/**
* @var string Our collection
*/
protected $collection;
/**
* Gets default configuration for this test
*
* @return array The configuration block
*/
protected static function getConfig () {
return [
'DocumentStorage' => [
'Type' => 'Files',
'Path' => UNITTESTING_FILESCOLLECTION_PATH
]
];
}
protected function setUp () : void {
$this->initializeDocuments();
global $Config;
$Config = self::getConfig();
$this->collection = new FilesCollection('quux');
}
///
/// Specific tests for this particular Collection class
///
public function testConstructor () {
global $Config;
$Config = self::getConfig();
$collection = new FilesCollection('quux');
$this->assertEquals('quux', $collection->id);
}
public function testPaths () {
global $Config;
$Config = self::getConfig();
$expectedPath = UNITTESTING_FILESCOLLECTION_PATH
. DIRECTORY_SEPARATOR
. 'quux';
$this->assertEquals(
$expectedPath,
FilesCollection::getCollectionPath('quux')
);
$this->assertFileExists($expectedPath);
$expectedPath .= DIRECTORY_SEPARATOR
. 'foo.json';
$this->assertEquals(
$expectedPath,
$this->collection->getDocumentPath('foo')
);
}
public function testConfigurationMissingException () {
//Note: @expectedException isn't allowed in PHPUnit to test the generic Exception class.
global $Config;
$oldConfigDocumentStorage = $Config['DocumentStorage'];
$Config['DocumentStorage'] = []; //Path isn't defined
$this>$this->expectException(Exception::class);
FilesCollection::getCollectionPath('quux');
$Config['DocumentStorage'] = $oldConfigDocumentStorage;
}
public function testCantCreateDirectoryException () {
global $Config;
$oldConfigDocumentStorage = $Config['DocumentStorage'];
$Config['DocumentStorage'] = [
'Type' => 'Files',
'Path' => '/root/obsidiancollections',
];
$this->expectException(Exception::class);
FilesCollection::getCollectionPath('quux');
$Config['DocumentStorage'] = $oldConfigDocumentStorage;
}
///
/// CRUD tests
///
use CRUDTestTrait;
public function testFileContent () {
global $Config;
$Config = self::getConfig();
$book = new BookDocument('Iain Banks', 'Excession');
$book->id = 'greenBook';
$this->collection->add($book);
$filename = $this->collection->getDocumentPath('greenBook');
$this->assertJsonFileEqualsJsonFile(
'includes/collection/greenBook1.json',
$filename
);
$book->author = 'Iain M. Banks';
$this->collection->update($book);
$this->assertJsonFileEqualsJsonFile(
'includes/collection/greenBook2.json',
$filename
);
//Cleans up, so CRUD test starts with an empty collection
unlink(UNITTESTING_FILESCOLLECTION_PATH . '/quux/greenBook.json');
}
///
/// Cleanup
///
/**
* Tears down resources when tests are done
*/
public static function tearDownAfterClass () : void {
//Removes created directories
rmdir(UNITTESTING_FILESCOLLECTION_PATH . '/quux');
rmdir(UNITTESTING_FILESCOLLECTION_PATH);
}
}
diff --git a/workspaces/tests/Engines/Collection/MongoDBCollectionTest.php b/workspaces/tests/Engines/Collection/MongoDBCollectionTest.php
index 9ce8f62..404e748 100644
--- a/workspaces/tests/Engines/Collection/MongoDBCollectionTest.php
+++ b/workspaces/tests/Engines/Collection/MongoDBCollectionTest.php
@@ -1,61 +1,61 @@
<?php
/**
* _, __, _, _ __, _ _, _, _
* / \ |_) (_ | | \ | /_\ |\ |
* \ / |_) , ) | |_/ | | | | \|
* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*
* Unit testing — MongoDBCollection class
*
* @package ObsidianWorkspaces
* @subpackage Tests
* @author Sébastien Santoro aka Dereckson <dereckson@espace-win.org>
* @license http://www.opensource.org/licenses/bsd-license.php BSD
* @filesource
*/
namespace Waystone\Workspaces\Tests\Engines\Collection;
+use Waystone\Workspaces\Engines\Collection\MongoDBCollection;
+
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\TestCase;
-use MongoDBCollection;
-
/**
* Tests MongoDBCollection class
*/
#[CoversClass(MongoDBCollection::class)]
class MongoDBCollectionTest extends TestCase {
/**
* @var string Our collection
*/
protected $collection;
/**
* Gets default configuration for this test
*
* @return array The configuration block
*/
public static function getConfig () {
return [
'DocumentStorage' => [
'Type' => 'MongoDB',
'Host' => UNITTESTING_MONGODB_HOST,
'Port' => UNITTESTING_MONGODB_PORT,
'SSL' => UNITTESTING_MONGODB_SSL ? [] : null
]
];
}
public function setUp () : void {
global $Config;
$Config = static::getConfig();
$this->initializeDocuments();
$this->collection = new MongoDBCollection('quux');
}
use CRUDTestTrait;
}
diff --git a/workspaces/tests/Engines/Collection/MySQCollectionTest.php b/workspaces/tests/Engines/Collection/MySQCollectionTest.php
index 742c537..c14a742 100644
--- a/workspaces/tests/Engines/Collection/MySQCollectionTest.php
+++ b/workspaces/tests/Engines/Collection/MySQCollectionTest.php
@@ -1,133 +1,133 @@
<?php
/**
* _, __, _, _ __, _ _, _, _
* / \ |_) (_ | | \ | /_\ |\ |
* \ / |_) , ) | |_/ | | | | \|
* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*
* Unit testing — MySQLCollection class
*
* @package ObsidianWorkspaces
* @subpackage Tests
* @author Sébastien Santoro aka Dereckson <dereckson@espace-win.org>
* @license http://www.opensource.org/licenses/bsd-license.php BSD
* @filesource
*/
namespace Waystone\Workspaces\Tests\Engines\Collection;
+use Waystone\Workspaces\Engines\Collection\MySQLCollection;
+
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\TestCase;
-use MySQLCollection;
-
/**
* Tests MySQLCollection class
*/
#[CoversClass(MySQLCollection::class)]
class MySQLCollectionTest extends TestCase {
///
/// Traits
///
use CRUDTestTrait;
use SQLTestTrait;
///
/// Test properties
///
/**
* @var string Our collection
*/
protected $collection;
///
/// Class initialisation
///
/**
* Gets default configuration for this test
*
* @return array The configuration block
*/
protected static function getConfig () {
return [
'DocumentStorage' => [
'Type' => 'MySQL',
'Table' => UNITTESTING_MYSQL_TABLE
]
];
}
/**
* Initializes the resources needed for thist test.
*/
public function setUp () : void {
$db = new MySQLDatabase(
UNITTESTING_MYSQL_HOST,
UNITTESTING_MYSQL_USERNAME,
UNITTESTING_MYSQL_PASSWORD,
UNITTESTING_MYSQL_DATABASE
);
$this->initializeDocuments();
$this->collection = new MySQLCollection('quux', $db, UNITTESTING_MYSQL_TABLE);
}
///
/// Tests specific to MySQLCollection
///
/**
* Tests the property table is correctly set
*/
public function testTable () {
$this->assertEquals(UNITTESTING_MYSQL_TABLE, $this->collection->table, "The collection constructor should have initialized the MySQLCollection::table property.");
}
/**
* Tests if the ready constant has been correctly defined
*/
public function testReadyConstant () {
$this->assertTrue(
defined('COLLECTIONS_MYSQL_DATABASE_READY'),
"After the client has been initialized, we shall have a 'COLLECTIONS_SQLITE_DATABASE_READY' constant defined."
);
$this->assertSame(
COLLECTIONS_MYSQL_DATABASE_READY,
true,
"COLLECTIONS_MYSQL_DATABASE_READY constant value shall be the boolean true."
);
}
/**
* Tests if strings are correctly escaped
*/
public function testEscape () {
$toEscapeExpressions = [
"",
"Lorem ipsum dolor",
"L'arbre",
"''",
"cœur"
];
$escapedExpressions = [
"",
"Lorem ipsum dolor",
"L\\'arbre",
"\\'\\'",
"cœur"
];
for ($i = 0 ; $i < count($toEscapeExpressions) ; $i++) {
$this->assertEquals(
$escapedExpressions[$i],
$this->collection->escape($toEscapeExpressions[$i]),
"The following string isn't properly escaped: '$toEscapeExpressions[$i]'"
);
}
}
}
diff --git a/workspaces/tests/Engines/Collection/SQLTestTrait.php b/workspaces/tests/Engines/Collection/SQLTestTrait.php
index 9a0ade8..64a7d38 100644
--- a/workspaces/tests/Engines/Collection/SQLTestTrait.php
+++ b/workspaces/tests/Engines/Collection/SQLTestTrait.php
@@ -1,68 +1,66 @@
<?php
/**
* _, __, _, _ __, _ _, _, _
* / \ |_) (_ | | \ | /_\ |\ |
* \ / |_) , ) | |_/ | | | | \|
* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*
* SQL schema tests for each Collection class.
*
* @package ObsidianWorkspaces
* @subpackage Tests
* @author Sébastien Santoro aka Dereckson <dereckson@espace-win.org>
* @license http://www.opensource.org/licenses/bsd-license.php BSD
* @filesource
*/
namespace Waystone\Workspaces\Tests\Engines\Collection;
-require_once(__DIR__ . '/../../../src/includes/autoload.php');
+use Exception;
/**
* The tests for our SQL storage engines, to ensure the schema is created correctly.
*
* For coverage purposes, it requires a coversDefaultClass annotation in the classes using this trait.
*/
trait SQLTestTrait {
- /**
- * @covers ::query()
- */
+
public function testQuery () {
/*
The query method is a complicated aspect of the code, as it returns a different
result according the kind of query:
(1) If the query doesn't return any result, null.
(2) If the query return a row with one field, the scalar value.
(3) Otherwise, an associative array, the fields as keys, the row as values.
*/
$sqlNoQueryResult = "";
$sqlNullResult = "UPDATE {$this->collection->table} SET collection_id = 'lorem' WHERE collection_id = 'lorem'";
$sqlScalarResult = "SELECT 1+1";
$sqlArrayResult = "SELECT 8+2 as sum, 8*2 as product, 8/2 as quotient, 8-2 as difference";
try {
$resultNull = $this->collection->query($sqlNoQueryResult);
} catch (Exception $ex) {
$this->fail("The query() specifications provides: 'If the query doesn't return any result, return null.'. This is also the expected behavior for empty queries. Instead we got an exception.");
}
$this->assertNull($resultNull, "The query() specifications provides: 'If the query doesn't return any result, return null.'. This is also the expected behavior for empty queries.");
$resultNull = $this->collection->query($sqlNullResult);
$this->assertNull($resultNull, "The query() specifications provides: 'If the query doesn't return any result, return null.'. This is expected for $sqlNullResult.");
$resultScalar = $this->collection->query($sqlScalarResult);
$this->assertEquals(2, $resultScalar, "The query() specifications provides: 'If the query return a row with one field, the scalar value.' This is expected for $sqlScalarResult.");
$resultArray = $this->collection->query($sqlArrayResult);
$expectedResultArray = [
'sum' => 10,
'product' => 16,
'quotient' => 4,
'difference' => 6,
];
$this->assertEquals($expectedResultArray, $resultArray, "The query() specifications provides: '[If the query returns a non scalar result, return] an associative array, the fields as keys, the row as values.'. This is expected for $sqlArrayResult.");
}
}
diff --git a/workspaces/tests/Engines/Collection/SQLiteCollectionTest.php b/workspaces/tests/Engines/Collection/SQLiteCollectionTest.php
index e655937..df137f2 100644
--- a/workspaces/tests/Engines/Collection/SQLiteCollectionTest.php
+++ b/workspaces/tests/Engines/Collection/SQLiteCollectionTest.php
@@ -1,174 +1,174 @@
<?php
/**
* _, __, _, _ __, _ _, _, _
* / \ |_) (_ | | \ | /_\ |\ |
* \ / |_) , ) | |_/ | | | | \|
* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*
* Unit testing — SQLiteCollection class
*
* @package ObsidianWorkspaces
* @subpackage Tests
* @author Sébastien Santoro aka Dereckson <dereckson@espace-win.org>
* @license http://www.opensource.org/licenses/bsd-license.php BSD
* @filesource
*/
namespace Waystone\Workspaces\Tests\Engines\Collection;
+use Waystone\Workspaces\Engines\Collection\SQLiteCollection;
+
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\TestCase;
-use SQLiteCollection;
-
/**
* Tests SQLiteCollection class
*/
#[CoversClass(SQLiteCollection::class)]
class SQLiteCollectionTest extends TestCase {
///
/// Traits
///
use CRUDTestTrait;
use SQLTestTrait;
///
/// Test properties
///
/**
* @var string Our collection
*/
protected $collection;
///
/// Class initizliation
///
/**
* Gets default configuration for this test
*
* @return array The configuration block
*/
public static function getConfig () {
return [
'DocumentStorage' => [
'Type' => 'SQLite',
'File' => UNITTESTING_SQLITE_FILE
]
];
}
public function setUp () : void {
$this->initializeDocuments();
global $Config;
$Config = static::getConfig();
$this->collection = new SQLiteCollection('quux');
}
///
/// Tests specific to SQLiteCollection
///
/**
* Tests the client related methods
*/
public function testClient () {
global $Config;
$client1 = SQLiteCollection::getClient();
$client2 = SQLiteCollection::getClient();
$this->assertInstanceOf('SQLite3', $client1);
$this->assertInstanceOf('SQLite3', $client2);
$this->assertSame($client1, $client2, "The collection classes are expected to use a singleton pattern for the client: you should return the same object initialized before instead to create another one.");
$databaseList = $this->collection->query("PRAGMA database_list");
$this->assertEquals(
[
'seq' => 0,
'name' => 'main',
'file' => realpath($Config['DocumentStorage']['File'])
],
$databaseList,
"The query PRAGMA database_list hasn't returned what we expected: one database opened by the client, the file returned by the database matching our configuration file."
);
$this->assertTrue(
defined('COLLECTIONS_SQLITE_DATABASE_READY'),
"After the client has been initialized, we shall have a 'COLLECTIONS_SQLITE_DATABASE_READY' constant defined."
);
$this->assertSame(
COLLECTIONS_SQLITE_DATABASE_READY,
true,
"COLLECTIONS_SQLITE_DATABASE_READY constant value shall be the boolean true."
);
}
/**
* Tests string escapement
*/
public function testEscape () {
$toEscapeExpressions = [
"",
"Lorem ipsum dolor",
"L'arbre",
"''",
"cœur"
];
$escapedExpressions = [
"",
"Lorem ipsum dolor",
"L''arbre",
"''''",
"cœur"
];
for ($i = 0 ; $i < count($toEscapeExpressions) ; $i++) {
$this->assertEquals(
$escapedExpressions[$i],
$this->collection->escape($toEscapeExpressions[$i]),
"The following string isn't properly escaped: '$toEscapeExpressions[$i]'"
);
}
}
public function testStatements () {
$sqlQueries = [
"SELECT foo FROM bar",
"PRAGMA foo"
];
$sqlStatements = [
"UPDATE bar SET foo = 'quux'",
"DELETE FROM bar WHERE foo = 'quux'",
"INSERT INTO bar (foo) VALUES ('quux')",
"REPLACE INTO bar (foo) VALUES ('quux')",
"INSERT INTO bar SELECT FROM baz"
];
foreach ($sqlQueries as $sql) {
$this->assertFalse(
$this->collection->isStatement($sql),
"The query $sql should be considered as a query, not as a statement, to use SQLite3::query() and not SQLite3::exec()"
);
}
foreach ($sqlStatements as $sql) {
$this->assertTrue(
$this->collection->isStatement($sql),
"The query $sql should be considered as a statement, not as a query, as long as SQLite3 is concerned, to use SQLite3::exec() and not SQLite3::query()"
);
}
}
/**
* Clears resources created for this test
*/
public static function tearDownAfterClass () : void {
unlink(UNITTESTING_SQLITE_FILE);
}
}

File Metadata

Mime Type
text/x-diff
Expires
Wed, Mar 18, 12:42 (1 d, 17 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3539736
Default Alt Text
(79 KB)

Event Timeline