HEX
Server: Apache
System: Linux server1.ariadata.co 4.18.0-553.120.1.el8_10.x86_64 #1 SMP Mon Apr 20 18:04:27 EDT 2026 x86_64
User: nepi (1051)
PHP: 7.4.33
Disabled: exec,passthru,shell_exec,system,show_source,popen,proc_open
Upload Files
File: /home/nepi/public_html/src/core/Directus/Application/CoreServicesProvider.php
<?php

namespace Directus\Application;

use Cache\Adapter\Apc\ApcCachePool;
use Cache\Adapter\Apcu\ApcuCachePool;
use Cache\Adapter\Common\PhpCachePool;
use Cache\Adapter\Filesystem\FilesystemCachePool;
use Cache\Adapter\Memcached\MemcachedCachePool;
use Cache\Adapter\Memcache\MemcacheCachePool;
use Cache\Adapter\PHPArray\ArrayCachePool;
use Cache\Adapter\Redis\RedisCachePool;
use Cache\Adapter\Void\VoidCachePool;
use Cocur\Slugify\Slugify;
use Directus\Application\ErrorHandlers\ErrorHandler;
use function Directus\array_get;
use Directus\Authentication\Provider;
use Directus\Authentication\Sso\Social;
use Directus\Authentication\User\Provider\UserTableGatewayProvider;
use Directus\Cache\Response;
use Directus\Cache\Exception\InvalidCacheAdapterException;
use Directus\Cache\Exception\InvalidCacheConfigurationException;
use Directus\Config\StatusMapping;
use Directus\Database\Connection;
use Directus\Database\Exception\ConnectionFailedException;
use Directus\Database\Schema\DataTypes;
use Directus\Database\Schema\Object\Field;
use Directus\Database\Schema\SchemaFactory;
use Directus\Database\Schema\SchemaManager;
use Directus\Database\TableGateway\BaseTableGateway;
use Directus\Database\TableGateway\DirectusPermissionsTableGateway;
use Directus\Database\TableGateway\DirectusUsersTableGateway;
use Directus\Database\TableGateway\RelationalTableGateway;
use Directus\Database\SchemaService;
use Directus\Embed\EmbedManager;
use Directus\Exception\ForbiddenException;
use Directus\Exception\MissingStorageConfigurationException;
use Directus\Exception\RuntimeException;
use Directus\Filesystem\Files;
use Directus\Filesystem\Filesystem;
use Directus\Filesystem\FilesystemFactory;
use function Directus\generate_uuid4;
use function Directus\get_api_project_from_request;
use function Directus\get_directus_files_settings;
use function Directus\get_directus_setting;
use function Directus\get_url;
use Directus\Hash\HashManager;
use Directus\Hook\Emitter;
use Directus\Hook\Payload;
use function Directus\is_a_url;
use function Directus\is_iso8601_datetime;
use Directus\Logger\Exception\InvalidLoggerConfigurationException;
use Directus\Mail\Mailer;
use Directus\Mail\TransportManager;
use Directus\Mail\Transports\SendMailTransport;
use Directus\Mail\Transports\SmtpTransport;
use function Directus\normalize_exception;
use Directus\Permissions\Acl;
use Directus\Services\AuthService;
use Directus\Session\Session;
use Directus\Session\Storage\NativeSessionStorage;
use Directus\Util\ArrayUtils;
use Directus\Util\DateTimeUtils;
use Directus\Util\Installation\InstallerUtils;
use Directus\Util\StringUtils;
use League\Flysystem\Adapter\Local;
use Monolog\Formatter\LineFormatter;
use Monolog\Handler\StreamHandler;
use Monolog\Logger;
use Slim\Views\Twig;
use Zend\Db\TableGateway\TableGateway;
use Directus\Api\Routes\Roles;
use function Directus\get_random_string;

class CoreServicesProvider
{
    public function register($container)
    {
        $container['database'] = $this->getDatabase();
        $container['logger'] = $this->getLogger();
        // TODO: Put hooks/filters listeners out of this service
        // for easy access and code readability
        $container['hook_emitter'] = $this->getEmitter();
        $container['auth'] = $this->getAuth();
        $container['external_auth'] = $this->getExternalAuth();
        $container['session'] = $this->getSession();
        $container['slugify'] = $this->getSlugify();
        $container['acl'] = $this->getAcl();
        $container['errorHandler'] = $this->getErrorHandler();
        $container['phpErrorHandler'] = $this->getErrorHandler();
        $container['schema_adapter'] = $this->getSchemaAdapter();
        $container['schema_manager'] = $this->getSchemaManager();
        $container['schema_factory'] = $this->getSchemaFactory();
        $container['hash_manager'] = $this->getHashManager();
        $container['embed_manager'] = $this->getEmbedManager();
        $container['filesystem'] = $this->getFileSystem();
        $container['filesystem_thumb'] = $this->getThumbFilesystem();
        $container['files'] = $this->getFiles();
        $container['files_thumb'] = $this->getThumbFiles();
        $container['mailer_transport'] = $this->getMailerTransportManager();
        $container['mailer'] = $this->getMailer();
        $container['mail_view'] = $this->getMailView();
        $container['app_settings'] = $this->getSettings();
        $container['status_mapping'] = $this->getStatusMapping();

        // Move this separately to avoid clogging one class
        $container['cache'] = $this->getCache();
        $container['response_cache'] = $this->getResponseCache();

        $container['services'] = $this->getServices($container);
    }

