Initial Version
This commit is contained in:
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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user