Initial Version
This commit is contained in:
76
core/lib/Db/Client.php
Normal file
76
core/lib/Db/Client.php
Normal file
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace KTXC\Db;
|
||||
|
||||
use MongoDB\Client as MongoClient;
|
||||
|
||||
/**
|
||||
* Wrapper for MongoDB\Client
|
||||
* Provides abstraction layer for MongoDB client operations
|
||||
*/
|
||||
class Client
|
||||
{
|
||||
private MongoClient $client;
|
||||
|
||||
/**
|
||||
* Create a new MongoDB client
|
||||
*
|
||||
* @param string $uri Connection URI
|
||||
* @param array $uriOptions URI options
|
||||
* @param array $driverOptions Driver options
|
||||
*/
|
||||
public function __construct(string $uri = 'mongodb://localhost:27017', array $uriOptions = [], array $driverOptions = [])
|
||||
{
|
||||
$this->client = new MongoClient($uri, $uriOptions, $driverOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Select a database
|
||||
*
|
||||
* @param string $databaseName Database name
|
||||
* @param array $options Database options
|
||||
* @return Database
|
||||
*/
|
||||
public function selectDatabase(string $databaseName, array $options = []): Database
|
||||
{
|
||||
$mongoDatabase = $this->client->selectDatabase($databaseName, $options);
|
||||
return new Database($mongoDatabase);
|
||||
}
|
||||
|
||||
/**
|
||||
* List databases
|
||||
*/
|
||||
public function listDatabases(array $options = []): array
|
||||
{
|
||||
$databases = [];
|
||||
foreach ($this->client->listDatabases($options) as $databaseInfo) {
|
||||
$databases[] = $databaseInfo;
|
||||
}
|
||||
return $databases;
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop a database
|
||||
*/
|
||||
public function dropDatabase(string $databaseName, array $options = []): array|object|null
|
||||
{
|
||||
return $this->client->dropDatabase($databaseName, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the underlying MongoDB Client
|
||||
* Use sparingly - prefer using wrapper methods
|
||||
*/
|
||||
public function getMongoClient(): MongoClient
|
||||
{
|
||||
return $this->client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic method to access database as property
|
||||
*/
|
||||
public function __get(string $databaseName): Database
|
||||
{
|
||||
return $this->selectDatabase($databaseName);
|
||||
}
|
||||
}
|
||||
295
core/lib/Db/Collection.php
Normal file
295
core/lib/Db/Collection.php
Normal file
@@ -0,0 +1,295 @@
|
||||
<?php
|
||||
|
||||
namespace KTXC\Db;
|
||||
|
||||
use MongoDB\Collection as MongoCollection;
|
||||
use MongoDB\InsertOneResult;
|
||||
use MongoDB\UpdateResult;
|
||||
use MongoDB\DeleteResult;
|
||||
|
||||
/**
|
||||
* Wrapper for MongoDB\Collection
|
||||
* Provides abstraction layer for MongoDB collection operations
|
||||
*/
|
||||
class Collection
|
||||
{
|
||||
private MongoCollection $collection;
|
||||
|
||||
public function __construct(MongoCollection $collection)
|
||||
{
|
||||
$this->collection = $collection;
|
||||
|
||||
// Set type map to return plain arrays instead of objects
|
||||
// This converts BSON types to PHP native types
|
||||
$this->collection = $collection->withOptions([
|
||||
'typeMap' => [
|
||||
'root' => 'array',
|
||||
'document' => 'array',
|
||||
'array' => 'array'
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find documents in the collection
|
||||
*
|
||||
* @param array $filter Query filter
|
||||
* @param array $options Query options
|
||||
* @return Cursor
|
||||
*/
|
||||
public function find(array $filter = [], array $options = []): Cursor
|
||||
{
|
||||
$filter = $this->convertFilter($filter);
|
||||
/** @var \Iterator $cursor */
|
||||
$cursor = $this->collection->find($filter, $options);
|
||||
return new Cursor($cursor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a single document
|
||||
*
|
||||
* @param array $filter Query filter
|
||||
* @param array $options Query options
|
||||
* @return array|null Returns array with _id as string
|
||||
*/
|
||||
public function findOne(array $filter = [], array $options = []): ?array
|
||||
{
|
||||
$filter = $this->convertFilter($filter);
|
||||
$result = $this->collection->findOne($filter, $options);
|
||||
|
||||
if ($result === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Convert to array if it's an object
|
||||
if (is_object($result)) {
|
||||
$result = (array) $result;
|
||||
}
|
||||
|
||||
return $this->convertBsonToNative($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a single document
|
||||
*
|
||||
* @param array|object $document Document to insert
|
||||
* @param array $options Insert options
|
||||
* @return InsertOneResult
|
||||
*/
|
||||
public function insertOne(array|object $document, array $options = []): InsertOneResult
|
||||
{
|
||||
$document = $this->convertDocument($document);
|
||||
return $this->collection->insertOne($document, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert multiple documents
|
||||
*
|
||||
* @param array $documents Documents to insert
|
||||
* @param array $options Insert options
|
||||
*/
|
||||
public function insertMany(array $documents, array $options = []): mixed
|
||||
{
|
||||
$documents = array_map(fn($doc) => $this->convertDocument($doc), $documents);
|
||||
return $this->collection->insertMany($documents, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a single document
|
||||
*
|
||||
* @param array $filter Query filter
|
||||
* @param array $update Update operations
|
||||
* @param array $options Update options
|
||||
* @return UpdateResult
|
||||
*/
|
||||
public function updateOne(array $filter, array $update, array $options = []): UpdateResult
|
||||
{
|
||||
$filter = $this->convertFilter($filter);
|
||||
$update = $this->convertDocument($update);
|
||||
return $this->collection->updateOne($filter, $update, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update multiple documents
|
||||
*
|
||||
* @param array $filter Query filter
|
||||
* @param array $update Update operations
|
||||
* @param array $options Update options
|
||||
* @return UpdateResult
|
||||
*/
|
||||
public function updateMany(array $filter, array $update, array $options = []): UpdateResult
|
||||
{
|
||||
$filter = $this->convertFilter($filter);
|
||||
$update = $this->convertDocument($update);
|
||||
return $this->collection->updateMany($filter, $update, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a single document
|
||||
*
|
||||
* @param array $filter Query filter
|
||||
* @param array $options Delete options
|
||||
* @return DeleteResult
|
||||
*/
|
||||
public function deleteOne(array $filter, array $options = []): DeleteResult
|
||||
{
|
||||
$filter = $this->convertFilter($filter);
|
||||
return $this->collection->deleteOne($filter, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete multiple documents
|
||||
*
|
||||
* @param array $filter Query filter
|
||||
* @param array $options Delete options
|
||||
* @return DeleteResult
|
||||
*/
|
||||
public function deleteMany(array $filter, array $options = []): DeleteResult
|
||||
{
|
||||
$filter = $this->convertFilter($filter);
|
||||
return $this->collection->deleteMany($filter, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Count documents matching filter
|
||||
*
|
||||
* @param array $filter Query filter
|
||||
* @param array $options Count options
|
||||
* @return int
|
||||
*/
|
||||
public function countDocuments(array $filter = [], array $options = []): int
|
||||
{
|
||||
$filter = $this->convertFilter($filter);
|
||||
return $this->collection->countDocuments($filter, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute aggregation pipeline
|
||||
*
|
||||
* @param array $pipeline Aggregation pipeline
|
||||
* @param array $options Aggregation options
|
||||
* @return Cursor
|
||||
*/
|
||||
public function aggregate(array $pipeline, array $options = []): Cursor
|
||||
{
|
||||
/** @var \Iterator $cursor */
|
||||
$cursor = $this->collection->aggregate($pipeline, $options);
|
||||
return new Cursor($cursor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an index
|
||||
*
|
||||
* @param array $key Index specification
|
||||
* @param array $options Index options
|
||||
* @return string Index name
|
||||
*/
|
||||
public function createIndex(array $key, array $options = []): string
|
||||
{
|
||||
return $this->collection->createIndex($key, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop the collection
|
||||
*/
|
||||
public function drop(): array|object|null
|
||||
{
|
||||
return $this->collection->drop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get collection name
|
||||
*/
|
||||
public function getCollectionName(): string
|
||||
{
|
||||
return $this->collection->getCollectionName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get database name
|
||||
*/
|
||||
public function getDatabaseName(): string
|
||||
{
|
||||
return $this->collection->getDatabaseName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert ObjectId instances in filter to MongoDB ObjectId
|
||||
*/
|
||||
private function convertFilter(array $filter): array
|
||||
{
|
||||
return $this->convertArray($filter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert ObjectId instances in document to MongoDB ObjectId
|
||||
*/
|
||||
private function convertDocument(array|object $document): array|object
|
||||
{
|
||||
if (is_array($document)) {
|
||||
return $this->convertArray($document);
|
||||
}
|
||||
return $document;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively convert ObjectId and UTCDateTime instances
|
||||
*/
|
||||
private function convertArray(array $data): array
|
||||
{
|
||||
foreach ($data as $key => $value) {
|
||||
if ($value instanceof ObjectId) {
|
||||
$data[$key] = $value->toBSON();
|
||||
} elseif ($value instanceof UTCDateTime) {
|
||||
$data[$key] = $value->toBSON();
|
||||
} elseif (is_array($value)) {
|
||||
$data[$key] = $this->convertArray($value);
|
||||
}
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the underlying MongoDB Collection
|
||||
* Use sparingly - prefer using wrapper methods
|
||||
*/
|
||||
public function getMongoCollection(): MongoCollection
|
||||
{
|
||||
return $this->collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert BSON objects to native PHP types
|
||||
* Handles ObjectId, UTCDateTime, and other BSON types
|
||||
*/
|
||||
private function convertBsonToNative(mixed $data): mixed
|
||||
{
|
||||
if (is_array($data)) {
|
||||
foreach ($data as $key => $value) {
|
||||
$data[$key] = $this->convertBsonToNative($value);
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
if (is_object($data)) {
|
||||
// Convert MongoDB BSON ObjectId to string
|
||||
if ($data instanceof \MongoDB\BSON\ObjectId) {
|
||||
return (string) $data;
|
||||
}
|
||||
|
||||
// Convert MongoDB BSON UTCDateTime to string or DateTime
|
||||
if ($data instanceof \MongoDB\BSON\UTCDateTime) {
|
||||
return (string) $data->toDateTime()->format('c');
|
||||
}
|
||||
|
||||
// Convert other objects to arrays recursively
|
||||
if (method_exists($data, 'bsonSerialize')) {
|
||||
return $this->convertBsonToNative($data->bsonSerialize());
|
||||
}
|
||||
|
||||
return (array) $data;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
86
core/lib/Db/Cursor.php
Normal file
86
core/lib/Db/Cursor.php
Normal file
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
namespace KTXC\Db;
|
||||
|
||||
use Iterator;
|
||||
use IteratorAggregate;
|
||||
use Traversable;
|
||||
|
||||
/**
|
||||
* Wrapper for MongoDB Cursor
|
||||
* Provides abstraction layer for MongoDB cursor operations
|
||||
* Automatically converts BSON types to native PHP types
|
||||
*/
|
||||
class Cursor implements IteratorAggregate
|
||||
{
|
||||
private Iterator $cursor;
|
||||
|
||||
public function __construct(Iterator $cursor)
|
||||
{
|
||||
$this->cursor = $cursor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert cursor to array with BSON types converted to native PHP types
|
||||
*/
|
||||
public function toArray(): array
|
||||
{
|
||||
$result = iterator_to_array($this->cursor);
|
||||
return $this->convertBsonToNative($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get iterator for foreach loops
|
||||
* Note: Items will be returned as-is (may contain BSON objects)
|
||||
* Use toArray() if you need full conversion
|
||||
*/
|
||||
public function getIterator(): Traversable
|
||||
{
|
||||
return $this->cursor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get underlying MongoDB cursor
|
||||
*/
|
||||
public function getMongoCursor(): Iterator
|
||||
{
|
||||
return $this->cursor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert BSON objects to native PHP types
|
||||
* Handles ObjectId, UTCDateTime, and other BSON types
|
||||
*/
|
||||
private function convertBsonToNative(mixed $data): mixed
|
||||
{
|
||||
if (is_array($data)) {
|
||||
foreach ($data as $key => $value) {
|
||||
$data[$key] = $this->convertBsonToNative($value);
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
if (is_object($data)) {
|
||||
// Convert MongoDB BSON ObjectId to string
|
||||
if ($data instanceof \MongoDB\BSON\ObjectId) {
|
||||
return (string) $data;
|
||||
}
|
||||
|
||||
// Convert MongoDB BSON UTCDateTime to ISO8601 string
|
||||
if ($data instanceof \MongoDB\BSON\UTCDateTime) {
|
||||
return $data->toDateTime()->format('c');
|
||||
}
|
||||
|
||||
// Convert other objects to arrays recursively
|
||||
if (method_exists($data, 'bsonSerialize')) {
|
||||
return $this->convertBsonToNative($data->bsonSerialize());
|
||||
}
|
||||
|
||||
// Convert stdClass and other objects to array
|
||||
$array = (array) $data;
|
||||
return $this->convertBsonToNative($array);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
97
core/lib/Db/DataStore.php
Normal file
97
core/lib/Db/DataStore.php
Normal file
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
|
||||
namespace KTXC\Db;
|
||||
|
||||
use DI\Attribute\Inject;
|
||||
|
||||
/**
|
||||
* DataStore provides access to MongoDB database operations
|
||||
* Uses composition pattern with Database wrapper
|
||||
*/
|
||||
class DataStore
|
||||
{
|
||||
protected array $configuration;
|
||||
protected Client $client;
|
||||
protected Database $database;
|
||||
|
||||
public function __construct(#[Inject('database')] array $configuration)
|
||||
{
|
||||
$this->configuration = $configuration;
|
||||
|
||||
$uri = $configuration['uri'];
|
||||
$databaseName = $configuration['database'];
|
||||
$options = $configuration['options'] ?? [];
|
||||
$driverOptions = $configuration['driverOptions'] ?? [];
|
||||
|
||||
$this->client = new Client($uri, $options, $driverOptions);
|
||||
$this->database = $this->client->selectDatabase($databaseName, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Select a collection from the database
|
||||
*
|
||||
* @param string $collectionName Collection name
|
||||
* @param array $options Collection options
|
||||
* @return Collection
|
||||
*/
|
||||
public function selectCollection(string $collectionName, array $options = []): Collection
|
||||
{
|
||||
return $this->database->selectCollection($collectionName, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the underlying Database instance
|
||||
*/
|
||||
public function getDatabase(): Database
|
||||
{
|
||||
return $this->database;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Client instance
|
||||
*/
|
||||
public function getClient(): Client
|
||||
{
|
||||
return $this->client;
|
||||
}
|
||||
|
||||
/**
|
||||
* List all collections
|
||||
*/
|
||||
public function listCollections(array $options = []): array
|
||||
{
|
||||
return $this->database->listCollections($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a collection
|
||||
*/
|
||||
public function createCollection(string $collectionName, array $options = []): Collection
|
||||
{
|
||||
return $this->database->createCollection($collectionName, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop a collection
|
||||
*/
|
||||
public function dropCollection(string $collectionName, array $options = []): array|object
|
||||
{
|
||||
return $this->database->dropCollection($collectionName, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get database name
|
||||
*/
|
||||
public function getDatabaseName(): string
|
||||
{
|
||||
return $this->database->getDatabaseName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic method to access collection as property
|
||||
*/
|
||||
public function __get(string $collectionName): Collection
|
||||
{
|
||||
return $this->selectCollection($collectionName);
|
||||
}
|
||||
}
|
||||
104
core/lib/Db/Database.php
Normal file
104
core/lib/Db/Database.php
Normal file
@@ -0,0 +1,104 @@
|
||||
<?php
|
||||
|
||||
namespace KTXC\Db;
|
||||
|
||||
use MongoDB\Database as MongoDatabase;
|
||||
|
||||
/**
|
||||
* Wrapper for MongoDB\Database
|
||||
* Provides abstraction layer for MongoDB database operations
|
||||
*/
|
||||
class Database
|
||||
{
|
||||
private MongoDatabase $database;
|
||||
|
||||
public function __construct(MongoDatabase $database)
|
||||
{
|
||||
$this->database = $database;
|
||||
}
|
||||
|
||||
/**
|
||||
* Select a collection
|
||||
*
|
||||
* @param string $collectionName Collection name
|
||||
* @param array $options Collection options
|
||||
* @return Collection
|
||||
*/
|
||||
public function selectCollection(string $collectionName, array $options = []): Collection
|
||||
{
|
||||
$mongoCollection = $this->database->selectCollection($collectionName, $options);
|
||||
return new Collection($mongoCollection);
|
||||
}
|
||||
|
||||
/**
|
||||
* List collections
|
||||
*/
|
||||
public function listCollections(array $options = []): array
|
||||
{
|
||||
$collections = [];
|
||||
foreach ($this->database->listCollections($options) as $collectionInfo) {
|
||||
$collections[] = $collectionInfo;
|
||||
}
|
||||
return $collections;
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop the database
|
||||
*/
|
||||
public function drop(array $options = []): array|object|null
|
||||
{
|
||||
return $this->database->drop($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get database name
|
||||
*/
|
||||
public function getDatabaseName(): string
|
||||
{
|
||||
return $this->database->getDatabaseName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a collection
|
||||
*/
|
||||
public function createCollection(string $collectionName, array $options = []): Collection|null
|
||||
{
|
||||
$mongoCollection = $this->database->createCollection($collectionName, $options);
|
||||
return $mongoCollection ? new Collection($mongoCollection) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop a collection
|
||||
*/
|
||||
public function dropCollection(string $collectionName, array $options = []): array|object|null
|
||||
{
|
||||
return $this->database->dropCollection($collectionName, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a database command
|
||||
*/
|
||||
public function command(array|object $command, array $options = []): Cursor
|
||||
{
|
||||
/** @var \Iterator $cursor */
|
||||
$cursor = $this->database->command($command, $options);
|
||||
return new Cursor($cursor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the underlying MongoDB Database
|
||||
* Use sparingly - prefer using wrapper methods
|
||||
*/
|
||||
public function getMongoDatabase(): MongoDatabase
|
||||
{
|
||||
return $this->database;
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic method to access collection as property
|
||||
*/
|
||||
public function __get(string $collectionName): Collection
|
||||
{
|
||||
return $this->selectCollection($collectionName);
|
||||
}
|
||||
}
|
||||
71
core/lib/Db/ObjectId.php
Normal file
71
core/lib/Db/ObjectId.php
Normal file
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
namespace KTXC\Db;
|
||||
|
||||
use MongoDB\BSON\ObjectId as MongoObjectId;
|
||||
|
||||
/**
|
||||
* Wrapper for MongoDB\BSON\ObjectId
|
||||
* Provides abstraction layer for MongoDB ObjectId handling
|
||||
*/
|
||||
class ObjectId
|
||||
{
|
||||
private MongoObjectId $objectId;
|
||||
|
||||
/**
|
||||
* Create a new ObjectId
|
||||
*
|
||||
* @param string|MongoObjectId|null $id Optional ID string or MongoDB ObjectId
|
||||
*/
|
||||
public function __construct(string|MongoObjectId|null $id = null)
|
||||
{
|
||||
if ($id instanceof MongoObjectId) {
|
||||
$this->objectId = $id;
|
||||
} elseif (is_string($id)) {
|
||||
$this->objectId = new MongoObjectId($id);
|
||||
} else {
|
||||
$this->objectId = new MongoObjectId();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the string representation of the ObjectId
|
||||
*/
|
||||
public function __toString(): string
|
||||
{
|
||||
return (string) $this->objectId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the underlying MongoDB ObjectId
|
||||
* Used internally when interacting with MongoDB driver
|
||||
*/
|
||||
public function toBSON(): MongoObjectId
|
||||
{
|
||||
return $this->objectId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the timestamp from the ObjectId
|
||||
*/
|
||||
public function getTimestamp(): int
|
||||
{
|
||||
return $this->objectId->getTimestamp();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create ObjectId from string
|
||||
*/
|
||||
public static function fromString(string $id): self
|
||||
{
|
||||
return new self($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a string is a valid ObjectId
|
||||
*/
|
||||
public static function isValid(string $id): bool
|
||||
{
|
||||
return MongoObjectId::isValid($id);
|
||||
}
|
||||
}
|
||||
89
core/lib/Db/UTCDateTime.php
Normal file
89
core/lib/Db/UTCDateTime.php
Normal file
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
namespace KTXC\Db;
|
||||
|
||||
use MongoDB\BSON\UTCDateTime as MongoUTCDateTime;
|
||||
use DateTimeInterface;
|
||||
|
||||
/**
|
||||
* Wrapper for MongoDB\BSON\UTCDateTime
|
||||
* Provides abstraction layer for MongoDB datetime handling
|
||||
*/
|
||||
class UTCDateTime
|
||||
{
|
||||
private MongoUTCDateTime|string $dateTime;
|
||||
|
||||
/**
|
||||
* Create a new UTCDateTime
|
||||
*
|
||||
* @param int|DateTimeInterface|null $milliseconds Milliseconds since epoch, or DateTime object
|
||||
*/
|
||||
public function __construct(int|DateTimeInterface|null $milliseconds = null)
|
||||
{
|
||||
// Check if MongoDB extension is loaded
|
||||
if (class_exists(MongoUTCDateTime::class)) {
|
||||
$this->dateTime = new MongoUTCDateTime($milliseconds);
|
||||
} else {
|
||||
// Fallback for environments without MongoDB extension (testing, linting)
|
||||
$this->dateTime = (new \DateTimeImmutable('now', new \DateTimeZone('UTC')))->format(DATE_ATOM);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the string representation
|
||||
*/
|
||||
public function __toString(): string
|
||||
{
|
||||
if ($this->dateTime instanceof MongoUTCDateTime) {
|
||||
return $this->dateTime->toDateTime()->format(DATE_ATOM);
|
||||
}
|
||||
return $this->dateTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the underlying MongoDB UTCDateTime or fallback string
|
||||
* Used internally when interacting with MongoDB driver
|
||||
*/
|
||||
public function toBSON(): MongoUTCDateTime|string
|
||||
{
|
||||
return $this->dateTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert to PHP DateTime
|
||||
*/
|
||||
public function toDateTime(): \DateTimeImmutable
|
||||
{
|
||||
if ($this->dateTime instanceof MongoUTCDateTime) {
|
||||
return \DateTimeImmutable::createFromMutable($this->dateTime->toDateTime());
|
||||
}
|
||||
return new \DateTimeImmutable($this->dateTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get milliseconds since epoch
|
||||
*/
|
||||
public function toMilliseconds(): int
|
||||
{
|
||||
if ($this->dateTime instanceof MongoUTCDateTime) {
|
||||
return (int) $this->dateTime;
|
||||
}
|
||||
return (int) ((new \DateTimeImmutable($this->dateTime))->getTimestamp() * 1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create from DateTime
|
||||
*/
|
||||
public static function fromDateTime(DateTimeInterface $dateTime): self
|
||||
{
|
||||
return new self($dateTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create current timestamp
|
||||
*/
|
||||
public static function now(): self
|
||||
{
|
||||
return new self();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user