    /**
     * @return \Closure
     */
    protected function getLogger()
    {
        /**
         * @param Container $container
         * @return Logger
         */
        $logger = function ($container) {
            $logger = new Logger(sprintf('api[%s]', get_api_project_from_request()));
            $formatter = new LineFormatter();
            $formatter->allowInlineLineBreaks();
            $formatter->includeStacktraces();
            // TODO: Move log configuration outside "slim app" settings
            $path = $container->get('path_base') . '/logs';
            $config = $container->get('config');
            if ($config->has('logger.path')) {
                $path = $config->get('logger.path');
            }

            $pathIsStream = $path == 'php://stdout' || $path == 'php://stderr';
            if (!$pathIsStream) {
                if (file_exists($path)) {
                    if (is_file($path)) {
                        $path = dirname($path);
                    }
                } else {
                    mkdir($path, 0777, true);
                }

                if (!is_dir($path) || !is_writeable($path)) {
                    throw new InvalidLoggerConfigurationException('path');
                }

                if (substr($path, -1) == '/') {
                    $path = substr($path, 0, strlen($path) - 1);
                }
            }

            $filenameFormat = '%s.%s.log';
            foreach (Logger::getLevels() as $name => $level) {
                if ($pathIsStream) {
                    $loggerPath = $path;
                } else {
                    $loggerPath = $path . '/' . sprintf($filenameFormat, strtolower($name), date('Y-m-d'));
                }
                $handler = new StreamHandler(
                    $loggerPath,
                    $level,
                    false
                );
                $handler->setFormatter($formatter);
                $logger->pushHandler($handler);
            }

            return $logger;
        };

        return $logger;
    }

    /**
     * @return \Closure
     */
    protected function getErrorHandler()
    {
        /**
         * @param Container $container
         *
         * @return ErrorHandler
         */
        $errorHandler = function (Container $container) {
            $hookEmitter = $container['hook_emitter'];

            return new ErrorHandler($hookEmitter, [
                'env' => $container->get('config')->get('env', 'development')
            ]);
        };

        return $errorHandler;
    }

    /**
     * @return \Closure
     */
    protected function getEmitter()
    {
        return function (Container $container) {
            $emitter = new Emitter();
            $cachePool = $container->get('cache');

            // Cache subscriptions
            $emitter->addAction('postUpdate', function (RelationalTableGateway $gateway, $data) use ($cachePool) {
                if (isset($data[$gateway->primaryKeyFieldName])) {
                    $cachePool->invalidateTags(['entity_' . $gateway->getTable() . '_' . $data[$gateway->primaryKeyFieldName]]);
                }
            });

            $cacheTableTagInvalidator = function ($tableName) use ($cachePool) {
                $cachePool->invalidateTags(['table_' . $tableName]);
            };
            foreach (['item.create:after', 'item.delete:after', 'item.update:after', 'collection.update:after', 'collection.delete:after'] as $action) {
                $emitter->addAction($action, $cacheTableTagInvalidator);
            }

            $emitter->addAction('item.update.directus_permissions:after', function ($data) use ($container, $cachePool) {
                $acl = $container->get('acl');
                $dbConnection = $container->get('database');
                $privileges = new DirectusPermissionsTableGateway($dbConnection, $acl);
                $record = $privileges->fetchById($data['id']);
                $cachePool->invalidateTags(['permissions_collection_' . $record['collection']]);
            });
            // /Cache subscriptions

            $emitter->addAction('application.error', function ($e) use ($container) {
                /** @var Logger $logger */
                $logger = $container->get('logger');

                $logger->error(normalize_exception($e));
            });
            $emitter->addFilter('response', function (Payload $payload) use ($container) {
                /** @var Acl $acl */
                $acl = $container->get('acl');
                if ($acl->isPublic() || !$acl->getUserId()) {
                    $payload->set('public', true);
                }
                return $payload;
            });
            $emitter->addAction('item.create.directus_roles', function ($data) use ($container) {
                $acl = $container->get('acl');
                $zendDb = $container->get('database');
                $privilegesTable = new DirectusPermissionsTableGateway($zendDb, $acl);

                $defaultPermissions = InstallerUtils::getDefaultPermissions();

                foreach ($defaultPermissions as $collection => $permissions) {
                    if (!ArrayUtils::isNumericKeys($permissions)) {
                        $permissions = [$permissions];
                    }

                    foreach ($permissions as $permission) {
                        $privilegesTable->insertPrivilege(array_merge($permission, [
                            'role' => $data['id'],
                            'collection' => $collection
                        ]));
                    }
                }
            });
            $emitter->addFilter('item.create:before', function (Payload $payload) use ($container) {
                $collectionName = $payload->attribute('collection_name');
                $collection = SchemaService::getCollection($collectionName);
                /** @var Acl $acl */
                $acl = $container->get('acl');


                if ($dateCreated = $collection->getDateCreatedField()) {
                    $payload[$dateCreated->getName()] = DateTimeUtils::nowInUTC()->toString();
                }

                if ($dateModified = $collection->getDateModifiedField()) {
                    $payload[$dateModified->getName()] = DateTimeUtils::nowInUTC()->toString();
                }

                // Directus Users created user are themselves (primary key)
                // populating that field will be a duplicated primary key violation
                if ($collection->getName() === 'directus_users') {
                    return $payload;
                }

                $userCreated = $collection->getUserCreatedField();
                $userModified = $collection->getUserModifiedField();

                if ($userCreated) {
                    $payload[$userCreated->getName()] = $acl->getUserId();
                }

                if ($userModified) {
                    $payload[$userModified->getName()] = $acl->getUserId();
                }

                return $payload;
            }, Emitter::P_HIGH);

            $emitter->addFilter('item.update:before', function (Payload $payload) use ($container) {
                $collection = SchemaService::getCollection($payload->attribute('collection_name'));

                /** @var Acl $acl */
                $acl = $container->get('acl');
                if ($dateModified = $collection->getDateModifiedField()) {
                    $payload[$dateModified->getName()] = DateTimeUtils::nowInUTC()->toString();
                }

                if ($userModified = $collection->getUserModifiedField()) {
                    $payload[$userModified->getName()] = $acl->getUserId();
                }

                // NOTE: exclude date_uploaded from updating a file record
                if ($collection->getName() === 'directus_files') {
                    $payload->remove('date_uploaded');
                }

                return $payload;
            }, Emitter::P_HIGH);

            $addFilesUrl = function ($rows) {
                return \Directus\append_storage_information($rows);
            };
            $emitter->addFilter('item.read.directus_files:before', function (Payload $payload) {
                $columns = $payload->get('columns');
                if (!in_array('filename_disk', $columns)) {
                    $columns[] = 'filename_disk';
                    $payload->set('columns', $columns);
                }
                if (!in_array('filename_download', $columns)) {
                    $columns[] = 'filename_download';
                    $payload->set('columns', $columns);
                }
                return $payload;
            });

            // -- Data types -----------------------------------------------------------------------------
            // TODO: improve Parse boolean/json/array almost similar code
            $parseArray = function ($decode, $collection, $data) use ($container) {
                /** @var SchemaManager $schemaManager */
                $schemaManager = $container->get('schema_manager');
                $collectionObject = $schemaManager->getCollection($collection);

                foreach ($collectionObject->getFields(array_keys($data)) as $field) {
                    if (!DataTypes::isArray($field->getType())) {
                        continue;
                    }

                    $key = $field->getName();
                    $value = $data[$key];

                    // convert string to array
                    $decodeFn = function ($value) {
                        // if empty string, empty array, null or false
                        if (empty($value) && !is_numeric($value)) {
                            $value = [];
                        } else {
                            $value = !is_array($value) ? explode(',', $value) : $value;
                        }

                        return $value;
                    };

                    // convert array into string
                    $encodeFn = function ($value) {
                        return is_array($value) ? implode(',', $value) : $value;
                    };

                    // NOTE: If the array has value with comma it will be treat as a separate value
                    // should we encode the commas to "hide" the comma when splitting the values?
                    if ($decode) {
                        $value = $decodeFn($value);
                    } else {
                        $value = $encodeFn($value);
                    }

                    $data[$key] = $value;
                }

                return $data;
            };

            $parseBoolean = function ($collection, $data) use ($container) {
                /** @var SchemaManager $schemaManager */
                $schemaManager = $container->get('schema_manager');
                $collectionObject = $schemaManager->getCollection($collection);

                foreach ($collectionObject->getFields(array_keys($data)) as $field) {
                    if (!DataTypes::isBoolean($field->getType())) {
                        continue;
                    }

                    $key = $field->getName();
                    $data[$key] = boolval($data[$key]);
                }

                return $data;
            };
            $parseJson = function ($decode, $collection, $data) use ($container) {
                /** @var SchemaManager $schemaManager */
                $schemaManager = $container->get('schema_manager');
                $collectionObject = $schemaManager->getCollection($collection);

                foreach ($collectionObject->getFields(array_keys($data)) as $field) {
                    if (!DataTypes::isJson($field->getType())) {
                        continue;
                    }

                    $key = $field->getName();
                    $value = $data[$key];

                    if ($decode === true) {
                        $value = is_string($value) ? json_decode($value) : $value;
                    } elseif ($value !== null) {
                        $value = !is_string($value) ? json_encode($value) : $value;
                    }

                    $data[$key] = $value;
                }

                return $data;
            };

            $emitter->addFilter('item.create:before', function (Payload $payload) use ($parseJson, $parseArray) {
                $payload->replace(
                    $parseJson(
                        false,
                        $payload->attribute('collection_name'),
                        $payload->getData()
                    )
                );

                $payload->replace($parseArray(false, $payload->attribute('collection_name'), $payload->getData()));

                return $payload;
            });
            $emitter->addFilter('item.update:before', function (Payload $payload) use ($parseJson, $parseArray) {
                $payload->replace(
                    $parseJson(
                        false,
                        $payload->attribute('collection_name'),
                        $payload->getData()
                    )
                );
                $payload->replace(
                    $parseArray(
                        false,
                        $payload->attribute('collection_name'),
                        $payload->getData()
                    )
                );

                return $payload;
            });
            $emitter->addFilter('item.read', function (Payload $payload) use ($container, $parseJson, $parseArray, $parseBoolean) {
                $rows = $payload->getData();
                $collectionName = $payload->attribute('collection_name');
                /** @var SchemaManager $schemaManager */
                $schemaManager = $container->get('schema_manager');
                $collection = $schemaManager->getCollection($collectionName);

                $hasJsonField = $collection->hasJsonField();
                $hasBooleanField = $collection->hasBooleanField();
                $hasArrayField = $collection->hasArrayField();

                if (!$hasArrayField && !$hasBooleanField && !$hasJsonField) {
                    return $payload;
                }

                foreach ($rows as $key => $row) {
                    if ($hasJsonField) {
                        $row = $parseJson(true, $collectionName, $row);
                    }

                    if ($hasBooleanField) {
                        $row = $parseBoolean($collectionName, $row);
                    }

                    if ($hasArrayField) {
                        $row = $parseArray(true, $collectionName, $row);
                    }

                    $rows[$key] = $row;
                }

                $payload->replace($rows);

                return $payload;
            });
            // -------------------------------------------------------------------------------------------
            // Add file url and thumb url
            $emitter->addFilter('item.read.directus_files', function (Payload $payload) use ($addFilesUrl, $container) {

                $rows = $addFilesUrl($payload->getData());
                $payload->replace($rows);

                return $payload;
            });
            $emitter->addFilter('item.read.directus_users', function (Payload $payload) use ($container) {
                $acl = $container->get('acl');
                $rows = $payload->getData();
                $userId = $acl->getUserId();
                foreach ($rows as &$row) {
                    $omit = [
                        'password'
                    ];
                    // Authenticated user can see their private info
                    // Admin can see all users private info
                    if (!$acl->isAdmin() && $userId !== (int) $row['id']) {
                        $omit = array_merge($omit, [
                            'token',
                            'email_notifications',
                            'last_access_on',
                            'last_page'
                        ]);
                    }
                    $row = ArrayUtils::omit($row, $omit);
                }
                $payload->replace($rows);
                return $payload;
            });

            $onInsertOrUpdate = function (Payload $payload) use ($container) {
                /** @var SchemaManager $schemaManager */
                $schemaManager = $container->get('schema_manager');
                /** @var HashManager $hashManager */
                $hashManager = $container->get('hash_manager');
                $collectionName = $payload->attribute('collection_name');
                $collection = $schemaManager->getCollection($collectionName);
                $isSystemCollection = $schemaManager->isSystemCollection($collectionName);
                /** @var Field[] $slugMirrorFields */
                $slugMirrorFields = [];

                // Find all slug field mirroredField values
                foreach ($collection->getFields() as $field) {
                    if (!$field || !DataTypes::isSlugType($field->getType())) {
                        continue;
                    }

                    $fieldOptions = $options = $field->getOptions() ?: [];
                    $mirroredFieldName = ArrayUtils::get($fieldOptions, 'mirroredField');
                    if ($mirroredFieldName && ($mirroredField = $collection->getField($mirroredFieldName)) && DataTypes::isStringType($mirroredField->getType())) {
                        $slugMirrorFields[$mirroredFieldName] = $field;
                    }
                }

                // TODO: Use iterator instead of looping through a copy of the payload data (while ($payload->valid))
                $data = $payload->getData();
                foreach ($data as $key => $value) {
                    $field = $collection->getField($key);

                    // This value is being populated in another hook
                    if (!$field || DataTypes::isSystemDateTimeType($field->getType())) {
                        continue;
                    }

                    $type = $field->getType();
                    if (DataTypes::isHashType($type)) {
                        $options = $field->getOptions() ?: ['hasher' => 'core'];
                        $hashedString = $hashManager->hash($value, $options);
                        $payload->set($key, $hashedString);

                        continue;
                    }

                    if (array_key_exists($key, $slugMirrorFields) && !$payload->has($slugMirrorFields[$key]->getName())) {
                        /** @var Slugify $slugify */
                        $slugify = $container->get('slugify');

                        $slugField = $slugMirrorFields[$key];
                        $slugOptions = $slugField->getOptions() ?: [];

                        ArrayUtils::renameSome($slugOptions, [
                            'forceLowercase' => 'lowercase',
                        ]);

                        $slugOptions = ArrayUtils::defaults(['lowercase' => true], $slugOptions);

                        $payload->set($slugField->getName(), $slugify->slugify($value, $slugOptions));

                        continue;
                    }

                    // Skip if the date/time is empty
                    if (!$value) {
                        continue;
                    }

                    if (DataTypes::isDateTimeType($type)) {
                        $dateTime = new DateTimeUtils($value);
                        if ($isSystemCollection || is_iso8601_datetime($value)) {
                            $dateTimeValue = $dateTime->toUTCString();
                        } else {
                            $dateTimeValue = $dateTime->toString();
                        }

                        $payload->set($key, $dateTimeValue);
                    } elseif (DataTypes::isDateType($type)) {
                        $dateTime = new DateTimeUtils($value);
                        $payload->set($key, $dateTime->toString(DateTimeUtils::DEFAULT_DATE_FORMAT));
                    } elseif (DataTypes::isTimeType($type)) {
                        $dateTime = new DateTimeUtils($value);
                        $payload->set($key, $dateTime->toString(DateTimeUtils::DEFAULT_TIME_FORMAT));
                    }
                }

                return $payload;
            };

            $generateExternalId = function (Payload $payload) {
                // generate an external id if none is passed
                if (!$payload->get('external_id')) {
                    $payload->set('external_id', generate_uuid4());
                }

                return $payload;
            };
            $emitter->addFilter('item.create.directus_users:before', $generateExternalId);
            $emitter->addFilter('item.create.directus_roles:before', $generateExternalId);

            $emitter->addFilter('item.create:before', $onInsertOrUpdate);
            $emitter->addFilter('item.update:before', $onInsertOrUpdate);

            $beforeSavingFiles = function ($payload) use ($container) {
                $acl = $container->get('acl');
                if (!$acl->canCreate('directus_files')) {
                    throw new ForbiddenException('You are not allowed to upload files');
                }

                return $payload;
            };
            $beforeUpdatingFiles = function ($payload) use ($container) {
                $acl = $container->get('acl');
                if (!$acl->canUpdate('directus_files')) {
                    throw new ForbiddenException('You are not allowed to edit files');
                }

                return $payload;
            };
            $beforeDeletingFiles = function ($payload) use ($container) {
                $acl = $container->get('acl');
                if (!$acl->canDelete('directus_files')) {
                    throw new ForbiddenException('You are not allowed to delete files');
                }

                return $payload;
            };
            $emitter->addAction('file.save', $beforeSavingFiles);
            $emitter->addAction('file.update', $beforeUpdatingFiles);
            // TODO: Make insert actions and filters
            $emitter->addFilter('item.create.directus_files:before', $beforeSavingFiles);
            $emitter->addFilter('item.update.directus_files:before', $beforeUpdatingFiles);
            $emitter->addFilter('item.delete.directus_files:before', $beforeDeletingFiles);

            $emitter->addAction('auth.request:credentials', function () use ($container) {
                /** @var Session $session */
                $session = $container->get('session');
                $useTelemetry =  get_directus_setting('telemetry', true);

                if ($useTelemetry) {
                    if ($session->getStorage()->get('telemetry') === true) {
                        return;
                    }

                    $data = [
                        'version' => Application::DIRECTUS_VERSION,
                        'url' => get_url(),
                        'type' => 'api'
                    ];
                    \Directus\request_send_json('POST', 'https://telemetry.directus.io/count', $data);

                    // NOTE: this only works when the client sends subsequent request with the same cookie
                    $session->getStorage()->set('telemetry', true);
                }
            });

            return $emitter;
        };
    }

    /**
     * @return \Closure
     */
    protected function getDatabase()
    {
        return function (Container $container) {
            $config = $container->get('config');
            $dbConfig = $config->get('database');
            $defaultConfig = [];

            // TODO: enforce/check required params

            $charset = ArrayUtils::get($dbConfig, 'charset', 'utf8mb4');
            $type = ArrayUtils::pull($dbConfig, 'type');

            // the "database" attribute is named "name"
            // and the "unix_socket" is named "socket"
            // in the directus configuration
            ArrayUtils::renameSome($dbConfig, [
                'name' => 'database',
                'socket' => 'unix_socket',
            ]);

            if (strtolower($type) === 'mysql') {
                $defaultConfig = [
                    \PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true,
                    \PDO::MYSQL_ATTR_INIT_COMMAND => sprintf('SET NAMES "%s"', $charset)
                ];
            }

            $parameters = array_merge($defaultConfig, $dbConfig, [
                'driver' => $type ? 'Pdo_' . $type : null,
                'charset' => $charset
            ]);

            if (!ArrayUtils::get($parameters, 'unix_socket')) {
                ArrayUtils::remove($parameters, 'unix_socket');
            } else {
                ArrayUtils::remove($parameters, 'host');
            }

            try {
                $db = new Connection($parameters);
                $db->connect();
            } catch (\Exception $e) {
                throw new ConnectionFailedException($e);
            }

            return $db;
        };
    }

    /**
     * @return \Closure
     */
    protected function getAuth()
    {
        return function (Container $container) {
            $db = $container->get('database');

            return new Provider(
                new UserTableGatewayProvider(
                    new DirectusUsersTableGateway($db)
                ),
                [
                    'secret_key' => $container->get('config')->get('auth.secret_key'),
                    'public_key' => $container->get('config')->get('auth.public_key'),
                    'ttl' => $container->get('config')->get('auth.ttl'),
                ]
            );
        };
    }

    /**
     * @return \Closure
     */
    protected function getExternalAuth()
    {
        return function (Container $container) {
            $config = $container->get('config');
            $providersConfig = $config->get('auth.social_providers', []);

            $socialAuth = new Social();

            $coreSso = \Directus\get_custom_x('auth', 'public/extensions/core/auth', true);
            $customSso = \Directus\get_custom_x('auth', 'public/extensions/custom/auth', true);

            // Flag the customs providers in order to choose the correct path for the icons
            $customSso = array_map(function ($config) {
                $config['custom'] = true;

                return $config;
            }, $customSso);

            $ssoProviders = array_merge($coreSso, $customSso);
            foreach ($providersConfig as $providerName => $providerConfig) {
                if (!is_array($providerConfig)) {
                    continue;
                }

                if (ArrayUtils::get($providerConfig, 'enabled') === false) {
                    continue;
                }

                if (array_key_exists($providerName, $ssoProviders) && isset($ssoProviders[$providerName]['provider'])) {
                    $providerInfo = $ssoProviders[$providerName];
                    $class = array_get($providerInfo, 'provider');
                    $custom = array_get($providerInfo, 'custom');

                    if (!class_exists($class)) {
                        throw new RuntimeException(sprintf('Class %s not found', $class));
                    }

                    $socialAuth->register($providerName, new $class($container, array_merge([
                        'custom' => $custom,
                        'callback_url' => \Directus\get_url('/' . get_api_project_from_request() . '/auth/sso/' . $providerName . '/callback')
                    ], $providerConfig)));
                }
            }

            return $socialAuth;
        };
    }

    /**
     * @return \Closure
     */
    protected function getSession()
    {
        return function (Container $container) {
            $config = $container->get('config');

            $session = new Session(new NativeSessionStorage($config->get('session', [])));
            $session->getStorage()->start();

            return $session;
        };
    }

    /**
     * @return \Closure
     */
    protected function getSlugify()
    {
        return function () {
            return new Slugify();
        };
    }

    /**
     * @return \Closure
     */
    protected function getAcl()
    {
        return function (Container $container) {
            return new Acl();
        };
    }

    /**
     * @return \Closure
     */
    protected function getCache()
    {
        return function (Container $container) {
            $config = $container->get('config');
            $poolConfig = $config->get('cache.pool');

            if (!$poolConfig || (!is_object($poolConfig) && empty($poolConfig['adapter']))) {
                $poolConfig = ['adapter' => 'void'];
            }

            $pool = new VoidCachePool();

            if (!$config->get('cache.enabled'))
                return $pool;

            if (is_object($poolConfig) && $poolConfig instanceof PhpCachePool) {
                $pool = $poolConfig;
            } else {
                if (!in_array($poolConfig['adapter'], ['apc', 'apcu', 'array', 'filesystem', 'memcached', 'memcache', 'redis', 'rediscluster', 'void'])) {
                    throw new InvalidCacheAdapterException();
                }

                $adapter = $poolConfig['adapter'];

                if ($adapter == 'apc') {
                    $pool = new ApcCachePool();
                }

                if ($adapter == 'apcu') {
                    $pool = new ApcuCachePool();
                }

                if ($adapter == 'array') {
                    $pool = new ArrayCachePool();
                }

                if ($adapter == 'filesystem') {
                    if (empty($poolConfig['path']) || !is_string($poolConfig['path'])) {
                        throw new InvalidCacheConfigurationException($adapter);
                    }

                    $cachePath = $poolConfig['path'];
                    if ($cachePath[0] !== '/') {
                        $basePath = $container->get('path_base');
                        $cachePath = rtrim($basePath, '/') . '/' . $cachePath;
                    }

                    $filesystemAdapter = new Local($cachePath);
                    $filesystem = new \League\Flysystem\Filesystem($filesystemAdapter);

                    $pool = new FilesystemCachePool($filesystem);
                }

                if ($adapter == 'memcached' || $adapter == 'memcache') {

                    if ($adapter == 'memcached' && !extension_loaded('memcached')) {
                        throw new InvalidCacheConfigurationException($adapter);
                    }

                    if ($adapter == 'memcache' && !extension_loaded('memcache')) {
                        throw new InvalidCacheConfigurationException($adapter);
                    }

                    $client = $adapter == 'memcached' ? new \Memcached() : new \Memcache();
                    if (isset($poolConfig['url'])) {
                        $urls = explode(';', $poolConfig['url']);
                        if ($urls ===  false) {
                            $urls = 'localhost:11211';
                        }
                        foreach ($urls as $url) {
                            $parts = parse_url($url);
                            $host = (isset($parts['host'])) ? $parts['host'] : 'localhost';
                            $port = (isset($parts['port'])) ? $parts['port'] : 11211;

                            $client->addServer($host, $port);
                        }
                    } else {
                        $host = (isset($poolConfig['host'])) ? $poolConfig['host'] : 'localhost';
                        $port = (isset($poolConfig['port'])) ? $poolConfig['port'] : 11211;

                        $client->addServer($host, $port);
                    }
                    $pool = $adapter == 'memcached' ? new MemcachedCachePool($client) : new MemcacheCachePool($client);
                }

                if ($adapter == 'redis' || $adapter == 'rediscluster') {

                    if (!extension_loaded('redis')) {
                        throw new InvalidCacheConfigurationException($adapter);
                    }

                    $host = (isset($poolConfig['host'])) ? $poolConfig['host'] : 'localhost';
                    $port = (isset($poolConfig['port'])) ? $poolConfig['port'] : 6379;
                    $socket = (isset($poolConfig['socket'])) ? $poolConfig['socket'] : null;
                    $auth = (isset($poolConfig['auth'])) ? $poolConfig['auth'] : null;

                    if ($adapter == 'rediscluster') {
                        $client = new \RedisCluster(NULL, ["$host:$port"]);
                    } else {
                        $client = new \Redis();
                        if ($socket) {
                            $client->connect($socket);
                        } else {
                            $client->connect($host, $port);
                        }
                    }

                    if ($auth) {
                        $client->auth($auth);
                    }

                    $pool = new RedisCachePool($client);
                }
            }

            return $pool;
        };
    }

    /**
     * @return \Closure
     */
    protected function getSchemaAdapter()
    {
        return function (Container $container) {
            $adapter = $container->get('database');
            $databaseName = $adapter->getPlatform()->getName();

            switch ($databaseName) {
                case 'MySQL':
                    return new \Directus\Database\Schema\Sources\MySQLSchema($adapter);
                    // case 'SQLServer':
                    //    return new SQLServerSchema($adapter);
                    // case 'SQLite':
                    //     return new \Directus\Database\Schemas\Sources\SQLiteSchema($adapter);
                    // case 'PostgreSQL':
                    //     return new PostgresSchema($adapter);
            }

            throw new \Exception('Unknown/Unsupported database: ' . $databaseName);
        };
    }

    /**
     * @return \Closure
     */
    protected function getSchemaManager()
    {
        return function (Container $container) {
            return new SchemaManager(
                $container->get('schema_adapter')
            );
        };
    }

    /**
     * @return \Closure
     */
    protected function getSchemaFactory()
    {
        return function (Container $container) {
            return new SchemaFactory(
                $container->get('schema_manager')
            );
        };
    }

    /**
     * @return \Closure
     */
    protected function getResponseCache()
    {
        return function (Container $container) {
            return new Response($container->get('cache'), $container->get('config')->get('cache.response_ttl'));
        };
    }

    /**
     * @return \Closure
     */
    protected function getHashManager()
    {
        return function (Container $container) {
            $hashManager = new HashManager();
            $basePath = $container->get('path_base');

            $path = implode(DIRECTORY_SEPARATOR, [
                $basePath,
                'custom',
                'hashers',
                '*.php'
            ]);

            $customHashersFiles = glob($path);
            $hashers = [];

            if ($customHashersFiles) {
                foreach ($customHashersFiles as $filename) {
                    $name = basename($filename, '.php');
                    // filename starting with underscore are skipped
                    if (StringUtils::startsWith($name, '_')) {
                        continue;
                    }

                    $hashers[] = '\\Directus\\Custom\\Hasher\\' . $name;
                }
            }

            foreach ($hashers as $hasher) {
                $hashManager->register(new $hasher());
            }

            return $hashManager;
        };
    }

    protected function getFileSystem()
    {
        return function (Container $container) {
            return new Filesystem(
                FilesystemFactory::createAdapter($this->getStorageConfiguration($container), 'root')
            );
        };
    }

    /**
     * @return \Closure
     */
    protected function getThumbFilesystem()
    {
        return function (Container $container) {
            return new Filesystem(
                FilesystemFactory::createAdapter($this->getStorageConfiguration($container), 'thumb_root')
            );
        };
    }

    /**
     * @return \Closure
     */
    protected function getMailerTransportManager()
    {
        return function (Container $container) {
            $config = $container->get('config');
            $manager = new TransportManager();

            $transports = [
                'smtp' => SmtpTransport::class,
                'sendmail' => SendMailTransport::class,
            ];

            $mailConfigs = $config->get('mail');
            foreach ($mailConfigs as $name => $mailConfig) {
                $transport = ArrayUtils::get($mailConfig, 'transport');

                if (array_key_exists($transport, $transports)) {
                    $transport = $transports[$transport];
                }

                $manager->register($name, $transport, $mailConfig);
            }

            return $manager;
        };
    }

    /**
     * @return \Closure
     */
    protected function getMailer()
    {
        return function (Container $container) {
            return new Mailer($container->get('mailer_transport'));
        };
    }

    /**
     * @return \Closure
     */
    protected function getSettings()
    {
        return function (Container $container) {
            $dbConnection = $container->get('database');
            $settingsTable = new TableGateway(SchemaManager::COLLECTION_SETTINGS, $dbConnection);

            return $settingsTable->select()->toArray();
        };
    }

    /**
     * @return \Closure
     */
    protected function getStatusMapping()
    {
        return function (Container $container) {
            $statusMapping = get_directus_setting('status_mapping');

            if (is_string($statusMapping)) {
                $statusMapping = json_decode($statusMapping, true);
            }

            if (!is_array($statusMapping)) {
                $statusMapping = [];
            }

            return new StatusMapping($statusMapping);
        };
    }

    /**
     * @return \Closure
     */
    protected function getMailView()
    {
        return function (Container $container) {
            $basePath = $container->get('path_base');

            return new Twig([
                $basePath . '/public/extensions/custom/mail',
                $basePath . '/src/mail'
            ]);
        };
    }

    /**
     * @return \Closure
     */
    protected function getFiles()
    {
        return function (Container $container) {
            // Convert result into a key-value array
            $filesSettings = get_directus_files_settings();

            $filesystem = $container->get('filesystem');
            $config = $container->get('config');
            $config = $config->get('storage', []);
            $emitter = $container->get('hook_emitter');

            return new Files(
                $filesystem,
                $config,
                $filesSettings,
                $emitter
            );
        };
    }

    /**
     * @return \Closure
     */
    protected function getThumbFiles()
    {
        return function (Container $container) {
            // Convert result into a key-value array
            $filesSettings = get_directus_files_settings();

            $filesystem = $container->get('filesystem_thumb');
            $config = $container->get('config');
            $config = $config->get('storage', []);
            $emitter = $container->get('hook_emitter');

            return new Files(
                $filesystem,
                $config,
                $filesSettings,
                $emitter
            );
        };
    }

    protected function getEmbedManager()
    {
        return function (Container $container) {
            $app = Application::getInstance();
            $embedManager = new EmbedManager();

            // Fetch files settings
            try {
                $settings = get_directus_files_settings();
            } catch (\Exception $e) {
                $settings = [];
                /** @var Logger $logger */
                $logger = $container->get('logger');
                $logger->warning($e->getMessage());
            }

            $providers = [
                '\Directus\Embed\Provider\VimeoProvider',
                '\Directus\Embed\Provider\YoutubeProvider'
            ];

            $path = implode(DIRECTORY_SEPARATOR, [
                $app->getContainer()->get('path_base'),
                'custom',
                'embeds',
                '*.php'
            ]);

            $customProvidersFiles = glob($path);
            if ($customProvidersFiles) {
                foreach ($customProvidersFiles as $filename) {
                    $providers[] = '\\Directus\\Embed\\Provider\\' . basename($filename, '.php');
                }
            }

            foreach ($providers as $providerClass) {
                $provider = new $providerClass($settings);
                $embedManager->register($provider);
            }

            return $embedManager;
        };
    }

    /**
     * Register all services
     *
     * @param Container $mainContainer
     *
     * @return \Closure
     *
     * @internal param Container $container
     *
     */
    protected function getServices(Container $mainContainer)
    {
        // A services container of all Directus services classes
        return function () use ($mainContainer) {
            $container = new Container();

            // =============================================================================
            // Register all services
            // -----------------------------------------------------------------------------
            // TODO: Set a place to load all the services
            // =============================================================================
            $container['auth'] = $this->getAuthService($mainContainer);

            return $container;
        };
    }

    /**
     * @param Container $container Application container
     *
     * @return \Closure
     */
    protected function getAuthService(Container $container)
    {
        return function () use ($container) {
            return new AuthService($container);
        };
    }

    /**
     * @param Container $container
     *
     * @return array
     *
     * @throws MissingStorageConfigurationException
     */
    protected function getStorageConfiguration(Container $container)
    {
        $config = $container->get('config');
        $storageConfig = $config->get('storage');

        if (!$storageConfig) {
            throw new MissingStorageConfigurationException();
        }

        return $storageConfig;
    }
}