') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); })(); GitHub - gamfi/dynamic-parameter-bundle: This bundle enables having multiple configurations in one Symfony application. · GitHub
Skip to content

Repository files navigation

OJezu/DynamicParameterBundle

This bundle enables having multiple configurations (installations) in one Symfony application. It does so, by supplying two independent features:

  • Installation-aware kernel, and installation-dependent parameters
  • Advanced parameter provider, that can read parameters from any source.

Combination of this features enable implementing multi-tenant applications, configured to use different resources separated at infrastructure level for each tenant. The resources can be database connection, filesystem adapters, etc. Moreover, configuration storage can be off-loaded to a database server, JSON file, zookeeper instance, with a custom or build-in parameter provider service, which will load appropriate configuration based on installation selected in application kernel.

Requirements

This bundle requires Symfony 3.4, as it depends on advanced environment variable processing.

Usage

Note: Processors from this bundle do not read actual environment variables.

Multi-installation

Provide kernel with information about installation (see configuration below), and then in your configuration you can use that information as parameters.

#app/config/config.ymlojezu_dynamic_parameter:
multi_installation: truefile_storage:
bucket: "/myapp/installation/%env(ojezu_installation:name)%/"

Usage is similar to plain environment variables, but gives more control, as it's developer who decides what and from where will find its way into Installation object. Installation parameters can be set based on request headers, php-cli arguments and any other data source, as implemented in application using this bundle (see configuration below).

All Installation class instance public properties can be accessed, and Installation class can be extended, with properties you need.

Advanced parameter provider

After configuring advanced parameter provider (see below), you are able to map parameters to abstract configuration paths used to obtain parameter values from any source, as long as there is a provider for that source. Providers are very simple services, that just have to implement ParameterProviderInterface. JSON local and remote file provider is already provided by this bundle, more powerful than Symfony built-in "json:" env variable processor.

# app/config/config.ymlojezu_dynamic_parameter:
advanced_parameters:
provider: 'OJezu\DynamicParameterBundle\Service\LocalJsonFileParameterProvider'parameter_map:
database_host: { path: ['database', 'host'] }doctrine:
dbal:
driver: pdo_mysqlserver_version: 5.7host: "%env(ojezu_param:database_host)%"
# services.ymlservices:
OJezu\DynamicParameterBundle\Service\LocalJsonFileParameterProvider:
arguments:
- '%kernel.root_dir%/config/config.json'

This configuration will find database.host value in JSON config file, and provide it to DBAL configuration.

Using them together

While both features offer more than what's built in Symfony 3.4, using them together allows for easy management of multiple configurations supported by same Symfony application.

#app/config/config.ymlojezu_dynamic_parameter:
multi_installation: trueadvanced_parameters:
provider: 'OJezu\DynamicParameterBundle\Service\LocalJsonFileParameterProvider'parameter_map:
database_name: { path: ['installation', '%env(ojezu_installation:name)%', 'database', 'name'] }doctrine:
dbal:
driver: pdo_mysqlserver_version: 5.7host: "mysql.example.com"dbname: "%env(ojezu_param:database_name)%"
#services.ymlservices:
OJezu\DynamicParameterBundle\Service\LocalJsonFileParameterProvider:
arguments:
- '%kernel.root_dir%/config/config.json'
{
"installation": {
"application1": {
"database": {
"name": "app1_database",
}
},
"application2": {
"database": {
"name": "app2_database",
}
}
}
}

Configuration

Multi-installation

