| #0 | MongoDB\Driver\Manager->selectServer /srv/ChatHispanoEngine/releases/20250927141530/vendor/mongodb/mongodb/src/functions.php (600) <?php
/*
* Copyright 2015-present MongoDB, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace MongoDB;
use Exception;
use MongoDB\BSON\Document;
use MongoDB\BSON\PackedArray;
use MongoDB\BSON\Serializable;
use MongoDB\Builder\Type\StageInterface;
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
use MongoDB\Driver\Manager;
use MongoDB\Driver\ReadPreference;
use MongoDB\Driver\Server;
use MongoDB\Driver\Session;
use MongoDB\Driver\WriteConcern;
use MongoDB\Exception\InvalidArgumentException;
use MongoDB\Exception\RuntimeException;
use MongoDB\Operation\ListCollections;
use MongoDB\Operation\WithTransaction;
use Psr\Log\LoggerInterface;
use ReflectionClass;
use ReflectionException;
use stdClass;
use function array_is_list;
use function array_key_first;
use function assert;
use function end;
use function get_object_vars;
use function is_array;
use function is_object;
use function is_string;
use function str_ends_with;
use function substr;
/**
* Registers a PSR-3 logger to receive log messages from the driver/library.
*
* Calling this method again with a logger that has already been added will have
* no effect.
*/
function add_logger(LoggerInterface $logger): void
{
PsrLogAdapter::addLogger($logger);
}
/**
* Unregisters a PSR-3 logger.
*
* Calling this method with a logger that has not been added will have no
* effect.
*/
function remove_logger(LoggerInterface $logger): void
{
PsrLogAdapter::removeLogger($logger);
}
/**
* Create a new stdClass instance with the provided properties.
* Use named arguments to specify the property names.
* object( property1: value1, property2: value2 )
*
* If property names contain a dot or a dollar characters, use array unpacking syntax.
* object( ...[ 'author.name' => 1, 'array.$' => 1 ] )
*
* @psalm-suppress MoreSpecificReturnType
* @psalm-suppress LessSpecificReturnStatement
*/
function object(mixed ...$values): stdClass
{
return (object) $values;
}
/**
* Check whether all servers support executing a write stage on a secondary.
*
* @internal
* @param Server[] $servers
*/
function all_servers_support_write_stage_on_secondary(array $servers): bool
{
/* Write stages on secondaries are technically supported by FCV 4.4, but the
* CRUD spec requires all 5.0+ servers since FCV is not tracked by SDAM. */
static $wireVersionForWriteStageOnSecondary = 13;
foreach ($servers as $server) {
// We can assume that load balancers only front 5.0+ servers
if ($server->getType() === Server::TYPE_LOAD_BALANCER) {
continue;
}
if (! server_supports_feature($server, $wireVersionForWriteStageOnSecondary)) {
return false;
}
}
return true;
}
/**
* Applies a type map to a document.
*
* This function is used by operations where it is not possible to apply a type
* map to the cursor directly because the root document is a command response
* (e.g. findAndModify).
*
* @internal
* @param array|object $document Document to which the type map will be applied
* @param array $typeMap Type map for BSON deserialization.
* @throws InvalidArgumentException
*/
function apply_type_map_to_document(array|object $document, array $typeMap): array|object
{
if (! is_document($document)) {
throw InvalidArgumentException::expectedDocumentType('$document', $document);
}
return Document::fromPHP($document)->toPHP($typeMap);
}
/**
* Converts a document parameter to an array.
*
* This is used to facilitate unified access to document fields. It also handles
* Document, PackedArray, and Serializable objects.
*
* This function is not used for type checking. Therefore, it does not reject
* PackedArray objects or Serializable::bsonSerialize() return values that would
* encode as BSON arrays.
*
* @internal
* @throws InvalidArgumentException if $document is not an array or object
*/
function document_to_array(array|object $document): array
{
if ($document instanceof Document || $document instanceof PackedArray) {
/* Nested documents and arrays are intentionally left as BSON. We avoid
* iterator_to_array() since Document and PackedArray iteration returns
* all values as MongoDB\BSON\Value instances. */
/** @psalm-var array */
return $document->toPHP([
'array' => 'bson',
'document' => 'bson',
'root' => 'array',
]);
} elseif ($document instanceof Serializable) {
$document = $document->bsonSerialize();
}
if (is_object($document)) {
/* Note: this omits all uninitialized properties, whereas BSON encoding
* includes untyped, uninitialized properties. This is acceptable given
* document_to_array()'s use cases. */
$document = get_object_vars($document);
}
return $document;
}
/**
* Return a collection's encryptedFields from the encryptedFieldsMap
* autoEncryption driver option (if available).
*
* @internal
* @see https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/client-side-encryption.rst#collection-encryptedfields-lookup-getencryptedfields
* @see Collection::drop()
* @see Database::createCollection()
* @see Database::dropCollection()
*/
function get_encrypted_fields_from_driver(string $databaseName, string $collectionName, Manager $manager): array|object|null
{
$encryptedFieldsMap = (array) $manager->getEncryptedFieldsMap();
return $encryptedFieldsMap[$databaseName . '.' . $collectionName] ?? null;
}
/**
* Return a collection's encryptedFields option from the server (if any).
*
* @internal
* @see https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/client-side-encryption.rst#collection-encryptedfields-lookup-getencryptedfields
* @see Collection::drop()
* @see Database::dropCollection()
*/
function get_encrypted_fields_from_server(string $databaseName, string $collectionName, Server $server): array|object|null
{
$collectionInfoIterator = (new ListCollections($databaseName, ['filter' => ['name' => $collectionName]]))->execute($server);
foreach ($collectionInfoIterator as $collectionInfo) {
/* Note: ListCollections applies a typeMap that converts BSON documents
* to PHP arrays. This should not be problematic as encryptedFields here
* is only used by drop helpers to obtain names of supporting encryption
* collections. */
return $collectionInfo['options']['encryptedFields'] ?? null;
}
return null;
}
/**
* Returns whether a given value is a valid document.
*
* This method returns true for any array or object, but specifically excludes
* BSON PackedArray instances
*
* @internal
*/
function is_document(mixed $document): bool
{
return is_array($document) || (is_object($document) && ! $document instanceof PackedArray);
}
/**
* Return whether the first key in the document starts with a "$" character.
*
* This is used for validating aggregation pipeline stages and differentiating
* update and replacement documents. Since true and false return values may be
* expected in different contexts, this function intentionally throws if
* $document has an unexpected type instead of returning false.
*
* @internal
* @throws InvalidArgumentException if $document is not an array or object
*/
function is_first_key_operator(array|object $document): bool
{
if ($document instanceof PackedArray) {
return false;
}
$document = document_to_array($document);
$firstKey = array_key_first($document);
if (! is_string($firstKey)) {
return false;
}
return '$' === ($firstKey[0] ?? null);
}
/**
* Returns whether the argument is a valid aggregation or update pipeline.
*
* This is primarily used for validating arguments for update and replace
* operations, but can also be used for validating an aggregation pipeline.
*
* The $allowEmpty parameter can be used to control whether an empty array
* should be considered a valid pipeline. Empty arrays are generally valid for
* an aggregation pipeline, but the things are more complicated for update
* pipelines.
*
* Update operations must prohibit empty pipelines, since libmongoc may encode
* an empty pipeline array as an empty replacement document when writing an
* update command (arrays and documents have the same bson_t representation).
* For consistency, findOneAndUpdate should also prohibit empty pipelines.
* Replace operations (e.g. replaceOne, findOneAndReplace) should reject empty
* and non-empty pipelines alike, since neither is a replacement document.
*
* Note: this method may propagate an InvalidArgumentException from
* document_or_array() if a Serializable object within the pipeline array
* returns a non-array, non-object value from its bsonSerialize() method.
*
* @internal
* @throws InvalidArgumentException
*/
function is_pipeline(array|object $pipeline, bool $allowEmpty = false): bool
{
if ($pipeline instanceof PackedArray) {
/* Nested documents and arrays are intentionally left as BSON. We avoid
* iterator_to_array() since PackedArray iteration returns all values as
* MongoDB\BSON\Value instances. */
/** @psalm-var array */
$pipeline = $pipeline->toPHP([
'array' => 'bson',
'document' => 'bson',
'root' => 'array',
]);
} elseif ($pipeline instanceof Serializable) {
$pipeline = $pipeline->bsonSerialize();
}
if (! is_array($pipeline)) {
return false;
}
if ($pipeline === []) {
return $allowEmpty;
}
if (! array_is_list($pipeline)) {
return false;
}
foreach ($pipeline as $stage) {
if (! is_document($stage)) {
return false;
}
if (! is_first_key_operator($stage)) {
return false;
}
}
return true;
}
/**
* Returns whether the argument is a list that contains at least one
* {@see StageInterface} object.
*
* @internal
*/
function is_builder_pipeline(array $pipeline): bool
{
if (! $pipeline || ! array_is_list($pipeline)) {
return false;
}
foreach ($pipeline as $stage) {
if (is_object($stage) && $stage instanceof StageInterface) {
return true;
}
}
return false;
}
/**
* Returns whether we are currently in a transaction.
*
* @internal
* @param array $options Command options
*/
function is_in_transaction(array $options): bool
{
if (isset($options['session']) && $options['session'] instanceof Session && $options['session']->isInTransaction()) {
return true;
}
return false;
}
/**
* Return whether the aggregation pipeline ends with an $out or $merge operator.
*
* This is used for determining whether the aggregation pipeline must be
* executed against a primary server.
*
* @internal
* @param array $pipeline Aggregation pipeline
*/
function is_last_pipeline_operator_write(array $pipeline): bool
{
$lastOp = end($pipeline);
if ($lastOp === false) {
return false;
}
if (! is_array($lastOp) && ! is_object($lastOp)) {
return false;
}
$key = array_key_first(document_to_array($lastOp));
return $key === '$merge' || $key === '$out';
}
/**
* Return whether the write concern is acknowledged.
*
* This function is similar to mongoc_write_concern_is_acknowledged but does not
* check the fsync option since that was never supported in the PHP driver.
*
* @internal
* @see https://mongodb.com/docs/manual/reference/write-concern/
*/
function is_write_concern_acknowledged(WriteConcern $writeConcern): bool
{
/* Note: -1 corresponds to MONGOC_WRITE_CONCERN_W_ERRORS_IGNORED, which is
* deprecated synonym of MONGOC_WRITE_CONCERN_W_UNACKNOWLEDGED and slated
* for removal in libmongoc 2.0. */
return ($writeConcern->getW() !== 0 && $writeConcern->getW() !== -1) || $writeConcern->getJournal() === true;
}
/**
* Return whether the server supports a particular feature.
*
* @internal
* @param Server $server Server to check
* @param integer $feature Feature constant (i.e. wire protocol version)
*/
function server_supports_feature(Server $server, int $feature): bool
{
$info = $server->getInfo();
$maxWireVersion = isset($info['maxWireVersion']) ? (integer) $info['maxWireVersion'] : 0;
$minWireVersion = isset($info['minWireVersion']) ? (integer) $info['minWireVersion'] : 0;
return $minWireVersion <= $feature && $maxWireVersion >= $feature;
}
/**
* Return whether the input is an array of strings.
*
* @internal
*/
function is_string_array(mixed $input): bool
{
if (! is_array($input)) {
return false;
}
foreach ($input as $item) {
if (! is_string($item)) {
return false;
}
}
return true;
}
/**
* Performs a deep copy of a value.
*
* This function will clone objects and recursively copy values within arrays.
*
* @internal
* @see https://bugs.php.net/bug.php?id=49664
* @param mixed $element Value to be copied
* @throws ReflectionException
*/
function recursive_copy(mixed $element): mixed
{
if (is_array($element)) {
foreach ($element as $key => $value) {
$element[$key] = recursive_copy($value);
}
return $element;
}
if (! is_object($element)) {
return $element;
}
if (! (new ReflectionClass($element))->isCloneable()) {
return $element;
}
return clone $element;
}
/**
* Creates a type map to apply to a field type
*
* This is used in the Aggregate, Distinct, and FindAndModify operations to
* apply the root-level type map to the document that will be returned. It also
* replaces the root type with object for consistency within these operations
*
* An existing type map for the given field path will not be overwritten
*
* @internal
* @param array $typeMap The existing typeMap
* @param string $fieldPath The field path to apply the root type to
*/
function create_field_path_type_map(array $typeMap, string $fieldPath): array
{
// If some field paths already exist, we prefix them with the field path we are assuming as the new root
if (isset($typeMap['fieldPaths']) && is_array($typeMap['fieldPaths'])) {
$fieldPaths = $typeMap['fieldPaths'];
$typeMap['fieldPaths'] = [];
foreach ($fieldPaths as $existingFieldPath => $type) {
$typeMap['fieldPaths'][$fieldPath . '.' . $existingFieldPath] = $type;
}
}
// If a root typemap was set, apply this to the field object
if (isset($typeMap['root'])) {
$typeMap['fieldPaths'][$fieldPath] = $typeMap['root'];
}
/* Special case if we want to convert an array, in which case we need to
* ensure that the field containing the array is exposed as an array,
* instead of the type given in the type map's array key. */
if (str_ends_with($fieldPath, '.$')) {
$typeMap['fieldPaths'][substr($fieldPath, 0, -2)] = 'array';
}
$typeMap['root'] = 'object';
return $typeMap;
}
/**
* Execute a callback within a transaction in the given session
*
* This helper takes care of retrying the commit operation or the entire
* transaction if an error occurs.
*
* If the commit fails because of an UnknownTransactionCommitResult error, the
* commit is retried without re-invoking the callback.
* If the commit fails because of a TransientTransactionError, the entire
* transaction will be retried. In this case, the callback will be invoked
* again. It is important that the logic inside the callback is idempotent.
*
* In case of failures, the commit or transaction are retried until 120 seconds
* from the initial call have elapsed. After that, no retries will happen and
* the helper will throw the last exception received from the driver.
*
* @see Client::startSession()
* @see Session::startTransaction() for supported transaction options
*
* @param Session $session A session object as retrieved by Client::startSession
* @param callable $callback A callback that will be invoked within the transaction
* @param array $transactionOptions Additional options that are passed to Session::startTransaction
* @throws RuntimeException for driver errors while committing the transaction
* @throws Exception for any other errors, including those thrown in the callback
*/
function with_transaction(Session $session, callable $callback, array $transactionOptions = []): void
{
$operation = new WithTransaction($callback, $transactionOptions);
$operation->execute($session);
}
/**
* Returns the session option if it is set and valid.
*
* @internal
*/
function extract_session_from_options(array $options): ?Session
{
if (isset($options['session']) && $options['session'] instanceof Session) {
return $options['session'];
}
return null;
}
/**
* Returns the readPreference option if it is set and valid.
*
* @internal
*/
function extract_read_preference_from_options(array $options): ?ReadPreference
{
if (isset($options['readPreference']) && $options['readPreference'] instanceof ReadPreference) {
return $options['readPreference'];
}
return null;
}
/**
* Performs server selection, respecting the readPreference and session options.
*
* The pinned server for an active transaction takes priority, followed by an
* operation-level read preference, followed by an active transaction's read
* preference, followed by a primary read preference.
*
* @internal
*/
function select_server(Manager $manager, array $options): Server
{
$session = extract_session_from_options($options);
$server = $session instanceof Session ? $session->getServer() : null;
// Pinned server for an active transaction takes priority
if ($server !== null) {
return $server;
}
// Operation read preference takes priority
$readPreference = extract_read_preference_from_options($options);
// Read preference for an active transaction takes priority
if ($readPreference === null && $session instanceof Session && $session->isInTransaction()) {
/* Session::getTransactionOptions() should always return an array if the
* session is in a transaction, but we can be defensive. */
$readPreference = extract_read_preference_from_options($session->getTransactionOptions() ?? []);
}
// Manager::selectServer() defaults to a primary read preference
return $manager->selectServer($readPreference);
}
/**
* Performs server selection for an aggregate operation with a write stage. The
* $options parameter may be modified by reference if a primary read preference
* must be forced due to the existence of pre-5.0 servers in the topology.
*
* @internal
* @see https://github.com/mongodb/specifications/blob/master/source/crud/crud.rst#aggregation-pipelines-with-write-stages
*/
function select_server_for_aggregate_write_stage(Manager $manager, array &$options): Server
{
$readPreference = extract_read_preference_from_options($options);
/* If there is either no read preference or a primary read preference, there
* is no special server selection logic to apply.
*
* Note: an alternative read preference could still be inherited from an
* active transaction's options, but we can rely on libmongoc to raise a
* "read preference in a transaction must be primary" error if necessary. */
if ($readPreference === null || $readPreference->getModeString() === ReadPreference::PRIMARY) {
return select_server($manager, $options);
}
$server = null;
$serverSelectionError = null;
try {
$server = select_server($manager, $options);
} catch (DriverRuntimeException $serverSelectionError) {
}
/* If any pre-5.0 servers exist in the topology, force a primary read
* preference and repeat server selection if it previously failed or
* selected a secondary. */
if (! all_servers_support_write_stage_on_secondary($manager->getServers())) {
$options['readPreference'] = new ReadPreference(ReadPreference::PRIMARY);
if ($server === null || $server->isSecondary()) {
return select_server($manager, $options);
}
}
/* If the topology only contains 5.0+ servers, we should either return the
* previously selected server or propagate the server selection error. */
if ($serverSelectionError !== null) {
throw $serverSelectionError;
}
assert($server instanceof Server);
return $server;
}
/**
* Performs server selection for a write operation.
*
* The pinned server for an active transaction takes priority, followed by an
* operation-level read preference, followed by a primary read preference. This
* is similar to select_server() except that it ignores a read preference from
* an active transaction's options.
*
* @internal
*/
function select_server_for_write(Manager $manager, array $options): Server
{
return select_server($manager, $options + ['readPreference' => new ReadPreference(ReadPreference::PRIMARY)]);
}
|
| #1 | MongoDB\select_server /srv/ChatHispanoEngine/releases/20250927141530/vendor/mongodb/mongodb/src/Collection.php (302) <?php
/*
* Copyright 2015-present MongoDB, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace MongoDB;
use Countable;
use Iterator;
use MongoDB\BSON\Document;
use MongoDB\BSON\PackedArray;
use MongoDB\Builder\BuilderEncoder;
use MongoDB\Builder\Pipeline;
use MongoDB\Codec\DocumentCodec;
use MongoDB\Codec\Encoder;
use MongoDB\Driver\CursorInterface;
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
use MongoDB\Driver\Manager;
use MongoDB\Driver\ReadConcern;
use MongoDB\Driver\ReadPreference;
use MongoDB\Driver\WriteConcern;
use MongoDB\Exception\InvalidArgumentException;
use MongoDB\Exception\UnexpectedValueException;
use MongoDB\Exception\UnsupportedException;
use MongoDB\Model\BSONArray;
use MongoDB\Model\BSONDocument;
use MongoDB\Model\IndexInfo;
use MongoDB\Operation\Aggregate;
use MongoDB\Operation\BulkWrite;
use MongoDB\Operation\Count;
use MongoDB\Operation\CountDocuments;
use MongoDB\Operation\CreateIndexes;
use MongoDB\Operation\CreateSearchIndexes;
use MongoDB\Operation\DeleteMany;
use MongoDB\Operation\DeleteOne;
use MongoDB\Operation\Distinct;
use MongoDB\Operation\DropCollection;
use MongoDB\Operation\DropEncryptedCollection;
use MongoDB\Operation\DropIndexes;
use MongoDB\Operation\DropSearchIndex;
use MongoDB\Operation\EstimatedDocumentCount;
use MongoDB\Operation\Explain;
use MongoDB\Operation\Explainable;
use MongoDB\Operation\Find;
use MongoDB\Operation\FindOne;
use MongoDB\Operation\FindOneAndDelete;
use MongoDB\Operation\FindOneAndReplace;
use MongoDB\Operation\FindOneAndUpdate;
use MongoDB\Operation\InsertMany;
use MongoDB\Operation\InsertOne;
use MongoDB\Operation\ListIndexes;
use MongoDB\Operation\ListSearchIndexes;
use MongoDB\Operation\RenameCollection;
use MongoDB\Operation\ReplaceOne;
use MongoDB\Operation\UpdateMany;
use MongoDB\Operation\UpdateOne;
use MongoDB\Operation\UpdateSearchIndex;
use MongoDB\Operation\Watch;
use stdClass;
use function array_diff_key;
use function array_intersect_key;
use function array_key_exists;
use function current;
use function is_array;
use function is_bool;
use function strlen;
class Collection
{
private const DEFAULT_TYPE_MAP = [
'array' => BSONArray::class,
'document' => BSONDocument::class,
'root' => BSONDocument::class,
];
private const WIRE_VERSION_FOR_READ_CONCERN_WITH_WRITE_STAGE = 8;
/** @psalm-var Encoder<array|stdClass|Document|PackedArray, mixed> */
private readonly Encoder $builderEncoder;
private ?DocumentCodec $codec = null;
private ReadConcern $readConcern;
private ReadPreference $readPreference;
private array $typeMap;
private WriteConcern $writeConcern;
private bool $autoEncryptionEnabled;
/**
* Constructs new Collection instance.
*
* This class provides methods for collection-specific operations, such as
* CRUD (i.e. create, read, update, and delete) and index management.
*
* Supported options:
*
* * builderEncoder (MongoDB\Codec\Encoder): Encoder for query and
* aggregation builders. If not given, the default encoder will be used.
*
* * codec (MongoDB\Codec\DocumentCodec): Codec used to decode documents
* from BSON to PHP objects.
*
* * readConcern (MongoDB\Driver\ReadConcern): The default read concern to
* use for collection operations. Defaults to the Manager's read concern.
*
* * readPreference (MongoDB\Driver\ReadPreference): The default read
* preference to use for collection operations. Defaults to the Manager's
* read preference.
*
* * typeMap (array): Default type map for cursors and BSON documents.
*
* * writeConcern (MongoDB\Driver\WriteConcern): The default write concern
* to use for collection operations. Defaults to the Manager's write
* concern.
*
* @param Manager $manager Manager instance from the driver
* @param string $databaseName Database name
* @param string $collectionName Collection name
* @param array $options Collection options
* @throws InvalidArgumentException for parameter/option parsing errors
*/
public function __construct(private Manager $manager, private string $databaseName, private string $collectionName, array $options = [])
{
if (strlen($databaseName) < 1) {
throw new InvalidArgumentException('$databaseName is invalid: ' . $databaseName);
}
if (strlen($collectionName) < 1) {
throw new InvalidArgumentException('$collectionName is invalid: ' . $collectionName);
}
if (isset($options['builderEncoder']) && ! $options['builderEncoder'] instanceof Encoder) {
throw InvalidArgumentException::invalidType('"builderEncoder" option', $options['builderEncoder'], Encoder::class);
}
if (isset($options['codec']) && ! $options['codec'] instanceof DocumentCodec) {
throw InvalidArgumentException::invalidType('"codec" option', $options['codec'], DocumentCodec::class);
}
if (isset($options['readConcern']) && ! $options['readConcern'] instanceof ReadConcern) {
throw InvalidArgumentException::invalidType('"readConcern" option', $options['readConcern'], ReadConcern::class);
}
if (isset($options['readPreference']) && ! $options['readPreference'] instanceof ReadPreference) {
throw InvalidArgumentException::invalidType('"readPreference" option', $options['readPreference'], ReadPreference::class);
}
if (isset($options['typeMap']) && ! is_array($options['typeMap'])) {
throw InvalidArgumentException::invalidType('"typeMap" option', $options['typeMap'], 'array');
}
if (isset($options['writeConcern']) && ! $options['writeConcern'] instanceof WriteConcern) {
throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], WriteConcern::class);
}
if (isset($options['autoEncryptionEnabled']) && ! is_bool($options['autoEncryptionEnabled'])) {
throw InvalidArgumentException::invalidType('"autoEncryptionEnabled" option', $options['autoEncryptionEnabled'], 'boolean');
}
$this->builderEncoder = $options['builderEncoder'] ?? new BuilderEncoder();
$this->codec = $options['codec'] ?? null;
$this->readConcern = $options['readConcern'] ?? $this->manager->getReadConcern();
$this->readPreference = $options['readPreference'] ?? $this->manager->getReadPreference();
$this->typeMap = $options['typeMap'] ?? self::DEFAULT_TYPE_MAP;
$this->writeConcern = $options['writeConcern'] ?? $this->manager->getWriteConcern();
$this->autoEncryptionEnabled = $options['autoEncryptionEnabled'] ?? false;
}
/**
* Return internal properties for debugging purposes.
*
* @see https://php.net/manual/en/language.oop5.magic.php#language.oop5.magic.debuginfo
*/
public function __debugInfo(): array
{
return [
'builderEncoder' => $this->builderEncoder,
'codec' => $this->codec,
'collectionName' => $this->collectionName,
'databaseName' => $this->databaseName,
'manager' => $this->manager,
'readConcern' => $this->readConcern,
'readPreference' => $this->readPreference,
'typeMap' => $this->typeMap,
'writeConcern' => $this->writeConcern,
];
}
/**
* Return the collection namespace (e.g. "db.collection").
*
* @see https://mongodb.com/docs/manual/core/databases-and-collections/
*/
public function __toString(): string
{
return $this->databaseName . '.' . $this->collectionName;
}
/**
* Executes an aggregation framework pipeline on the collection.
*
* @see Aggregate::__construct() for supported options
* @param array|Pipeline $pipeline Aggregation pipeline
* @param array $options Command options
* @throws UnexpectedValueException if the command response was malformed
* @throws UnsupportedException if options are not supported by the selected server
* @throws InvalidArgumentException for parameter/option parsing errors
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
*/
public function aggregate(array|Pipeline $pipeline, array $options = []): CursorInterface
{
if (is_array($pipeline) && is_builder_pipeline($pipeline)) {
$pipeline = new Pipeline(...$pipeline);
}
$pipeline = $this->builderEncoder->encodeIfSupported($pipeline);
$hasWriteStage = is_last_pipeline_operator_write($pipeline);
$options = $this->inheritReadPreference($options);
$server = $hasWriteStage
? select_server_for_aggregate_write_stage($this->manager, $options)
: select_server($this->manager, $options);
/* MongoDB 4.2 and later supports a read concern when an $out stage is
* being used, but earlier versions do not.
*/
if (! $hasWriteStage || server_supports_feature($server, self::WIRE_VERSION_FOR_READ_CONCERN_WITH_WRITE_STAGE)) {
$options = $this->inheritReadConcern($options);
}
$options = $this->inheritCodecOrTypeMap($options);
if ($hasWriteStage) {
$options = $this->inheritWriteOptions($options);
}
$operation = new Aggregate($this->databaseName, $this->collectionName, $pipeline, $options);
return $operation->execute($server);
}
/**
* Executes multiple write operations.
*
* @see BulkWrite::__construct() for supported options
* @param array[] $operations List of write operations
* @param array $options Command options
* @throws UnsupportedException if options are not supported by the selected server
* @throws InvalidArgumentException for parameter/option parsing errors
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
*/
public function bulkWrite(array $operations, array $options = []): BulkWriteResult
{
$options = $this->inheritBuilderEncoder($options);
$options = $this->inheritWriteOptions($options);
$options = $this->inheritCodec($options);
$operation = new BulkWrite($this->databaseName, $this->collectionName, $operations, $options);
return $operation->execute(select_server_for_write($this->manager, $options));
}
/**
* Gets the number of documents matching the filter.
*
* @see Count::__construct() for supported options
* @param array|object $filter Query by which to filter documents
* @param array $options Command options
* @throws UnexpectedValueException if the command response was malformed
* @throws UnsupportedException if options are not supported by the selected server
* @throws InvalidArgumentException for parameter/option parsing errors
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
*
* @deprecated 1.4
*/
public function count(array|object $filter = [], array $options = []): int
{
$filter = $this->builderEncoder->encodeIfSupported($filter);
$options = $this->inheritReadOptions($options);
$operation = new Count($this->databaseName, $this->collectionName, $filter, $options);
return $operation->execute(select_server($this->manager, $options));
}
/**
* Gets the number of documents matching the filter.
*
* @see CountDocuments::__construct() for supported options
* @param array|object $filter Query by which to filter documents
* @param array $options Command options
* @throws UnexpectedValueException if the command response was malformed
* @throws UnsupportedException if options are not supported by the selected server
* @throws InvalidArgumentException for parameter/option parsing errors
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
*/
public function countDocuments(array|object $filter = [], array $options = []): int
{
$filter = $this->builderEncoder->encodeIfSupported($filter);
$options = $this->inheritReadOptions($options);
$operation = new CountDocuments($this->databaseName, $this->collectionName, $filter, $options);
return $operation->execute(select_server($this->manager, $options));
}
/**
* Create a single index for the collection.
*
* @see Collection::createIndexes()
* @see CreateIndexes::__construct() for supported command options
* @param array|object $key Document containing fields mapped to values,
* which denote order or an index type
* @param array $options Index and command options
* @return string The name of the created index
* @throws UnsupportedException if options are not supported by the selected server
* @throws InvalidArgumentException for parameter/option parsing errors
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
*/
public function createIndex(array|object $key, array $options = []): string
{
$operationOptionKeys = ['comment' => 1, 'commitQuorum' => 1, 'maxTimeMS' => 1, 'session' => 1, 'writeConcern' => 1];
$indexOptions = array_diff_key($options, $operationOptionKeys);
$operationOptions = array_intersect_key($options, $operationOptionKeys);
return current($this->createIndexes([['key' => $key] + $indexOptions], $operationOptions));
}
/**
* Create one or more indexes for the collection.
*
* Each element in the $indexes array must have a "key" document, which
* contains fields mapped to an order or type. Other options may follow.
* For example:
*
* $indexes = [
* // Create a unique index on the "username" field
* [ 'key' => [ 'username' => 1 ], 'unique' => true ],
* // Create a 2dsphere index on the "loc" field with a custom name
* [ 'key' => [ 'loc' => '2dsphere' ], 'name' => 'geo' ],
* ];
*
* If the "name" option is unspecified, a name will be generated from the
* "key" document.
*
* @see https://mongodb.com/docs/manual/reference/command/createIndexes/
* @see https://mongodb.com/docs/manual/reference/method/db.collection.createIndex/
* @see CreateIndexes::__construct() for supported command options
* @param array[] $indexes List of index specifications
* @param array $options Command options
* @return string[] The names of the created indexes
* @throws UnsupportedException if options are not supported by the selected server
* @throws InvalidArgumentException for parameter/option parsing errors
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
*/
public function createIndexes(array $indexes, array $options = []): array
{
$options = $this->inheritWriteOptions($options);
$operation = new CreateIndexes($this->databaseName, $this->collectionName, $indexes, $options);
return $operation->execute(select_server_for_write($this->manager, $options));
}
/**
* Create an Atlas Search index for the collection.
* Only available when used against a 7.0+ Atlas cluster.
*
* @see https://www.mongodb.com/docs/manual/reference/command/createSearchIndexes/
* @see https://mongodb.com/docs/manual/reference/method/db.collection.createSearchIndex/
* @param array|object $definition Atlas Search index mapping definition
* @param array{comment?: mixed, name?: string, type?: string} $options Index and command options
* @return string The name of the created search index
* @throws UnsupportedException if options are not supported by the selected server
* @throws InvalidArgumentException for parameter/option parsing errors
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
*/
public function createSearchIndex(array|object $definition, array $options = []): string
{
$indexOptionKeys = ['name' => 1, 'type' => 1];
/** @psalm-var array{name?: string, type?: string} */
$indexOptions = array_intersect_key($options, $indexOptionKeys);
/** @psalm-var array{comment?: mixed} */
$operationOptions = array_diff_key($options, $indexOptionKeys);
$names = $this->createSearchIndexes([['definition' => $definition] + $indexOptions], $operationOptions);
return current($names);
}
/**
* Create one or more Atlas Search indexes for the collection.
* Only available when used against a 7.0+ Atlas cluster.
*
* Each element in the $indexes array must have "definition" document and they may have a "name" string.
* The name can be omitted for a single index, in which case a name will be the default.
* For example:
*
* $indexes = [
* // Create a search index with the default name on a single field
* ['definition' => ['mappings' => ['dynamic' => false, 'fields' => ['title' => ['type' => 'string']]]]],
* // Create a named search index on all fields
* ['name' => 'search_all', 'definition' => ['mappings' => ['dynamic' => true]]],
* ];
*
* @see https://www.mongodb.com/docs/manual/reference/command/createSearchIndexes/
* @see https://mongodb.com/docs/manual/reference/method/db.collection.createSearchIndex/
* @param list<array{definition: array|object, name?: string, type?: string}> $indexes List of search index specifications
* @param array{comment?: mixed} $options Command options
* @return string[] The names of the created search indexes
* @throws UnsupportedException if options are not supported by the selected server
* @throws InvalidArgumentException for parameter/option parsing errors
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
*/
public function createSearchIndexes(array $indexes, array $options = []): array
{
$operation = new CreateSearchIndexes($this->databaseName, $this->collectionName, $indexes, $options);
$server = select_server_for_write($this->manager, $options);
return $operation->execute($server);
}
/**
* Deletes all documents matching the filter.
*
* @see DeleteMany::__construct() for supported options
* @see https://mongodb.com/docs/manual/reference/command/delete/
* @param array|object $filter Query by which to delete documents
* @param array $options Command options
* @throws UnsupportedException if options are not supported by the selected server
* @throws InvalidArgumentException for parameter/option parsing errors
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
*/
public function deleteMany(array|object $filter, array $options = []): DeleteResult
{
$filter = $this->builderEncoder->encodeIfSupported($filter);
$options = $this->inheritWriteOptions($options);
$operation = new DeleteMany($this->databaseName, $this->collectionName, $filter, $options);
return $operation->execute(select_server_for_write($this->manager, $options));
}
/**
* Deletes at most one document matching the filter.
*
* @see DeleteOne::__construct() for supported options
* @see https://mongodb.com/docs/manual/reference/command/delete/
* @param array|object $filter Query by which to delete documents
* @param array $options Command options
* @throws UnsupportedException if options are not supported by the selected server
* @throws InvalidArgumentException for parameter/option parsing errors
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
*/
public function deleteOne(array|object $filter, array $options = []): DeleteResult
{
$filter = $this->builderEncoder->encodeIfSupported($filter);
$options = $this->inheritWriteOptions($options);
$operation = new DeleteOne($this->databaseName, $this->collectionName, $filter, $options);
return $operation->execute(select_server_for_write($this->manager, $options));
}
/**
* Finds the distinct values for a specified field across the collection.
*
* @see Distinct::__construct() for supported options
* @param string $fieldName Field for which to return distinct values
* @param array|object $filter Query by which to filter documents
* @param array $options Command options
* @throws UnexpectedValueException if the command response was malformed
* @throws UnsupportedException if options are not supported by the selected server
* @throws InvalidArgumentException for parameter/option parsing errors
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
*/
public function distinct(string $fieldName, array|object $filter = [], array $options = []): array
{
$filter = $this->builderEncoder->encodeIfSupported($filter);
$options = $this->inheritReadOptions($options);
$options = $this->inheritTypeMap($options);
$operation = new Distinct($this->databaseName, $this->collectionName, $fieldName, $filter, $options);
return $operation->execute(select_server($this->manager, $options));
}
/**
* Drop this collection.
*
* @see DropCollection::__construct() for supported options
* @param array $options Additional options
* @throws UnsupportedException if options are not supported by the selected server
* @throws InvalidArgumentException for parameter/option parsing errors
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
*/
public function drop(array $options = []): void
{
$options = $this->inheritWriteOptions($options);
$server = select_server_for_write($this->manager, $options);
if ($this->autoEncryptionEnabled && ! isset($options['encryptedFields'])) {
$options['encryptedFields'] = get_encrypted_fields_from_driver($this->databaseName, $this->collectionName, $this->manager)
?? get_encrypted_fields_from_server($this->databaseName, $this->collectionName, $server);
}
$operation = isset($options['encryptedFields'])
? new DropEncryptedCollection($this->databaseName, $this->collectionName, $options)
: new DropCollection($this->databaseName, $this->collectionName, $options);
$operation->execute($server);
}
/**
* Drop a single index in the collection.
*
* @see DropIndexes::__construct() for supported options
* @param string|IndexInfo $indexName Index name or model object
* @param array $options Additional options
* @throws UnsupportedException if options are not supported by the selected server
* @throws InvalidArgumentException for parameter/option parsing errors
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
*/
public function dropIndex(string|IndexInfo $indexName, array $options = []): void
{
$indexName = (string) $indexName;
if ($indexName === '*') {
throw new InvalidArgumentException('dropIndexes() must be used to drop multiple indexes');
}
$options = $this->inheritWriteOptions($options);
$operation = new DropIndexes($this->databaseName, $this->collectionName, $indexName, $options);
$operation->execute(select_server_for_write($this->manager, $options));
}
/**
* Drop all indexes in the collection.
*
* @see DropIndexes::__construct() for supported options
* @param array $options Additional options
* @throws UnsupportedException if options are not supported by the selected server
* @throws InvalidArgumentException for parameter/option parsing errors
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
*/
public function dropIndexes(array $options = []): void
{
$options = $this->inheritWriteOptions($options);
$operation = new DropIndexes($this->databaseName, $this->collectionName, '*', $options);
$operation->execute(select_server_for_write($this->manager, $options));
}
/**
* Drop a single Atlas Search index in the collection.
* Only available when used against a 7.0+ Atlas cluster.
*
* @param string $name Search index name
* @param array{comment?: mixed} $options Additional options
* @throws UnsupportedException if options are not supported by the selected server
* @throws InvalidArgumentException for parameter/option parsing errors
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
*/
public function dropSearchIndex(string $name, array $options = []): void
{
$operation = new DropSearchIndex($this->databaseName, $this->collectionName, $name);
$server = select_server_for_write($this->manager, $options);
$operation->execute($server);
}
/**
* Gets an estimated number of documents in the collection using the collection metadata.
*
* @see EstimatedDocumentCount::__construct() for supported options
* @param array $options Command options
* @throws UnexpectedValueException if the command response was malformed
* @throws UnsupportedException if options are not supported by the selected server
* @throws InvalidArgumentException for parameter/option parsing errors
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
*/
public function estimatedDocumentCount(array $options = []): int
{
$options = $this->inheritReadOptions($options);
$operation = new EstimatedDocumentCount($this->databaseName, $this->collectionName, $options);
return $operation->execute(select_server($this->manager, $options));
}
/**
* Explains explainable commands.
*
* @see Explain::__construct() for supported options
* @see https://mongodb.com/docs/manual/reference/command/explain/
* @param Explainable $explainable Command on which to run explain
* @param array $options Additional options
* @throws UnsupportedException if explainable or options are not supported by the selected server
* @throws InvalidArgumentException for parameter/option parsing errors
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
*/
public function explain(Explainable $explainable, array $options = []): array|object
{
$options = $this->inheritReadPreference($options);
$options = $this->inheritTypeMap($options);
$operation = new Explain($this->databaseName, $explainable, $options);
return $operation->execute(select_server($this->manager, $options));
}
/**
* Finds documents matching the query.
*
* @see Find::__construct() for supported options
* @see https://mongodb.com/docs/manual/crud/#read-operations
* @param array|object $filter Query by which to filter documents
* @param array $options Additional options
* @throws UnsupportedException if options are not supported by the selected server
* @throws InvalidArgumentException for parameter/option parsing errors
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
*/
public function find(array|object $filter = [], array $options = []): CursorInterface
{
$filter = $this->builderEncoder->encodeIfSupported($filter);
$options = $this->inheritReadOptions($options);
$options = $this->inheritCodecOrTypeMap($options);
$operation = new Find($this->databaseName, $this->collectionName, $filter, $options);
return $operation->execute(select_server($this->manager, $options));
}
/**
* Finds a single document matching the query.
*
* @see FindOne::__construct() for supported options
* @see https://mongodb.com/docs/manual/crud/#read-operations
* @param array|object $filter Query by which to filter documents
* @param array $options Additional options
* @throws UnsupportedException if options are not supported by the selected server
* @throws InvalidArgumentException for parameter/option parsing errors
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
*/
public function findOne(array|object $filter = [], array $options = []): array|object|null
{
$filter = $this->builderEncoder->encodeIfSupported($filter);
$options = $this->inheritReadOptions($options);
$options = $this->inheritCodecOrTypeMap($options);
$operation = new FindOne($this->databaseName, $this->collectionName, $filter, $options);
return $operation->execute(select_server($this->manager, $options));
}
/**
* Finds a single document and deletes it, returning the original.
*
* The document to return may be null if no document matched the filter.
*
* @see FindOneAndDelete::__construct() for supported options
* @see https://mongodb.com/docs/manual/reference/command/findAndModify/
* @param array|object $filter Query by which to filter documents
* @param array $options Command options
* @throws UnexpectedValueException if the command response was malformed
* @throws UnsupportedException if options are not supported by the selected server
* @throws InvalidArgumentException for parameter/option parsing errors
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
*/
public function findOneAndDelete(array|object $filter, array $options = []): array|object|null
{
$filter = $this->builderEncoder->encodeIfSupported($filter);
$options = $this->inheritWriteOptions($options);
$options = $this->inheritCodecOrTypeMap($options);
$operation = new FindOneAndDelete($this->databaseName, $this->collectionName, $filter, $options);
return $operation->execute(select_server_for_write($this->manager, $options));
}
/**
* Finds a single document and replaces it, returning either the original or
* the replaced document.
*
* The document to return may be null if no document matched the filter. By
* default, the original document is returned. Specify
* FindOneAndReplace::RETURN_DOCUMENT_AFTER for the "returnDocument" option
* to return the updated document.
*
* @see FindOneAndReplace::__construct() for supported options
* @see https://mongodb.com/docs/manual/reference/command/findAndModify/
* @param array|object $filter Query by which to filter documents
* @param array|object $replacement Replacement document
* @param array $options Command options
* @throws UnexpectedValueException if the command response was malformed
* @throws UnsupportedException if options are not supported by the selected server
* @throws InvalidArgumentException for parameter/option parsing errors
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
*/
public function findOneAndReplace(array|object $filter, array|object $replacement, array $options = []): array|object|null
{
$filter = $this->builderEncoder->encodeIfSupported($filter);
$options = $this->inheritWriteOptions($options);
$options = $this->inheritCodecOrTypeMap($options);
$operation = new FindOneAndReplace($this->databaseName, $this->collectionName, $filter, $replacement, $options);
return $operation->execute(select_server_for_write($this->manager, $options));
}
/**
* Finds a single document and updates it, returning either the original or
* the updated document.
*
* The document to return may be null if no document matched the filter. By
* default, the original document is returned. Specify
* FindOneAndUpdate::RETURN_DOCUMENT_AFTER for the "returnDocument" option
* to return the updated document.
*
* @see FindOneAndReplace::__construct() for supported options
* @see https://mongodb.com/docs/manual/reference/command/findAndModify/
* @param array|object $filter Query by which to filter documents
* @param array|object $update Update to apply to the matched document
* @param array $options Command options
* @throws UnexpectedValueException if the command response was malformed
* @throws UnsupportedException if options are not supported by the selected server
* @throws InvalidArgumentException for parameter/option parsing errors
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
*/
public function findOneAndUpdate(array|object $filter, array|object $update, array $options = []): array|object|null
{
$filter = $this->builderEncoder->encodeIfSupported($filter);
$options = $this->inheritWriteOptions($options);
$options = $this->inheritCodecOrTypeMap($options);
$operation = new FindOneAndUpdate($this->databaseName, $this->collectionName, $filter, $update, $options);
return $operation->execute(select_server_for_write($this->manager, $options));
}
/** @psalm-return Encoder<array|stdClass|Document|PackedArray, mixed> */
public function getBuilderEncoder(): Encoder
{
return $this->builderEncoder;
}
public function getCodec(): ?DocumentCodec
{
return $this->codec;
}
/**
* Return the collection name.
*/
public function getCollectionName(): string
{
return $this->collectionName;
}
/**
* Return the database name.
*/
public function getDatabaseName(): string
{
return $this->databaseName;
}
/**
* Return the Manager.
*/
public function getManager(): Manager
{
return $this->manager;
}
/**
* Return the collection namespace.
*
* @see https://mongodb.com/docs/manual/reference/glossary/#term-namespace
*/
public function getNamespace(): string
{
return $this->databaseName . '.' . $this->collectionName;
}
/**
* Return the read concern for this collection.
*
* @see https://php.net/manual/en/mongodb-driver-readconcern.isdefault.php
*/
public function getReadConcern(): ReadConcern
{
return $this->readConcern;
}
/**
* Return the read preference for this collection.
*/
public function getReadPreference(): ReadPreference
{
return $this->readPreference;
}
/**
* Return the type map for this collection.
*/
public function getTypeMap(): array
{
return $this->typeMap;
}
/**
* Return the write concern for this collection.
*
* @see https://php.net/manual/en/mongodb-driver-writeconcern.isdefault.php
*/
public function getWriteConcern(): WriteConcern
{
return $this->writeConcern;
}
/**
* Inserts multiple documents.
*
* @see InsertMany::__construct() for supported options
* @see https://mongodb.com/docs/manual/reference/command/insert/
* @param list<object|array> $documents The documents to insert
* @param array $options Command options
* @throws InvalidArgumentException for parameter/option parsing errors
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
*/
public function insertMany(array $documents, array $options = []): InsertManyResult
{
$options = $this->inheritWriteOptions($options);
$options = $this->inheritCodec($options);
$operation = new InsertMany($this->databaseName, $this->collectionName, $documents, $options);
return $operation->execute(select_server_for_write($this->manager, $options));
}
/**
* Inserts one document.
*
* @see InsertOne::__construct() for supported options
* @see https://mongodb.com/docs/manual/reference/command/insert/
* @param array|object $document The document to insert
* @param array $options Command options
* @throws InvalidArgumentException for parameter/option parsing errors
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
*/
public function insertOne(array|object $document, array $options = []): InsertOneResult
{
$options = $this->inheritWriteOptions($options);
$options = $this->inheritCodec($options);
$operation = new InsertOne($this->databaseName, $this->collectionName, $document, $options);
return $operation->execute(select_server_for_write($this->manager, $options));
}
/**
* Returns information for all indexes for the collection.
*
* @see ListIndexes::__construct() for supported options
* @return Iterator<int, IndexInfo>
* @throws InvalidArgumentException for parameter/option parsing errors
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
*/
public function listIndexes(array $options = []): Iterator
{
$operation = new ListIndexes($this->databaseName, $this->collectionName, $options);
return $operation->execute(select_server($this->manager, $options));
}
/**
* Returns information for all Atlas Search indexes for the collection.
* Only available when used against a 7.0+ Atlas cluster.
*
* @param array $options Command options
* @return Countable&Iterator
* @throws InvalidArgumentException for parameter/option parsing errors
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
* @see ListSearchIndexes::__construct() for supported options
*/
public function listSearchIndexes(array $options = []): Iterator
{
$options = $this->inheritTypeMap($options);
$operation = new ListSearchIndexes($this->databaseName, $this->collectionName, $options);
$server = select_server($this->manager, $options);
return $operation->execute($server);
}
/**
* Renames the collection.
*
* @see RenameCollection::__construct() for supported options
* @param string $toCollectionName New name of the collection
* @param string|null $toDatabaseName New database name of the collection. Defaults to the original database.
* @param array $options Additional options
* @throws UnsupportedException if options are not supported by the selected server
* @throws InvalidArgumentException for parameter/option parsing errors
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
*/
public function rename(string $toCollectionName, ?string $toDatabaseName = null, array $options = []): void
{
if (! isset($toDatabaseName)) {
$toDatabaseName = $this->databaseName;
}
$options = $this->inheritWriteOptions($options);
$operation = new RenameCollection($this->databaseName, $this->collectionName, $toDatabaseName, $toCollectionName, $options);
$operation->execute(select_server_for_write($this->manager, $options));
}
/**
* Replaces at most one document matching the filter.
*
* @see ReplaceOne::__construct() for supported options
* @see https://mongodb.com/docs/manual/reference/command/update/
* @param array|object $filter Query by which to filter documents
* @param array|object $replacement Replacement document
* @param array $options Command options
* @throws UnsupportedException if options are not supported by the selected server
* @throws InvalidArgumentException for parameter/option parsing errors
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
*/
public function replaceOne(array|object $filter, array|object $replacement, array $options = []): UpdateResult
{
$filter = $this->builderEncoder->encodeIfSupported($filter);
$options = $this->inheritWriteOptions($options);
$options = $this->inheritCodec($options);
$operation = new ReplaceOne($this->databaseName, $this->collectionName, $filter, $replacement, $options);
return $operation->execute(select_server_for_write($this->manager, $options));
}
/**
* Updates all documents matching the filter.
*
* @see UpdateMany::__construct() for supported options
* @see https://mongodb.com/docs/manual/reference/command/update/
* @param array|object $filter Query by which to filter documents
* @param array|object $update Update to apply to the matched documents
* @param array $options Command options
* @throws UnsupportedException if options are not supported by the selected server
* @throws InvalidArgumentException for parameter/option parsing errors
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
*/
public function updateMany(array|object $filter, array|object $update, array $options = []): UpdateResult
{
$filter = $this->builderEncoder->encodeIfSupported($filter);
$update = $this->builderEncoder->encodeIfSupported($update);
$options = $this->inheritWriteOptions($options);
$operation = new UpdateMany($this->databaseName, $this->collectionName, $filter, $update, $options);
return $operation->execute(select_server_for_write($this->manager, $options));
}
/**
* Updates at most one document matching the filter.
*
* @see UpdateOne::__construct() for supported options
* @see https://mongodb.com/docs/manual/reference/command/update/
* @param array|object $filter Query by which to filter documents
* @param array|object $update Update to apply to the matched document
* @param array $options Command options
* @throws UnsupportedException if options are not supported by the selected server
* @throws InvalidArgumentException for parameter/option parsing errors
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
*/
public function updateOne(array|object $filter, array|object $update, array $options = []): UpdateResult
{
$filter = $this->builderEncoder->encodeIfSupported($filter);
$update = $this->builderEncoder->encodeIfSupported($update);
$options = $this->inheritWriteOptions($options);
$operation = new UpdateOne($this->databaseName, $this->collectionName, $filter, $update, $options);
return $operation->execute(select_server_for_write($this->manager, $options));
}
/**
* Update a single Atlas Search index in the collection.
* Only available when used against a 7.0+ Atlas cluster.
*
* @param string $name Search index name
* @param array|object $definition Atlas Search index definition
* @param array{comment?: mixed} $options Command options
* @throws UnsupportedException if options are not supported by the selected server
* @throws InvalidArgumentException for parameter parsing errors
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
*/
public function updateSearchIndex(string $name, array|object $definition, array $options = []): void
{
$operation = new UpdateSearchIndex($this->databaseName, $this->collectionName, $name, $definition, $options);
$server = select_server_for_write($this->manager, $options);
$operation->execute($server);
}
/**
* Create a change stream for watching changes to the collection.
*
* @see Watch::__construct() for supported options
* @param array|Pipeline $pipeline Aggregation pipeline
* @param array $options Command options
* @throws InvalidArgumentException for parameter/option parsing errors
*/
public function watch(array|Pipeline $pipeline = [], array $options = []): ChangeStream
{
if (is_array($pipeline) && is_builder_pipeline($pipeline)) {
$pipeline = new Pipeline(...$pipeline);
}
$pipeline = $this->builderEncoder->encodeIfSupported($pipeline);
$options = $this->inheritReadOptions($options);
$options = $this->inheritCodecOrTypeMap($options);
$operation = new Watch($this->manager, $this->databaseName, $this->collectionName, $pipeline, $options);
return $operation->execute(select_server($this->manager, $options));
}
/**
* Get a clone of this collection with different options.
*
* @see Collection::__construct() for supported options
* @param array $options Collection constructor options
* @throws InvalidArgumentException for parameter/option parsing errors
*/
public function withOptions(array $options = []): Collection
{
$options += [
'autoEncryptionEnabled' => $this->autoEncryptionEnabled,
'builderEncoder' => $this->builderEncoder,
'codec' => $this->codec,
'readConcern' => $this->readConcern,
'readPreference' => $this->readPreference,
'typeMap' => $this->typeMap,
'writeConcern' => $this->writeConcern,
];
return new Collection($this->manager, $this->databaseName, $this->collectionName, $options);
}
private function inheritBuilderEncoder(array $options): array
{
return ['builderEncoder' => $this->builderEncoder] + $options;
}
private function inheritCodec(array $options): array
{
// If the options contain a type map, don't inherit anything
if (isset($options['typeMap'])) {
return $options;
}
if (! array_key_exists('codec', $options)) {
$options['codec'] = $this->codec;
}
return $options;
}
private function inheritCodecOrTypeMap(array $options): array
{
// If the options contain a type map, don't inherit anything
if (isset($options['typeMap'])) {
return $options;
}
// If this collection does not use a codec, or if a codec was explicitly
// defined in the options, only inherit the type map (if possible)
if (! $this->codec || array_key_exists('codec', $options)) {
return $this->inheritTypeMap($options);
}
// At this point, we know that we use a codec and the options array did
// not explicitly contain a codec, so we can inherit ours
$options['codec'] = $this->codec;
return $options;
}
private function inheritReadConcern(array $options): array
{
// ReadConcern and ReadPreference may not change within a transaction
if (! isset($options['readConcern']) && ! is_in_transaction($options)) {
$options['readConcern'] = $this->readConcern;
}
return $options;
}
private function inheritReadOptions(array $options): array
{
$options = $this->inheritReadConcern($options);
return $this->inheritReadPreference($options);
}
private function inheritReadPreference(array $options): array
{
// ReadConcern and ReadPreference may not change within a transaction
if (! isset($options['readPreference']) && ! is_in_transaction($options)) {
$options['readPreference'] = $this->readPreference;
}
return $options;
}
private function inheritTypeMap(array $options): array
{
// Only inherit the type map if no codec is used
if (! isset($options['typeMap']) && ! isset($options['codec'])) {
$options['typeMap'] = $this->typeMap;
}
return $options;
}
private function inheritWriteOptions(array $options): array
{
// WriteConcern may not change within a transaction
if (! is_in_transaction($options)) {
if (! isset($options['writeConcern'])) {
$options['writeConcern'] = $this->writeConcern;
}
}
return $options;
}
}
|
| #2 | MongoDB\Collection->count /srv/ChatHispanoEngine/releases/20250927141530/apps/Core/Models/BaseCollection.php (103) <?php
namespace ChatHispanoEngine\Core\Models;
/**
* Class that managers MongoDB database
*
* @author iwalkalone
*/
class BaseCollection extends \Phalcon\Di\Injectable
{
public $_id;
protected const MONGOMODELCLASS = "Phalcon\Db\Adapter\MongoDB\Model";
public function getId()
{
return $this->_id;
}
protected static function getConnection()
{
$class = get_called_class();
$o = new $class();
return $o->getDI()->get('mongo');
}
protected static function getInstance()
{
$class = get_called_class();
$o = new $class();
return $o;
}
protected static function getCollection()
{
$class = get_called_class();
$o = new $class();
return $o->getSource();
}
public static function findFirst(array $data = [])
{
$database = self::getConnection();
$collection = self::getCollection();
if (isset($data[0])) {
$filters = $data[0];
unset($data[0]);
} else {
$filters = [];
}
$options = $data;
$doc = $database->$collection->findOne($filters, $options);
if (!$doc) {
return false;
}
$o = self::getInstance();
$o->fromArray($doc->getArrayCopy());
return $o;
}
public static function findById($id)
{
return self::findFirst([
[
'_id' => new \MongoDB\BSON\ObjectId($id),
],
]);
}
public static function find(array $data = [])
{
$database = self::getConnection();
$collection = self::getCollection();
if (isset($data[0])) {
$filters = $data[0];
unset($data[0]);
} else {
$filters = [];
}
$options = $data;
$result = $database->$collection->find($filters, $options);
$list = [];
foreach ($result as $doc) {
$o = self::getInstance();
$o->fromArray($doc->getArrayCopy());
$list[] = $o;
}
return $list;
}
public static function count(array $data = [])
{
$database = self::getConnection();
$collection = self::getCollection();
if (isset($data[0])) {
$filters = $data[0];
unset($data[0]);
} else {
$filters = [];
}
$options = $data;
return $database->$collection->count($filters, $options); // Will be deprecated?
//return $database->$collection->countDocuments($filters, $options);
}
public function create()
{
$database = self::getConnection();
$collection = self::getCollection();
$data = get_object_vars($this);
$data['_id'] = new \MongoDB\BSON\ObjectId();
$res = $database->$collection->insertOne($data);
if ($res->getInsertedCount() > 0) {
$this->_id = $res->getInsertedId();
return $this->_id;
} else {
return false;
}
}
public function save()
{
$database = self::getConnection();
$collection = self::getCollection();
$data = get_object_vars($this);
if (isset($data['_id'])) {
$id = $data['_id'];
unset($data['_id']);
$res = $database->$collection->updateOne([
'_id' => $id,
], [
'$set' => $data,
]);
return $res->getModifiedCount() > 0;
} else {
return $this->create();
}
}
public function delete()
{
$database = self::getConnection();
$collection = self::getCollection();
$res = $database->$collection->deleteOne([
'_id' => $this->_id,
]);
return $res->getDeletedCount() > 0;
}
protected function fromArrayInternal(array $data)
{
$a = [];
foreach ($data as $key => $val) {
if (is_object($val)) {
$class = get_class($val);
if (substr($class, 0, strlen(self::MONGOMODELCLASS)) == self::MONGOMODELCLASS) {
$a[$key] = $this->fromArrayInternal($val->getArrayCopy());
} else {
$a[$key] = $val;
}
} else {
$a[$key] = $val;
}
}
return $a;
}
public function fromArray(array $data)
{
foreach ($data as $key => $val) {
if (is_object($val)) {
$class = get_class($val);
if (substr($class, 0, strlen(self::MONGOMODELCLASS)) == self::MONGOMODELCLASS) {
$this->$key = $this->fromArrayInternal($val->getArrayCopy());
} else {
$this->$key = $val;
}
} else {
$this->$key = $val;
}
}
}
public function toArray($columns = null): array
{
$data = get_object_vars($this);
if ($columns && is_array($columns)) {
$data = array_diff_assoc($data, $columns);
}
unset($data['_id']);
return $data;
}
// Dummy function to make it compat with Phalcon 3 code
public function getMessages(): array
{
return [];
}
}
|
| #3 | ChatHispanoEngine\Core\Models\BaseCollection::count /srv/ChatHispanoEngine/releases/20250927141530/apps/Core/Managers/InspIRCd/ChannelLoggerManager.php (112) <?php
namespace ChatHispanoEngine\Core\Managers\InspIRCd;
use ChatHispanoEngine\Core\Exception\Exception;
use ChatHispanoEngine\Core\Exception\ErrorCodes;
use ChatHispanoEngine\Core\Library\Faker;
use ChatHispanoEngine\Core\Library\Util;
use ChatHispanoEngine\Core\Models\InspIRCd\Channel\Log;
use ChatHispanoEngine\Core\Models\InspIRCd\Channel\Story;
class ChannelLoggerManager extends \Phalcon\Mvc\Model\Manager
{
public const PAGE_SIZE = 10;
public function listByChannel($channel, $date = '', $asc = false)
{
if ($date == '') {
$date = date('Y-m-d');
}
// Get timestamps of start and end of day to retrieve only data of specified day
$start = strtotime($date);
$end = strtotime($date.' +1 day');
return Log::find(array(
array(
'channel' => mb_strtolower($channel),
'date' => [
'$gte' => new \MongoDB\BSON\UTCDateTime($start * 1000),
'$lte' => new \MongoDB\BSON\UTCDateTime($end * 1000),
],
),
'sort' => [
'date' => $asc === true ? 1 : -1,
],
));
}
public function create($ts, $channel, $event, $sender, $reason = null, $kicker = null, $new_nick = null)
{
$o = new Log();
$o->date = new \MongoDB\BSON\UTCDateTime($ts * 1000);
$o->channel = mb_strtolower($channel);
$o->event = $event;
$o->sender = $sender;
$o->reason = $reason;
$o->kicker = $kicker;
$o->new_nick = $new_nick;
if (false === $o->save()) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_LOG_CREATE);
}
return $o;
}
public function countStories()
{
return Story::count();
}
public function listStories($offset = 0, $limit = 50)
{
return Story::find([
[],
'sort' => [
'date' => -1,
],
'limit' => $limit,
'skip' => $offset,
]);
}
public function listActiveStories($channel = null, $date = null, array $sort, $page = 1)
{
$query = [
'status' => Story::STATUS_ACTIVE,
];
if ($channel) {
$query['channel'] = '#'.$channel;
}
if ($date) {
$query['date'] = [
'$gte' => new \MongoDB\BSON\UTCDateTime(strtotime($date) * 1000),
'$lt' => new \MongoDB\BSON\UTCDateTime(strtotime($date.' +1 day') * 1000),
];
}
return Story::find(array(
$query,
'sort' => $sort,
'limit' => self::PAGE_SIZE,
'skip' => ($page - 1) * self::PAGE_SIZE,
));
}
public function countActiveStories($channel = null, $date = null)
{
$query = [
'status' => Story::STATUS_ACTIVE,
];
if ($channel) {
$query['channel'] = '#'.$channel;
}
if ($date) {
$query['date'] = [
'$gte' => new \MongoDB\BSON\UTCDateTime(strtotime($date) * 1000),
'$lt' => new \MongoDB\BSON\UTCDateTime(strtotime($date.' +1 day') * 1000),
];
}
return Story::count(array(
$query,
));
}
public function getStoriesPages($cnt)
{
return ceil($cnt / self::PAGE_SIZE);
}
public function getStory($id)
{
$o = Story::findFirst([
[
'_id' => new \MongoDB\BSON\ObjectId($id),
],
]);
if ($o === false || $o === null) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_STORY_NOT_FOUND);
}
return $o;
}
public function getLastActiveStoryFromChannel($channel)
{
return Story::findFirst([
[
'channel' => $channel,
],
'sort' => [
'date' => -1,
],
]);
}
public function getPreviousStory(Story $s, $list, $hasDate = 0, $hasChannel = 0)
{
$query = [
'status' => Story::STATUS_ACTIVE,
];
if ($hasChannel) {
$query['channel'] = $s->channel;
}
if ($hasDate) {
$query['date'] = [
'$gte' => new \MongoDB\BSON\UTCDateTime(strtotime($s->getDate('Y-m-d')) * 1000),
'$lt' => $s->date,
];
} else {
$query['date'] = [
'$lt' => $s->date,
];
}
switch ($list) {
case 'viewed':
$sort = [
'views' => -1,
'date' => -1,
];
break;
case 'liked':
$sort = [
'positive' => -1,
'negative' => 1,
'date' => -1,
];
break;
case 'disliked':
$sort = [
'negative' => -1,
'positive' => 1,
'date' => -1,
];
break;
default:
$sort = [
'date' => -1,
];
break;
}
return Story::findFirst(array(
$query,
'sort' => $sort,
));
}
public function getNextStory(Story $s, $list, $hasDate = 0, $hasChannel = 0)
{
$query = [
'status' => Story::STATUS_ACTIVE,
];
if ($hasChannel) {
$query['channel'] = $s->channel;
}
if ($hasDate) {
$query['date'] = [
'$gt' => $s->date,
'$lt' => new \MongoDB\BSON\UTCDateTime(strtotime($s->getDate('Y-m-d').' +1 day') * 1000),
];
} else {
$query['date'] = [
'$gt' => $s->date,
];
}
switch ($list) {
case 'viewed':
$sort = [
'views' => -1,
'date' => 1,
];
break;
case 'liked':
$sort = [
'positive' => -1,
'negative' => 1,
'date' => 1,
];
break;
case 'disliked':
$sort = [
'negative' => -1,
'positive' => 1,
'date' => 1,
];
break;
default:
$sort = [
'date' => 1,
];
break;
}
return Story::findFirst(array(
$query,
'sort' => $sort,
));
}
public function createStory($ts, $channel, $messages = [])
{
$o = new Story();
$o->createIndexes();
$o->date = new \MongoDB\BSON\UTCDateTime($ts * 1000);
$o->channel = mb_strtolower($channel);
$o->status = Story::STATUS_ACTIVE;
$o->views = 0;
$o->positive = 0;
$o->negative = 0;
$o->positive_emails = [];
$o->negative_emails = [];
$o->messages = [];
$anonimized_nick = [];
$nick_color = [];
$nick_color_dec = [];
foreach ($messages as $msg) {
if (!isset($anonimized_nick[$msg->sender])) {
$anonimized_nick[$msg->sender] = Faker::getNick();
$round = 0;
while (true) {
$r = rand(0, 130);
$g = rand(0, 130);
$b = rand(0, 130);
$v = true;
foreach ($nick_color_dec as $c) {
$d = abs($r - $c[0]) + abs($g - $c[1]) + abs($b - $c[2]);
if ($d < 50) {
$v = false;
break;
}
}
if ($v === true || $round >= 10) {
break;
}
$round++;
}
$nick_color[$msg->sender] = '#'.str_pad(dechex($r), 2, "0").str_pad(dechex($g), 2, "0").str_pad(dechex($b), 2, "0");
$nick_color_dec[$msg->sender] = [$r, $g, $b];
}
}
foreach ($messages as $msg) {
$o->messages[] = [
'date' => $msg->date->toDateTime()->getTimestamp(),
'nick' => $msg->sender,
'anonimized_nick' => $anonimized_nick[$msg->sender],
'nick_color' => $nick_color[$msg->sender],
'message' => str_replace(array_keys($anonimized_nick), array_values($anonimized_nick), Util::stripColor($msg->reason)),
];
}
$o->lines = count($o->messages);
$o->users = count($anonimized_nick);
if (false === $o->save()) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_STORY_CREATE);
}
return $o;
}
public function enableStory($id)
{
$o = $this->getStory($id);
$o->status = Story::STATUS_ACTIVE;
if (false === $o->save()) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_STORY_UPDATE);
}
return $o;
}
public function disableStory($id)
{
$o = $this->getStory($id);
$o->status = Story::STATUS_DISABLED;
if (false === $o->save()) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_STORY_UPDATE);
}
return $o;
}
public function addStoryView(Story $o)
{
$o->views = $o->views + 1;
if (false === $o->save()) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_STORY_UPDATE);
}
return $o;
}
public function likeStory(Story $o, $email)
{
$ppos = get_class($o->positive_emails) == 'MongoDB\Model\BSONArray' ? array_search(mb_strtolower($email), $o->positive_emails->getArrayCopy()) : false;
$npos = get_class($o->negative_emails) == 'MongoDB\Model\BSONArray' ? array_search(mb_strtolower($email), $o->negative_emails->getArrayCopy()) : false;
if (false !== $npos) {
// We remove from the negative list
$o->negative_emails->offsetUnset($npos);
$o->negative = $o->negative - 1;
if (false === $o->save()) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_STORY_UPDATE);
}
} elseif (false === $ppos) {
// We add to the positive list
if (get_class($o->positive_emails) != 'MongoDB\Model\BSONArray') {
$o->positive_emails = new \MongoDB\Model\BSONArray();
}
$o->positive_emails->append($email);
$o->positive = $o->positive + 1;
if (false === $o->save()) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_STORY_UPDATE);
}
} else {
// We ignore it, as it is already in positive list
}
return $o;
}
public function likeStorySession(Story $o)
{
if ($this->getDI()->get('session')->has('story_like_'.$o->_id->__toString())) {
// It exists, so we ignore it
} else {
$removeNegative = false;
if ($this->getDI()->get('session')->has('story_dislike_'.$o->_id->__toString())) {
$removeNegative = true;
$o->negative--;
}
$o->positive++;
if (false === $o->save()) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_STORY_UPDATE);
}
if ($removeNegative) {
$this->getDI()->get('session')->remove('story_dislike_'.$o->_id->__toString());
}
$this->getDI()->get('session')->set('story_like_'.$o->_id->__toString(), 1);
}
return $o;
}
public function dislikeStory(Story $o, $email)
{
$ppos = get_class($o->positive_emails) == 'MongoDB\Model\BSONArray' ? array_search(mb_strtolower($email), $o->positive_emails->getArrayCopy()) : false;
$npos = get_class($o->negative_emails) == 'MongoDB\Model\BSONArray' ? array_search(mb_strtolower($email), $o->negative_emails->getArrayCopy()) : false;
if (false !== $ppos) {
// We remove from the positive list
array_splice($o->positive_emails, $ppos, 1);
$o->positive_emails->offsetUnset($ppos);
$o->positive = $o->positive - 1;
if (false === $o->save()) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_STORY_UPDATE);
}
} elseif (false === $npos) {
// We add to the negative list
if (get_class($o->negative_emails) != 'MongoDB\Model\BSONArray') {
$o->negative_emails = new \MongoDB\Model\BSONArray();
}
$o->negative_emails->append($email);
$o->negative = $o->negative + 1;
if (false === $o->save()) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_STORY_UPDATE);
}
} else {
// We ignore it, as it is already in negative list
}
return $o;
}
public function dislikeStorySession(Story $o)
{
if ($this->getDI()->get('session')->has('story_dislike_'.$o->_id->__toString())) {
// It exists, so we ignore it
} else {
$removePositive = false;
if ($this->getDI()->get('session')->has('story_like_'.$o->_id->__toString())) {
$removePositive = true;
$o->positive--;
}
$o->negative++;
if (false === $o->save()) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_STORY_UPDATE);
}
if ($removePositive === true) {
$this->getDI()->get('session')->remove('story_like_'.$o->_id->__toString());
}
$this->getDI()->get('session')->set('story_dislike_'.$o->_id->__toString(), 1);
}
return $o;
}
}
|
| #4 | ChatHispanoEngine\Core\Managers\InspIRCd\ChannelLoggerManager->countActiveStories /srv/ChatHispanoEngine/releases/20250927141530/apps/Web/Controllers/StoriesController.php (38) <?php
namespace ChatHispanoEngine\Web\Controllers;
use ChatHispanoEngine\Core\Library\MobileDetect;
class StoriesController extends BaseController
{
public function indexAction($channel = null, $date = null)
{
$this->view->channel = $channel;
$this->view->date = $date;
if ($date) {
if ($channel) {
$this->view->stories_title = $this->_t('Stories from %name% at %date%', [
'name' => '#'.$channel,
'date' => date('d/m/Y', strtotime($date)),
]);
} else {
$this->view->stories_title = $this->_t('Stories at %date%', [
'date' => date('d/m/Y', strtotime($date)),
]);
}
} elseif ($channel) {
$this->view->stories_title = $this->_t('Stories from %name%', [
'name' => '#'.$channel,
]);
} else {
$this->view->stories_title = $this->_t('Stories', []);
}
$this->setHeadTitle($this->view->stories_title);
$this->view->hasDate = $date ? 1 : 0;
$this->view->hasChannel = $channel ? 1 : 0;
$page = $this->request->getQuery('page', 'int', 1);
$channel_logger_manager = $this->getDI()->get('channel_logger_manager');
$this->view->page = $page;
$this->view->total_stories = $channel_logger_manager->countActiveStories($channel, $date);
$this->view->total_pages = $channel_logger_manager->getStoriesPages($this->view->total_stories);
$this->view->uri_stories = $this->request->get('_url');
if ($page > $this->view->total_pages) {
$this->flashSession->error($this->_t('Page does not exist'));
$this->response->redirect('/historias');
return;
}
$this->view->stories = [
'last' => $channel_logger_manager->listActiveStories($channel, $date, [
'date' => -1,
], $page),
'viewed' => $channel_logger_manager->listActiveStories($channel, $date, [
'views' => -1,
'date' => -1,
], $page),
'liked' => $channel_logger_manager->listActiveStories($channel, $date, [
'positive' => -1,
'negative' => 1,
'date' => -1,
], $page),
'disliked' => $channel_logger_manager->listActiveStories($channel, $date, [
'negative' => -1,
'positive' => 1,
'date' => -1,
], $page),
];
// Navigation
$nav = [
['name' => $this->_t('Home', []), 'url' => '/', ],
['name' => $this->_t('Stories', []), 'url' => '/historias', ],
];
if ($channel) {
$nav[] = ['name' => $this->_t('Channel %name%', ['name' => '#'.$channel]), 'url' => '/historias/'.$channel, ];
}
if ($date) {
$nav[] = ['name' => $date, 'url' => '/historias/'.$channel.'/'.$date, ];
}
$this->view->navigation = $nav;
}
public function viewAction($channel, $date, $id)
{
$list = $this->request->getQuery('l', 'string', 'last');
$hasDate = $this->request->getQuery('d', 'string', 0);
$hasChannel = $this->request->getQuery('c', 'string', 0);
$config = $this->getDI()->get('config');
$channel_logger_manager = $this->getDI()->get('channel_logger_manager');
try {
$story = $channel_logger_manager->getStory($id);
} catch (\Exception $e) {
$this->flashSession->error($this->_t($e->getMessage()));
$this->response->redirect('/historias');
return;
}
if ($story->channel != '#'.$channel || $story->getDate('Y-m-d') != $date) {
$this->flashSession->error($this->_t('Unexpected error'));
$this->response->redirect('/historias');
return;
}
try {
$detect = new MobileDetect();
$detect->setUserAgent($this->request->getUserAgent());
if (false === $detect->is('Bot') && false === $detect->is('MobileBot')) {
$v = $this->session->get('story_view_'.$story->_id->__toString());
if (!$v || $v != 1) {
$story = $channel_logger_manager->addStoryView($story);
$this->session->set('story_view_'.$story->_id->__toString(), 1);
}
}
} catch (\Exception $e) {
}
$this->view->story = $story;
$this->view->list = $list;
$this->view->hasDate = $hasDate;
$this->view->hasChannel = $hasChannel;
$this->view->previousStory = $channel_logger_manager->getPreviousStory($story, $list, $hasDate, $hasChannel);
$this->view->nextStory = $channel_logger_manager->getNextStory($story, $list, $hasDate, $hasChannel);
// Navigation
$this->view->navigation = [
['name' => $this->_t('Home', []), 'url' => '/', ],
['name' => $this->_t('Stories', []), 'url' => '/historias', ],
['name' => $this->_t('Channel %name%', ['name' => $story->channel]), 'url' => '/historias/'.$channel, ],
['name' => $date, 'url' => '/historias/'.$channel.'/'.$date, ],
['name' => $id, 'url' => '/historias/'.$channel.'/'.$date.'/'.$id, ],
];
}
public function likeAction($channel, $date, $id)
{
$this->response->setHeader('X-Robots-Tag', 'noindex');
$this->view->disable();
try {
$channel_logger_manager = $this->getDI()->get('channel_logger_manager');
$story = $channel_logger_manager->getStory($id);
} catch (\Exception $e) {
$this->flashSession->error($this->_t($e->getMessage()));
$this->response->redirect('/historias');
return;
}
if ($story->channel != '#'.$channel || $story->getDate('Y-m-d') != $date) {
$this->flashSession->error($this->_t('Unexpected error'));
$this->response->redirect('/historias');
return;
}
try {
$detect = new MobileDetect();
$detect->setUserAgent($this->request->getUserAgent());
if (false === $detect->is('Bot') && false === $detect->is('MobileBot')) {
if ($this->auth->isUserSignedIn()) {
$story = $channel_logger_manager->likeStory($story, $this->auth->getIdentity()['email']);
} else {
$story = $channel_logger_manager->likeStorySession($story);
}
}
} catch (\Exception $e) {
$this->flashSession->error($this->_t($e->getMessage()));
}
$this->response->redirect($this->view->backLink);
}
public function dislikeAction($channel, $date, $id)
{
$this->response->setHeader('X-Robots-Tag', 'noindex');
$this->view->disable();
try {
$channel_logger_manager = $this->getDI()->get('channel_logger_manager');
$story = $channel_logger_manager->getStory($id);
} catch (\Exception $e) {
$this->flashSession->error($this->_t($e->getMessage()));
$this->response->redirect('/historias');
return;
}
if ($story->channel != '#'.$channel || $story->getDate('Y-m-d') != $date) {
$this->flashSession->error($this->_t('Unexpected error'));
$this->response->redirect('/historias');
return;
}
try {
$detect = new MobileDetect();
$detect->setUserAgent($this->request->getUserAgent());
if (false === $detect->is('Bot') && false === $detect->is('MobileBot')) {
if ($this->auth->isUserSignedIn()) {
$story = $channel_logger_manager->dislikeStory($story, $this->auth->getIdentity()['email']);
} else {
$story = $channel_logger_manager->dislikeStorySession($story);
}
}
} catch (\Exception $e) {
$this->flashSession->error($this->_t($e->getMessage()));
}
$this->response->redirect($this->view->backLink);
}
}
|
| #5 | ChatHispanoEngine\Web\Controllers\StoriesController->indexAction |
| #6 | Phalcon\Dispatcher\AbstractDispatcher->callActionMethod |
| #7 | Phalcon\Dispatcher\AbstractDispatcher->dispatch |
| #8 | Phalcon\Mvc\Application->handle /srv/ChatHispanoEngine/releases/20250927141530/apps/Application.php (150) <?php
// namespace ChatHispanoEngine;
/**
* Application driver class to initialize Phalcon and
* other resources.
*/
class Application extends \Phalcon\Mvc\Application
{
private static $mode = 'dev';
private static $DEFAULT_MODULE = 'api';
public const MODE_PRODUCTION = 'prod';
public const MODE_STAGING = 'staging';
public const MODE_TEST = 'test';
public const MODE_DEVELOPMENT = 'dev';
/**
* Set application mode and error reporting level.
*/
public function __construct($defaultModule, $env = 'dev')
{
$this->modules = array(
'core' => array(
'className' => 'ChatHispanoEngine\Core\Module',
'path' => __DIR__.'/Core/Module.php',
),
'api' => array(
'className' => 'ChatHispanoEngine\Api\Module',
'path' => __DIR__.'/Api/Module.php',
),
'login' => array(
'className' => 'ChatHispanoEngine\Login\Module',
'path' => __DIR__.'/Login/Module.php',
),
'oidc' => array(
'className' => 'ChatHispanoEngine\Oidc\Module',
'path' => __DIR__.'/Oidc/Module.php',
),
'web' => array(
'className' => 'ChatHispanoEngine\Web\Module',
'path' => __DIR__.'/Web/Module.php',
),
'backoffice' => array(
'className' => 'ChatHispanoEngine\Backoffice\Module',
'path' => __DIR__.'/Backoffice/Module.php',
),
'movil' => array(
'className' => 'ChatHispanoEngine\Movil\Module',
'path' => __DIR__.'/Movil/Module.php',
),
'regwebexternal' => array(
'className' => 'ChatHispanoEngine\RegWebExternal\Module',
'path' => __DIR__.'/Regwebexternal/Module.php',
),
'cdn' => array(
'className' => 'ChatHispanoEngine\Cdn\Module',
'path' => __DIR__.'/Cdn/Module.php',
),
'shorten' => array(
'className' => 'ChatHispanoEngine\Shorten\Module',
'path' => __DIR__.'/Shorten/Module.php',
),
);
static::$DEFAULT_MODULE = $defaultModule;
self::$mode = $env;
self::$mode = trim(file_get_contents(__DIR__.'/../config/environment.txt'));
define('ENVIRONMENT', self::$mode);
if (!defined('PHALCON_MODE')) {
$mode = getenv('PHALCON_MODE');
$mode = $mode ? $mode : self::$mode;
define('PHALCON_MODE', $mode);
}
switch (self::getMode()) {
case self::MODE_PRODUCTION:
case self::MODE_STAGING:
error_reporting(0);
break;
case self::MODE_TEST:
case self::MODE_DEVELOPMENT:
ini_set('display_errors', 'On');
error_reporting(E_ALL);
break;
}
}
/**
* Register the services here to make them general or register in
* the ModuleDefinition to make them module-specific.
*/
protected function _registerServices()
{
$defaultModule = self::$DEFAULT_MODULE;
$modules = $this->modules;
$config = include __DIR__.'/../config/config.php';
$env_config = include __DIR__.'/../config/config_'.ENVIRONMENT.'.php';
$config->merge($env_config);
$di = new \Phalcon\DI\FactoryDefault();
include __DIR__.'/../config/loader.php';
include __DIR__.'/../config/services.php';
include __DIR__.'/../config/routing.php';
$this->setDI($di);
}
/**
* Run the application.
*/
public function main()
{
if (static::MODE_PRODUCTION === static::getMode()) {
$this->mainProd();
} else {
$this->mainDev();
}
}
private function getRequestUri()
{
if (!isset($_SERVER)) {
return "/";
}
if (!is_array($_SERVER)) {
return "/";
}
if (!isset($_SERVER['REQUEST_URI'])) {
return "/";
}
return $_SERVER['REQUEST_URI'];
}
/**
* Run the development environment.
*/
private function mainDev()
{
(new \Phalcon\Support\Debug())->listen();
$this->_registerServices();
$this->registerModules($this->modules);
$response = $this->handle($this->getRequestUri());
$response->send();
}
/**
* Run the production environment.
*/
private function mainProd()
{
try {
$this->registerModules($this->modules);
$this->_registerServices();
$response = $this->handle($this->getRequestUri());
$response->send();
} catch (\Exception $e) {
$logger = new \Phalcon\Logger\Adapter\Stream(__DIR__.'/../logs/'.date('Y-m-d').'.log');
$msg = "[".$_SERVER['SERVER_NAME']."] [".$_SERVER['REQUEST_URI']."] [".$e->getCode()."] ".$e->getMessage()." at ".$e->getFile()." (".$e->getLine().")";
$msg .= "\n".$e->getTraceAsString();
$logger->process(new \Phalcon\Logger\Item($msg, "error", 100));
$logger->close();
// remove view contents from buffer
ob_clean();
$errorCode = 500;
$errorView = __DIR__.'/../public/errors/error.html';
if (401 === $e->getCode()) {
// 401 UNAUTHORIZED
$errorCode = 401;
} elseif (403 === $e->getCode()) {
// 403 FORBIDDEN
$errorCode = 403;
} elseif (404 === $e->getCode()
|| $e instanceof Phalcon\Mvc\View\Exception
|| $e instanceof Phalcon\Mvc\Dispatcher\Exception) {
// 404 NOT FOUND
$errorCode = 404;
}
// Get error view contents. Since we are including the view
// file here you can use PHP and local vars inside the error view.
ob_start();
include_once $errorView;
$contents = ob_get_contents();
ob_end_clean();
// send view to header
$response = $this->getDI()->getShared('response');
$response->resetHeaders()
->setStatusCode($errorCode, null)
->setContent($contents)
->send()
;
/**
* We try to register in MongoDB the error to be able to
* track it in backoffice and/or receive emails
*/
try {
$system_log_manager = $this->getDI()->get('system_log_manager');
if ($errorCode == 500) {
$system_log_manager->createError([
'ip' => $_SERVER['SERVER_ADDR'],
'host' => $_SERVER['SERVER_NAME'],
'process' => 'php-fpm',
'message' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
]);
} else {
$system_log_manager->createWarning([
'ip' => $_SERVER['SERVER_ADDR'],
'host' => $_SERVER['SERVER_NAME'],
'process' => 'php-fpm',
'message' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
]);
}
} catch (\Exception $e) {
}
}
}
public function slowLog($t)
{
$config = $this->getDI()->get('config');
$irc_manager = $this->getDI()->get('inspircd_irc_manager');
$server = gethostname() ? gethostname() : 'unknown';
$uri = "https://".$_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI'];
if (substr($_SERVER['REQUEST_URI'], 0, 10) == '/historias') {
return;
}
$msg = "\x02[SLOWLOG] [".str_pad($server, 6, " ", STR_PAD_LEFT)."] [".str_pad(round($t, 1), 5, " ", STR_PAD_LEFT)."s] PATH=\x02 ".$_SERVER['REQUEST_URI']
."\x02 TYPE=\x02 ".$_SERVER['REQUEST_METHOD']."\x02 URI=\x02 ".$uri;
$irc_manager->privmsgOrderEnqueue('AAAAAI', $config->irc->debug_channel, $msg);
}
/**
* Get the current mode.
*
* @return string
*/
public static function getMode()
{
return self::$mode;
}
}
|
| #9 | Application->mainDev /srv/ChatHispanoEngine/releases/20250927141530/apps/Application.php (122) <?php
// namespace ChatHispanoEngine;
/**
* Application driver class to initialize Phalcon and
* other resources.
*/
class Application extends \Phalcon\Mvc\Application
{
private static $mode = 'dev';
private static $DEFAULT_MODULE = 'api';
public const MODE_PRODUCTION = 'prod';
public const MODE_STAGING = 'staging';
public const MODE_TEST = 'test';
public const MODE_DEVELOPMENT = 'dev';
/**
* Set application mode and error reporting level.
*/
public function __construct($defaultModule, $env = 'dev')
{
$this->modules = array(
'core' => array(
'className' => 'ChatHispanoEngine\Core\Module',
'path' => __DIR__.'/Core/Module.php',
),
'api' => array(
'className' => 'ChatHispanoEngine\Api\Module',
'path' => __DIR__.'/Api/Module.php',
),
'login' => array(
'className' => 'ChatHispanoEngine\Login\Module',
'path' => __DIR__.'/Login/Module.php',
),
'oidc' => array(
'className' => 'ChatHispanoEngine\Oidc\Module',
'path' => __DIR__.'/Oidc/Module.php',
),
'web' => array(
'className' => 'ChatHispanoEngine\Web\Module',
'path' => __DIR__.'/Web/Module.php',
),
'backoffice' => array(
'className' => 'ChatHispanoEngine\Backoffice\Module',
'path' => __DIR__.'/Backoffice/Module.php',
),
'movil' => array(
'className' => 'ChatHispanoEngine\Movil\Module',
'path' => __DIR__.'/Movil/Module.php',
),
'regwebexternal' => array(
'className' => 'ChatHispanoEngine\RegWebExternal\Module',
'path' => __DIR__.'/Regwebexternal/Module.php',
),
'cdn' => array(
'className' => 'ChatHispanoEngine\Cdn\Module',
'path' => __DIR__.'/Cdn/Module.php',
),
'shorten' => array(
'className' => 'ChatHispanoEngine\Shorten\Module',
'path' => __DIR__.'/Shorten/Module.php',
),
);
static::$DEFAULT_MODULE = $defaultModule;
self::$mode = $env;
self::$mode = trim(file_get_contents(__DIR__.'/../config/environment.txt'));
define('ENVIRONMENT', self::$mode);
if (!defined('PHALCON_MODE')) {
$mode = getenv('PHALCON_MODE');
$mode = $mode ? $mode : self::$mode;
define('PHALCON_MODE', $mode);
}
switch (self::getMode()) {
case self::MODE_PRODUCTION:
case self::MODE_STAGING:
error_reporting(0);
break;
case self::MODE_TEST:
case self::MODE_DEVELOPMENT:
ini_set('display_errors', 'On');
error_reporting(E_ALL);
break;
}
}
/**
* Register the services here to make them general or register in
* the ModuleDefinition to make them module-specific.
*/
protected function _registerServices()
{
$defaultModule = self::$DEFAULT_MODULE;
$modules = $this->modules;
$config = include __DIR__.'/../config/config.php';
$env_config = include __DIR__.'/../config/config_'.ENVIRONMENT.'.php';
$config->merge($env_config);
$di = new \Phalcon\DI\FactoryDefault();
include __DIR__.'/../config/loader.php';
include __DIR__.'/../config/services.php';
include __DIR__.'/../config/routing.php';
$this->setDI($di);
}
/**
* Run the application.
*/
public function main()
{
if (static::MODE_PRODUCTION === static::getMode()) {
$this->mainProd();
} else {
$this->mainDev();
}
}
private function getRequestUri()
{
if (!isset($_SERVER)) {
return "/";
}
if (!is_array($_SERVER)) {
return "/";
}
if (!isset($_SERVER['REQUEST_URI'])) {
return "/";
}
return $_SERVER['REQUEST_URI'];
}
/**
* Run the development environment.
*/
private function mainDev()
{
(new \Phalcon\Support\Debug())->listen();
$this->_registerServices();
$this->registerModules($this->modules);
$response = $this->handle($this->getRequestUri());
$response->send();
}
/**
* Run the production environment.
*/
private function mainProd()
{
try {
$this->registerModules($this->modules);
$this->_registerServices();
$response = $this->handle($this->getRequestUri());
$response->send();
} catch (\Exception $e) {
$logger = new \Phalcon\Logger\Adapter\Stream(__DIR__.'/../logs/'.date('Y-m-d').'.log');
$msg = "[".$_SERVER['SERVER_NAME']."] [".$_SERVER['REQUEST_URI']."] [".$e->getCode()."] ".$e->getMessage()." at ".$e->getFile()." (".$e->getLine().")";
$msg .= "\n".$e->getTraceAsString();
$logger->process(new \Phalcon\Logger\Item($msg, "error", 100));
$logger->close();
// remove view contents from buffer
ob_clean();
$errorCode = 500;
$errorView = __DIR__.'/../public/errors/error.html';
if (401 === $e->getCode()) {
// 401 UNAUTHORIZED
$errorCode = 401;
} elseif (403 === $e->getCode()) {
// 403 FORBIDDEN
$errorCode = 403;
} elseif (404 === $e->getCode()
|| $e instanceof Phalcon\Mvc\View\Exception
|| $e instanceof Phalcon\Mvc\Dispatcher\Exception) {
// 404 NOT FOUND
$errorCode = 404;
}
// Get error view contents. Since we are including the view
// file here you can use PHP and local vars inside the error view.
ob_start();
include_once $errorView;
$contents = ob_get_contents();
ob_end_clean();
// send view to header
$response = $this->getDI()->getShared('response');
$response->resetHeaders()
->setStatusCode($errorCode, null)
->setContent($contents)
->send()
;
/**
* We try to register in MongoDB the error to be able to
* track it in backoffice and/or receive emails
*/
try {
$system_log_manager = $this->getDI()->get('system_log_manager');
if ($errorCode == 500) {
$system_log_manager->createError([
'ip' => $_SERVER['SERVER_ADDR'],
'host' => $_SERVER['SERVER_NAME'],
'process' => 'php-fpm',
'message' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
]);
} else {
$system_log_manager->createWarning([
'ip' => $_SERVER['SERVER_ADDR'],
'host' => $_SERVER['SERVER_NAME'],
'process' => 'php-fpm',
'message' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
]);
}
} catch (\Exception $e) {
}
}
}
public function slowLog($t)
{
$config = $this->getDI()->get('config');
$irc_manager = $this->getDI()->get('inspircd_irc_manager');
$server = gethostname() ? gethostname() : 'unknown';
$uri = "https://".$_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI'];
if (substr($_SERVER['REQUEST_URI'], 0, 10) == '/historias') {
return;
}
$msg = "\x02[SLOWLOG] [".str_pad($server, 6, " ", STR_PAD_LEFT)."] [".str_pad(round($t, 1), 5, " ", STR_PAD_LEFT)."s] PATH=\x02 ".$_SERVER['REQUEST_URI']
."\x02 TYPE=\x02 ".$_SERVER['REQUEST_METHOD']."\x02 URI=\x02 ".$uri;
$irc_manager->privmsgOrderEnqueue('AAAAAI', $config->irc->debug_channel, $msg);
}
/**
* Get the current mode.
*
* @return string
*/
public static function getMode()
{
return self::$mode;
}
}
|
| #10 | Application->main /srv/ChatHispanoEngine/releases/20250927141530/public/index.php (13) <?php
date_default_timezone_set('Europe/Madrid');
require_once __DIR__.'/../vendor/autoload.php';
require_once __DIR__.'/../apps/Application.php';
if (isset($_SERVER['PHALCON_APP'])) {
$app = new Application($_SERVER['PHALCON_APP']);
} else {
$app = new Application('web');
}
$app->main();
try {
$t = microtime(true) - $_SERVER["REQUEST_TIME_FLOAT"];
if ($t > 6) {
$app->slowLog($t);
}
} catch (\Exception $e) {
}
|
| Key | Value |
|---|---|
| _url | /historias |
| Key | Value |
|---|---|
| USER | www-data |
| HOME | /var/www |
| HTTP_CONNECTION | close |
| HTTP_X_FORWARDED_FOR | 216.73.217.19 |
| HTTP_X_FORWARDED_PROTO | http |
| HTTP_COOKIE | PHPSESSID=ae805de96a16e5c49be760952e9be608 |
| HTTP_REFERER | https://test.chathispano.com/historias/navarra/2023-10-21/65346d3b33c59a14c402cfcb/dislike |
| HTTP_ACCEPT_ENCODING | gzip, br, zstd, deflate |
| HTTP_USER_AGENT | Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; ClaudeBot/1.0; +claudebot@anthropic.com) |
| HTTP_ACCEPT | */* |
| DISABLE_ANTEVENIO | 0 |
| DISABLE_MOBUSI | 0 |
| DISABLE_MASSARIUS | 0 |
| DISABLE_RELATEDCONTENT | 0 |
| DISABLE_ADSENSE | 0 |
| ADS_DEFER | 0 |
| PHALCON_APP | web |
| CHATHISPANOENGINE_REVISION | development |
| CHATHISPANOENGINE_INSTANCE | virtualbox |
| SCRIPT_FILENAME | /srv/ChatHispanoEngine/releases/20250927141530/public/index.php |
| PATH_TRANSLATED | /srv/ChatHispanoEngine/current/public |
| PATH_INFO | |
| HTTP_HOST | test.chathispano.com |
| REDIRECT_STATUS | 200 |
| SERVER_NAME | test.chathispano.com |
| SERVER_PORT | 80 |
| SERVER_ADDR | 10.234.61.101 |
| REMOTE_USER | |
| REMOTE_PORT | 36450 |
| REMOTE_ADDR | 10.234.61.153 |
| SERVER_SOFTWARE | nginx/1.26.3 |
| GATEWAY_INTERFACE | CGI/1.1 |
| REQUEST_SCHEME | http |
| SERVER_PROTOCOL | HTTP/1.1 |
| DOCUMENT_ROOT | /srv/ChatHispanoEngine/releases/20250927141530/public |
| DOCUMENT_URI | /index.php |
| REQUEST_URI | /historias |
| SCRIPT_NAME | /index.php |
| CONTENT_LENGTH | |
| CONTENT_TYPE | |
| REQUEST_METHOD | GET |
| QUERY_STRING | _url=/historias |
| FCGI_ROLE | RESPONDER |
| PHP_SELF | /index.php |
| REQUEST_TIME_FLOAT | 1781542643.0103 |
| REQUEST_TIME | 1781542643 |
| # | Path |
|---|---|
| 0 | /srv/ChatHispanoEngine/releases/20250927141530/public/index.php |
| 1 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/autoload.php |
| 2 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/composer/autoload_real.php |
| 3 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/composer/platform_check.php |
| 4 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/composer/ClassLoader.php |
| 5 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/composer/include_paths.php |
| 6 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/composer/autoload_static.php |
| 7 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/symfony/polyfill-mbstring/bootstrap.php |
| 8 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/symfony/polyfill-mbstring/bootstrap80.php |
| 9 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/symfony/deprecation-contracts/function.php |
| 10 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/amphp/amp/lib/functions.php |
| 11 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/amphp/amp/lib/Internal/functions.php |
| 12 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/react/promise/src/functions_include.php |
| 13 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/react/promise/src/functions.php |
| 14 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/symfony/polyfill-ctype/bootstrap.php |
| 15 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/symfony/polyfill-ctype/bootstrap80.php |
| 16 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/symfony/polyfill-intl-normalizer/bootstrap.php |
| 17 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/symfony/polyfill-intl-normalizer/bootstrap80.php |
| 18 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/symfony/polyfill-php85/bootstrap.php |
| 19 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/symfony/polyfill-php85/bootstrap80.php |
| 20 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/symfony/polyfill-php84/bootstrap.php |
| 21 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/symfony/polyfill-intl-grapheme/bootstrap.php |
| 22 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/symfony/polyfill-intl-grapheme/bootstrap80.php |
| 23 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/amphp/byte-stream/lib/functions.php |
| 24 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/illuminate/collections/functions.php |
| 25 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/illuminate/collections/helpers.php |
| 26 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/symfony/string/Resources/functions.php |
| 27 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/myclabs/deep-copy/src/DeepCopy/deep_copy.php |
| 28 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/ralouphie/getallheaders/src/getallheaders.php |
| 29 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/phpunit/phpunit/src/Framework/Assert/Functions.php |
| 30 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/symfony/clock/Resources/now.php |
| 31 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/symfony/polyfill-intl-idn/bootstrap.php |
| 32 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/symfony/translation/Resources/functions.php |
| 33 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/symfony/var-dumper/Resources/functions/dump.php |
| 34 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/guzzlehttp/guzzle/src/functions_include.php |
| 35 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/guzzlehttp/guzzle/src/functions.php |
| 36 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/symfony/polyfill-php80/bootstrap.php |
| 37 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/amphp/process/lib/functions.php |
| 38 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/amphp/serialization/src/functions.php |
| 39 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/amphp/sync/src/functions.php |
| 40 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/amphp/sync/src/ConcurrentIterator/functions.php |
| 41 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/illuminate/reflection/helpers.php |
| 42 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/psy/psysh/src/functions.php |
| 43 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/daverandom/libdns/src/functions.php |
| 44 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/illuminate/support/functions.php |
| 45 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/illuminate/support/helpers.php |
| 46 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/symfony/polyfill-php81/bootstrap.php |
| 47 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/amphp/dns/lib/functions.php |
| 48 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/codeception/codeception/functions.php |
| 49 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/mongodb/mongodb/src/functions.php |
| 50 | /srv/ChatHispanoEngine/releases/20250927141530/apps/Application.php |
| 51 | /srv/ChatHispanoEngine/releases/20250927141530/config/config.php |
| 52 | /srv/ChatHispanoEngine/releases/20250927141530/config/config_staging.php |
| 53 | /srv/ChatHispanoEngine/releases/20250927141530/config/loader.php |
| 54 | /srv/ChatHispanoEngine/releases/20250927141530/config/services.php |
| 55 | /srv/ChatHispanoEngine/releases/20250927141530/config/managers.php |
| 56 | /srv/ChatHispanoEngine/releases/20250927141530/config/routing.php |
| 57 | /srv/ChatHispanoEngine/releases/20250927141530/apps/Web/config/routing.php |
| 58 | /srv/ChatHispanoEngine/releases/20250927141530/apps/Web/Module.php |
| 59 | /srv/ChatHispanoEngine/releases/20250927141530/apps/Web/config/config.php |
| 60 | /srv/ChatHispanoEngine/releases/20250927141530/apps/Web/config/services.php |
| 61 | /srv/ChatHispanoEngine/releases/20250927141530/apps/Web/config/managers.php |
| 62 | /srv/ChatHispanoEngine/releases/20250927141530/apps/Web/Controllers/StoriesController.php |
| 63 | /srv/ChatHispanoEngine/releases/20250927141530/apps/Web/Controllers/BaseController.php |
| 64 | /srv/ChatHispanoEngine/releases/20250927141530/apps/Core/Controllers/BaseController.php |
| 65 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/iwalkalone/translator/src/Translator.php |
| 66 | /srv/ChatHispanoEngine/releases/20250927141530/apps/Web/Auth/Auth.php |
| 67 | /srv/ChatHispanoEngine/releases/20250927141530/apps/Core/Managers/InspIRCd/GlineManager.php |
| 68 | /srv/ChatHispanoEngine/releases/20250927141530/apps/Core/Models/InspIRCd/Gline.php |
| 69 | /srv/ChatHispanoEngine/releases/20250927141530/apps/Core/Models/BaseCollection.php |
| 70 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/mongodb/mongodb/src/Client.php |
| 71 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/composer/InstalledVersions.php |
| 72 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/composer/installed.php |
| 73 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/mongodb/mongodb/src/Builder/BuilderEncoder.php |
| 74 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/mongodb/mongodb/src/Codec/EncodeIfSupported.php |
| 75 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/mongodb/mongodb/src/Codec/Encoder.php |
| 76 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/mongodb/mongodb/src/Builder/Encoder/PipelineEncoder.php |
| 77 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/mongodb/mongodb/src/Builder/Encoder/RecursiveEncode.php |
| 78 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/mongodb/mongodb/src/Builder/Encoder/VariableEncoder.php |
| 79 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/mongodb/mongodb/src/Builder/Encoder/DictionaryEncoder.php |
| 80 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/mongodb/mongodb/src/Builder/Encoder/FieldPathEncoder.php |
| 81 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/mongodb/mongodb/src/Builder/Encoder/CombinedFieldQueryEncoder.php |
| 82 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/mongodb/mongodb/src/Builder/Encoder/QueryEncoder.php |
| 83 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/mongodb/mongodb/src/Builder/Encoder/OutputWindowEncoder.php |
| 84 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/mongodb/mongodb/src/Builder/Encoder/OperatorEncoder.php |
| 85 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/mongodb/mongodb/src/Builder/Encoder/DateTimeEncoder.php |
| 86 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/mongodb/mongodb/src/Database.php |
| 87 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/mongodb/mongodb/src/Collection.php |
| 88 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/mongodb/mongodb/src/Operation/FindOne.php |
| 89 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/mongodb/mongodb/src/Operation/Explainable.php |
| 90 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/mongodb/mongodb/src/Operation/Find.php |
| 91 | /srv/ChatHispanoEngine/releases/20250927141530/apps/Core/Managers/InspIRCd/ChannelManager.php |
| 92 | /srv/ChatHispanoEngine/releases/20250927141530/apps/Core/Models/Channel/Datasheet.php |
| 93 | /srv/ChatHispanoEngine/releases/20250927141530/apps/Core/Managers/VivelavitaManager.php |
| 94 | /srv/ChatHispanoEngine/releases/20250927141530/apps/Core/Managers/InspIRCd/ChannelLoggerManager.php |
| 95 | /srv/ChatHispanoEngine/releases/20250927141530/apps/Core/Models/InspIRCd/Channel/Story.php |
| 96 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/mongodb/mongodb/src/Operation/Count.php |
| Memory | |
|---|---|
| Usage | 4194304 |