Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactored Container configuration for project types #183

Draft
wants to merge 5 commits into
base: 4.5
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
<?php

/**
* @copyright Copyright (C) Ibexa AS. All rights reserved.
* @license For full copyright and license information view LICENSE file distributed with this source code.
*/
declare(strict_types=1);

namespace Ibexa\Bundle\Core\DependencyInjection\Configuration\ContainerConfigurator;

use Ibexa\Bundle\Core\DependencyInjection\Configuration\ContainerConfiguratorInterface;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader;

class Generic implements ContainerConfiguratorInterface
{
/**
* @throws \Exception
*/
public function configure(ContainerBuilder $container): void
{
// One of `legacy` (default) or `solr`
$container->setParameter('search_engine', '%env(SEARCH_ENGINE)%');

// Session save path as used by symfony session handlers (e.g. used for dsn with redis)
$container->setParameter('ibexa.session.save_path', '%kernel.project_dir%/var/sessions/%kernel.environment%');

// Predefined pools are located in config/packages/cache_pool/
// You can add your own cache pool to the folder mentioned above.
// In order to change the default cache_pool use environmental variable export.
// The line below must not be altered as required cache service files are resolved based on environmental config.
$container->setParameter('cache_pool', '%env(CACHE_POOL)%');

// By default, cache ttl is set to 24h, when using Varnish you can set a much higher value. High values depends on
// using IbexaHttpCacheBundle (default as of v1.12) which by design expires affected cache on changes
$container->setParameter('httpcache_default_ttl', '%env(HTTPCACHE_DEFAULT_TTL)%');

// Settings for HttpCache
$container->setParameter('purge_server', '%env(HTTPCACHE_PURGE_SERVER)%');

// Identifier used to generate the CSRF token. Commenting this line will result in authentication
// issues both in AdminUI and REST calls
$container->setParameter('ibexa.rest.csrf_token_intention', 'authenticate');

// Varnish invalidation/purge token (for use on platform.sh, Ibexa Cloud and other places you can't use IP for ACL)
$container->setParameter('varnish_invalidate_token', '%env(resolve:default::HTTPCACHE_VARNISH_INVALIDATE_TOKEN)%');

// Compile time handlers
// These are defined at compile time, and hence can't be set at runtime using env()
// config/env/generic.php takes care about letting you set them by env variables

// Session handler, by default set to file based (instead of ~) in order to be able to use %ibexa.session.save_path%
$container->setParameter('ibexa.session.handler_id', 'session.handler.native_file');

// Purge type used by HttpCache system ("local", "varnish"/"http", and on ee also "fastly")
$container->setParameter('purge_type', '%env(HTTPCACHE_PURGE_TYPE)%');

$container->setParameter('solr_dsn', '%env(SOLR_DSN)%');
$container->setParameter('solr_core', '%env(SOLR_CORE)%');

$projectDir = $container->getParameter('kernel.project_dir');

if (null !== ($dfsNfsPath = $_SERVER['DFS_NFS_PATH'] ?? null)) {
$container->setParameter('dfs_nfs_path', $dfsNfsPath);

$parameterMap = [
'dfs_database_charset' => 'database_charset',
'dfs_database_driver' => 'database_driver',
'dfs_database_collation' => 'database_collation',
];

foreach ($parameterMap as $dfsParameter => $platformParameter) {
$container->setParameter(
$dfsParameter,
$_SERVER[strtoupper($dfsParameter)] ?? $container->getParameter($platformParameter)
);
}

$loader = new Loader\YamlFileLoader($container, new FileLocator($projectDir . '/config/packages/dfs'));
$loader->load('dfs.yaml');
}

// Cache settings
// If CACHE_POOL env variable is set, check if there is a yml file that needs to be loaded for it
if (
null !== ($pool = $_SERVER['CACHE_POOL'] ?? null) &&
file_exists($projectDir . "/config/packages/cache_pool/${pool}.yaml")
) {
$loader = new Loader\YamlFileLoader($container, new FileLocator($projectDir . '/config/packages/cache_pool'));
$loader->load($pool . '.yaml');
}

if (null !== ($purgeType = $_SERVER['HTTPCACHE_PURGE_TYPE'] ?? null)) {
$container->setParameter('purge_type', $purgeType);
$container->setParameter('ibexa.http_cache.purge_type', $purgeType);
}

if (null !== ($value = $_SERVER['MAILER_TRANSPORT'] ?? null)) {
$container->setParameter('mailer_transport', $value);
}

if (null !== ($value = $_SERVER['LOG_TYPE'] ?? null)) {
$container->setParameter('log_type', $value);
}

if (null !== ($value = $_SERVER['SESSION_HANDLER_ID'] ?? null)) {
$container->setParameter('ibexa.session.handler_id', $value);
}

if (null !== ($value = $_SERVER['SESSION_SAVE_PATH'] ?? null)) {
$container->setParameter('ibexa.session.save_path', $value);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
<?php

/**
* @copyright Copyright (C) Ibexa AS. All rights reserved.
* @license For full copyright and license information view LICENSE file distributed with this source code.
*/
declare(strict_types=1);

namespace Ibexa\Bundle\Core\DependencyInjection\Configuration\ContainerConfigurator;

use Ibexa\Bundle\Core\DependencyInjection\Configuration\ContainerConfiguratorInterface;
use Ibexa\Bundle\Core\Session\Handler\NativeSessionHandler;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader;

class PlatformSh implements ContainerConfiguratorInterface
{
/**
* @throws \Exception
*/
public function configure(ContainerBuilder $container): void
{
$projectDir = $container->getParameter('kernel.project_dir');

// Will not be executed on build step
$relationships = $_SERVER['PLATFORM_RELATIONSHIPS'] ?? null;
if (null === $relationships) {
return;
}
$routes = $_SERVER['PLATFORM_ROUTES'];

$relationships = json_decode(base64_decode($relationships), true);
$routes = json_decode(base64_decode($routes), true);

// PLATFORMSH_DFS_NFS_PATH is different compared to DFS_NFS_PATH in the sense that it is relative to ezplatform dir
// DFS_NFS_PATH is an absolute path
if (null !== ($dfsNfsPath = $_SERVER['PLATFORMSH_DFS_NFS_PATH'] ?? null)) {
$container->setParameter('dfs_nfs_path', sprintf('%s/%s', $projectDir, $dfsNfsPath));

// Map common parameters
$container->setParameter('dfs_database_charset', $container->getParameter('database_charset'));
$container->setParameter(
'dfs_database_collation',
$container->getParameter('database_collation')
);
if (\array_key_exists('dfs_database', $relationships)) {
// process dedicated P.sh dedicated config
foreach ($relationships['dfs_database'] as $endpoint) {
if (empty($endpoint['query']['is_master'])) {
continue;
}
$container->setParameter('dfs_database_driver', 'pdo_' . $endpoint['scheme']);
$container->setParameter(
'dfs_database_url',
sprintf(
'%s://%s:%s:%d@%s/%s',
$endpoint['scheme'],
$endpoint['username'],
$endpoint['password'],
$endpoint['port'],
$endpoint['host'],
$endpoint['path']
)
);
}
} else {
// or set fallback from the Repository database, if not configured
$container->setParameter('dfs_database_driver', $container->getParameter('database_driver'));
}

$loader = new Loader\YamlFileLoader($container, new FileLocator($projectDir . '/config/packages/dfs'));
$loader->load('dfs.yaml');
}

// Use Redis-based caching if possible.
if (isset($relationships['rediscache'])) {
foreach ($relationships['rediscache'] as $endpoint) {
if ($endpoint['scheme'] !== 'redis') {
continue;
}

$loader = new Loader\YamlFileLoader($container, new FileLocator($projectDir . '/config/packages/cache_pool'));
$loader->load('cache.redis.yaml');

$container->setParameter('cache_pool', 'cache.redis');
$container->setParameter('cache_dsn', sprintf('%s:%d', $endpoint['host'], $endpoint['port']) . '?retry_interval=3');
}
} elseif (isset($relationships['cache'])) {
// Fallback to memcached if here (deprecated, we will only handle redis here in the future)
foreach ($relationships['cache'] as $endpoint) {
if ($endpoint['scheme'] !== 'memcached') {
continue;
}

@trigger_error('Usage of Memcached is deprecated, redis is recommended', E_USER_DEPRECATED);

$container->setParameter('cache_pool', 'cache.memcached');
$container->setParameter('cache_dsn', sprintf('%s:%d', $endpoint['host'], $endpoint['port']));

$loader = new Loader\YamlFileLoader($container, new FileLocator($projectDir . '/config/packages/cache_pool'));
$loader->load('cache.memcached.yaml');
}
}

// Use Redis-based sessions if possible. If a separate Redis instance
// is available, use that. If not, share a Redis instance with the
// Cache. (That should be safe to do except on especially high-traffic sites.)
if (isset($relationships['redissession'])) {
foreach ($relationships['redissession'] as $endpoint) {
if ($endpoint['scheme'] !== 'redis') {
continue;
}

$container->setParameter('ibexa.session.handler_id', NativeSessionHandler::class);
$container->setParameter('ibexa.session.save_path', sprintf('%s:%d', $endpoint['host'], $endpoint['port']));
}
} elseif (isset($relationships['rediscache'])) {
foreach ($relationships['rediscache'] as $endpoint) {
if ($endpoint['scheme'] !== 'redis') {
continue;
}

$container->setParameter('ibexa.session.handler_id', NativeSessionHandler::class);
$container->setParameter('ibexa.session.save_path', sprintf('%s:%d', $endpoint['host'], $endpoint['port']));
}
}

if (isset($relationships['solr'])) {
foreach ($relationships['solr'] as $endpoint) {
if ($endpoint['scheme'] !== 'solr') {
continue;
}

$container->setParameter('search_engine', 'solr');

$container->setParameter('solr_dsn', sprintf('http://%s:%d/%s', $endpoint['host'], $endpoint['port'], 'solr'));
// To set solr_core parameter we assume path is in form like: "solr/collection1"
$container->setParameter('solr_core', substr($endpoint['path'], 5));
}
}

if (isset($relationships['elasticsearch'])) {
foreach ($relationships['elasticsearch'] as $endpoint) {
$dsn = sprintf('%s:%d', $endpoint['host'], $endpoint['port']);

if ($endpoint['username'] !== null && $endpoint['password'] !== null) {
$dsn = $endpoint['username'] . ':' . $endpoint['password'] . '@' . $dsn;
}

if ($endpoint['path'] !== null) {
$dsn .= '/' . $endpoint['path'];
}

$dsn = $endpoint['scheme'] . '://' . $dsn;

$container->setParameter('search_engine', 'elasticsearch');
$container->setParameter('elasticsearch_dsn', $dsn);
}
}

// We will pick a varnish route by the following prioritization:
// - The first route found that has upstream: varnish
// - if primary route has upstream: varnish, that route will be prioritised
// If no route is found with upstream: varnish, then purge_server will not be set
$route = null;
foreach ($routes as $host => $info) {
if ($route === null && $info['type'] === 'upstream' && $info['upstream'] === 'varnish') {
$route = $host;
}
if ($info['type'] === 'upstream' && $info['upstream'] === 'varnish' && $info['primary'] === true) {
$route = $host;
break;
}
}

if ($route !== null && null !== ($_SERVER['SKIP_HTTPCACHE_PURGE'] ?? null)) {
$purgeServer = rtrim($route, '/');
if (
null !== ($_SERVER['HTTPCACHE_USERNAME'] ?? null) &&
null !== ($_SERVER['HTTPCACHE_PASSWORD'] ?? null)
) {
$domain = parse_url($purgeServer, PHP_URL_HOST);
$credentials = sprintf(
'%s:%s',
urlencode($_SERVER['HTTPCACHE_USERNAME']),
urlencode($_SERVER['HTTPCACHE_PASSWORD'])
);
$purgeServer = str_replace($domain, $credentials . '@' . $domain, $purgeServer);
}

$container->setParameter('ibexa.http_cache.purge_type', 'varnish');
$container->setParameter('purge_type', 'varnish');
$container->setParameter('purge_server', $purgeServer);
}
// Setting default value for HTTPCACHE_VARNISH_INVALIDATE_TOKEN if it is not explicitly set
if (null === ($_SERVER['HTTPCACHE_VARNISH_INVALIDATE_TOKEN'] ?? null)) {
$container->setParameter('varnish_invalidate_token', $_SERVER['PLATFORM_PROJECT_ENTROPY']);
}

// Adapt config based on enabled PHP extensions
// Get imagine to use imagick if enabled, to avoid using php memory for image conversions
if (\extension_loaded('imagick')) {
$container->setParameter('liip_imagine_driver', 'imagick');
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

/**
* @copyright Copyright (C) Ibexa AS. All rights reserved.
* @license For full copyright and license information view LICENSE file distributed with this source code.
*/
declare(strict_types=1);

namespace Ibexa\Bundle\Core\DependencyInjection\Configuration;

use Symfony\Component\DependencyInjection\ContainerBuilder;

/**
* Configurator to be instantiated during Symfony Extension building (load or prepend phase).
*
* @internal for internal use by Ibexa extensions
*/
interface ContainerConfiguratorInterface
{
public function configure(ContainerBuilder $container): void;
}
Loading