In order to be able to use multi-installation support:

  1. Enable it in configuration:

    #app/config/config.ymlojezu_dynamic_parameter:
    multi_installation: true
  2. Change your AppKernel to extend \OJezu\DynamicParameterBundle\Kernel\Kernel

    <?phpuse \OJezu\DynamicParameterBundle\Kernel\Kernel;
    class AppKernel extends Kernel
    {
    (...)
    }
  3. Make sure that in all places where kernel is created in your application, it is provided with Installation instance. Kernel is usually created by web/*.php or public/*.php files, but remember to modify your bin/console too.

    <?php
    (...)
    $installation = newInstallation($requestedInstallation);
    $kernel = newAppKernel($installation, $env, $debug);

    Complete examples can be found in doc/examples directory of this repository.

  4. In bin/console be sure to also swap Application with one provided by this bundle, if you want to specify installation via CLI option - otherwise parsing of argv may introduce problems.

Complete examples can be found in doc/examples directory

Advanced parameter provider

You must provide mapping for supported parameters. It is required due to limitations in %env(processor:variable)% Symfony DI Container configuration syntax, and to allow paths that can be easily adapted to any configuration provider.

ojezu_dynamic_parameter:
advanced_parameters:
provider: 'OJezu\DynamicParameterBundle\Service\LocalJsonFileParameterProvider'parameter_map:
database_host: { path: ['database', 'host'] }database_name: { path: ['database', 'name'] }database_user: { path: ['database', 'user'] }

Those parameters can later be used in all places in your application configuration, no matter support from configured bundle:

doctrine:
dbal:
driver: pdo_mysqlserver_version: 5.7host: "%env(ojezu_param:database_host)%"dbname: "%env(ojezu_param:database_name)%"user: "%env(ojezu_param:database_user)%"
Using other parameters

In paths all previously loaded parameters can be used, including ojezu_installation parameters.

ojezu_dynamic_parameter:
multi_installation: trueadvanced_parameters:
provider: 'OJezu\DynamicParameterBundle\Service\LocalJsonFileParameterProvider'parameter_map:
database_host: { path: ['installation', '%env(ojezu_installation:name)%', 'database', 'host'] }database_name: { path: ['installation', '%env(ojezu_installation:name)%', 'database', 'name'] }database_user: { path: ['installation', '%env(ojezu_installation:name)%', 'database', 'user'] }

Parameter providers

Built-in parameter providers

LocalJsonFileParameterProvider

Opens and parses json file from local disk.

# services.ymlservices:
OJezu\DynamicParameterBundle\Service\LocalJsonFileParameterProvider:
arguments:
- '%kernel.root_dir%/etc/installation/%env(ojezu_installation:name)%.json'
# app/config/config.ymlojezu_dynamic_parameter:
multi_installation: trueadvanced_parameters:
provider: 'OJezu\DynamicParameterBundle\Service\LocalJsonFileParameterProvider'

RemoteJsonFileParameterProvider

Downloads json file with GuzzleHttp client and optionally caches it in a PSR-16 Simple Cache compatible cache.

# services.ymlservices:
app.guzzle.configuration:
class: GuzzleHttp\Clientarguments:
- timeout: 5auth: ['configuration', 'configuration']app.cache.configuration:
class: Symfony\Component\Cache\Simple\ApcuCachearguments:
- 'installation_configuration'OJezu\DynamicParameterBundle\Service\RemoteJsonFileParameterProvider:
arguments:
- 'http://configuration_server/%env(ojezu_installation:name)%.json'
- '@app.guzzle.configuration'
- '@app.cache.configuration'
# app/config/config.ymlojezu_dynamic_parameter:
multi_installation: trueadvanced_parameters:
provider: 'OJezu\DynamicParameterBundle\Service\RemoteJsonFileParameterProvider'

Custom parameter providers

You can use any service implementing OJezu\DynamicParameterBundle\Service\ParameterProviderInterface interface.

ojezu_dynamic_parameter:
multi_installation: trueadvanced_parameters:
provider: 'MyAppBundle\Services\RedisParameterProvider'# this is service! not class.parameter_map:
database_host: { path: ['installation', '%env(ojezu_installation:name)%', 'database', 'host'] }database_name: { path: ['installation', '%env(ojezu_installation:name)%', 'database', 'name'] }database_user: { path: ['installation', '%env(ojezu_installation:name)%', 'database', 'user'] }

Keep in mind that your provider is a service - it can have its arguments injected, it can be tagged etc. As long as there is no cycle it will work like any other service (no use trying to inject ojezu_params there!)

Defaults?

Yes.

ojezu_dynamic_parameter:
advanced_parameters:
provider: 'OJezu\DynamicParameterBundle\Service\LocalJsonFileParameterProvider'processor:
database_host:
path: ['database', 'host']default: 'localhost'
No config mode

In some instances there is no configuration to be loaded - e.g. when warming cache. For those instances there is "no config mode", in which provider won't be used, and all variables will be resolved to null, unless given explicit value for use in those scenarios. Defaults won't be used.

Enable it by using load_configuration option in processor section:

ojezu_dynamic_parameter:
multi_installation: trueadvanced_parameters:
provider: 'OJezu\DynamicParameterBundle\Service\LocalJsonFileParameterProvider'load_configuration: '%env(bool:ojezu_installation:name)%'parameter_map:
database_host: {path: ['installation', '%env(ojezu_installation:name)%', 'database', 'host']}log_channel: {path: ['log', '%env(ojezu_installation:name)%'], default: 'default', no_config_value: 'default'}bucket_name: {path: ['buckets', '%env(ojezu_installation:name)%'], no_config_value: '%env(LOCAL_BUCKET)%'}

Extending this bundle in your application

Points for expansion are

  • Installation value object for ojezu_installation
  • Parameter providers

If you need more options from Installation, extend that class with additional public properties or methods, and use your extended class in place of the base Installation.

New providers can be written by extending OJezu\DynamicParameterBundle\Service\ParameterProviderInterface and configured as described in Configuration part of this ReadMe

Testing

would be nice.

License

MIT

About

This bundle enables having multiple configurations in one Symfony application.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages