123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399 |
- <?php
- /**
- * Copyright © Magento, Inc. All rights reserved.
- * See COPYING.txt for license details.
- */
- /**
- * Factory that creates cache frontend instances based on options
- */
- namespace Magento\Framework\App\Cache\Frontend;
- use Magento\Framework\App\Filesystem\DirectoryList;
- use Magento\Framework\Filesystem;
- /**
- * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
- */
- class Factory
- {
- /**
- * Default cache entry lifetime
- */
- const DEFAULT_LIFETIME = 7200;
- /**
- * Caching params, that applied for all cache frontends regardless of type
- */
- const PARAM_CACHE_FORCED_OPTIONS = 'cache_options';
- /**
- * @var \Magento\Framework\ObjectManagerInterface
- */
- private $_objectManager;
- /**
- * @var Filesystem
- */
- private $_filesystem;
- /**
- * Cache options to be enforced for all instances being created
- *
- * @var array
- */
- private $_enforcedOptions = [];
- /**
- * Configuration of decorators that are to be applied to every cache frontend being instantiated, format:
- * array(
- * array('class' => '<decorator_class>', 'arguments' => array()),
- * ...
- * )
- *
- * @var array
- */
- private $_decorators = [];
- /**
- * Default cache backend type
- *
- * @var string
- */
- protected $_defaultBackend = 'Cm_Cache_Backend_File';
- /**
- * Options for default backend
- *
- * @var array
- */
- protected $_backendOptions = [
- 'hashed_directory_level' => 1,
- 'file_name_prefix' => 'mage',
- ];
- /**
- * Resource
- *
- * @var \Magento\Framework\App\ResourceConnection
- */
- protected $_resource;
- /**
- * @param \Magento\Framework\ObjectManagerInterface $objectManager
- * @param Filesystem $filesystem
- * @param \Magento\Framework\App\ResourceConnection $resource
- * @param array $enforcedOptions
- * @param array $decorators
- */
- public function __construct(
- \Magento\Framework\ObjectManagerInterface $objectManager,
- Filesystem $filesystem,
- \Magento\Framework\App\ResourceConnection $resource,
- array $enforcedOptions = [],
- array $decorators = []
- ) {
- $this->_objectManager = $objectManager;
- $this->_filesystem = $filesystem;
- $this->_resource = $resource;
- $this->_enforcedOptions = $enforcedOptions;
- $this->_decorators = $decorators;
- }
- /**
- * Return newly created cache frontend instance
- *
- * @param array $options
- * @return \Magento\Framework\Cache\FrontendInterface
- */
- public function create(array $options)
- {
- $options = $this->_getExpandedOptions($options);
- foreach (['backend_options', 'slow_backend_options'] as $section) {
- if (!empty($options[$section]['cache_dir'])) {
- $directory = $this->_filesystem->getDirectoryWrite(DirectoryList::VAR_DIR);
- $directory->create($options[$section]['cache_dir']);
- $options[$section]['cache_dir'] = $directory->getAbsolutePath($options[$section]['cache_dir']);
- }
- }
- $idPrefix = isset($options['id_prefix']) ? $options['id_prefix'] : '';
- if (!$idPrefix && isset($options['prefix'])) {
- $idPrefix = $options['prefix'];
- }
- if (empty($idPrefix)) {
- $configDirPath = $this->_filesystem->getDirectoryRead(DirectoryList::CONFIG)->getAbsolutePath();
- $idPrefix =
- substr(md5($configDirPath), 0, 3) . '_';
- }
- $options['frontend_options']['cache_id_prefix'] = $idPrefix;
- $backend = $this->_getBackendOptions($options);
- $frontend = $this->_getFrontendOptions($options);
- // Start profiling
- $profilerTags = [
- 'group' => 'cache',
- 'operation' => 'cache:create',
- 'frontend_type' => $frontend['type'],
- 'backend_type' => $backend['type'],
- ];
- \Magento\Framework\Profiler::start('cache_frontend_create', $profilerTags);
- /** @var $result \Magento\Framework\Cache\Frontend\Adapter\Zend */
- $result = $this->_objectManager->create(
- \Magento\Framework\Cache\Frontend\Adapter\Zend::class,
- [
- 'frontendFactory' => function () use ($frontend, $backend) {
- return \Zend_Cache::factory(
- $frontend['type'],
- $backend['type'],
- $frontend,
- $backend['options'],
- true,
- true,
- true
- );
- }
- ]
- );
- $result = $this->_applyDecorators($result);
- // stop profiling
- \Magento\Framework\Profiler::stop('cache_frontend_create');
- return $result;
- }
- /**
- * Return options expanded with enforced values
- *
- * @param array $options
- * @return array
- */
- private function _getExpandedOptions(array $options)
- {
- return array_replace_recursive($options, $this->_enforcedOptions);
- }
- /**
- * Apply decorators to a cache frontend instance and return the topmost one
- *
- * @param \Magento\Framework\Cache\FrontendInterface $frontend
- * @return \Magento\Framework\Cache\FrontendInterface
- * @throws \LogicException
- * @throws \UnexpectedValueException
- */
- private function _applyDecorators(\Magento\Framework\Cache\FrontendInterface $frontend)
- {
- foreach ($this->_decorators as $decoratorConfig) {
- if (!isset($decoratorConfig['class'])) {
- throw new \LogicException('Class has to be specified for a cache frontend decorator.');
- }
- $decoratorClass = $decoratorConfig['class'];
- $decoratorParams = isset($decoratorConfig['parameters']) ? $decoratorConfig['parameters'] : [];
- $decoratorParams['frontend'] = $frontend;
- // conventionally, 'frontend' argument is a decoration subject
- $frontend = $this->_objectManager->create($decoratorClass, $decoratorParams);
- if (!$frontend instanceof \Magento\Framework\Cache\FrontendInterface) {
- throw new \UnexpectedValueException('Decorator has to implement the cache frontend interface.');
- }
- }
- return $frontend;
- }
- /**
- * Get cache backend options. Result array contain backend type ('type' key) and backend options ('options')
- *
- * @param array $cacheOptions
- * @return array
- * @SuppressWarnings(PHPMD.CyclomaticComplexity)
- * @SuppressWarnings(PHPMD.NPathComplexity)
- */
- protected function _getBackendOptions(array $cacheOptions)
- {
- $enableTwoLevels = false;
- $type = isset($cacheOptions['backend']) ? $cacheOptions['backend'] : $this->_defaultBackend;
- if (isset($cacheOptions['backend_options']) && is_array($cacheOptions['backend_options'])) {
- $options = $cacheOptions['backend_options'];
- } else {
- $options = [];
- }
- $backendType = false;
- switch (strtolower($type)) {
- case 'sqlite':
- if (extension_loaded('sqlite') && isset($options['cache_db_complete_path'])) {
- $backendType = 'Sqlite';
- }
- break;
- case 'memcached':
- if (extension_loaded('memcached')) {
- if (isset($cacheOptions['memcached'])) {
- $options = $cacheOptions['memcached'];
- }
- $enableTwoLevels = true;
- $backendType = 'Libmemcached';
- } elseif (extension_loaded('memcache')) {
- if (isset($cacheOptions['memcached'])) {
- $options = $cacheOptions['memcached'];
- }
- $enableTwoLevels = true;
- $backendType = 'Memcached';
- }
- break;
- case 'apc':
- if (extension_loaded('apc') && ini_get('apc.enabled')) {
- $enableTwoLevels = true;
- $backendType = 'Apc';
- }
- break;
- case 'xcache':
- if (extension_loaded('xcache')) {
- $enableTwoLevels = true;
- $backendType = 'Xcache';
- }
- break;
- case 'eaccelerator':
- case 'varien_cache_backend_eaccelerator':
- if (extension_loaded('eaccelerator') && ini_get('eaccelerator.enable')) {
- $enableTwoLevels = true;
- $backendType = \Magento\Framework\Cache\Backend\Eaccelerator::class;
- }
- break;
- case 'database':
- $backendType = \Magento\Framework\Cache\Backend\Database::class;
- $options = $this->_getDbAdapterOptions();
- break;
- case 'remote_synchronized_cache':
- $backendType = \Magento\Framework\Cache\Backend\RemoteSynchronizedCache::class;
- $options['remote_backend'] = \Magento\Framework\Cache\Backend\Database::class;
- $options['remote_backend_options'] = $this->_getDbAdapterOptions();
- $options['local_backend'] = \Cm_Cache_Backend_File::class;
- $cacheDir = $this->_filesystem->getDirectoryWrite(DirectoryList::CACHE);
- $options['local_backend_options']['cache_dir'] = $cacheDir->getAbsolutePath();
- $cacheDir->create();
- break;
- default:
- if ($type != $this->_defaultBackend) {
- try {
- if (class_exists($type, true)) {
- $implements = class_implements($type, true);
- if (in_array('Zend_Cache_Backend_Interface', $implements)) {
- $backendType = $type;
- }
- }
- } catch (\Exception $e) {
- }
- }
- }
- if (!$backendType) {
- $backendType = $this->_defaultBackend;
- $cacheDir = $this->_filesystem->getDirectoryWrite(DirectoryList::CACHE);
- $this->_backendOptions['cache_dir'] = $cacheDir->getAbsolutePath();
- $cacheDir->create();
- }
- foreach ($this->_backendOptions as $option => $value) {
- if (!array_key_exists($option, $options)) {
- $options[$option] = $value;
- }
- }
- $backendOptions = ['type' => $backendType, 'options' => $options];
- if ($enableTwoLevels) {
- $backendOptions = $this->_getTwoLevelsBackendOptions($backendOptions, $cacheOptions);
- }
- return $backendOptions;
- }
- /**
- * Get options for database backend type
- *
- * @return array
- */
- protected function _getDbAdapterOptions()
- {
- $options['adapter_callback'] = function () {
- return $this->_resource->getConnection();
- };
- $options['data_table_callback'] = function () {
- return $this->_resource->getTableName('cache');
- };
- $options['tags_table_callback'] = function () {
- return $this->_resource->getTableName('cache_tag');
- };
- return $options;
- }
- /**
- * Initialize two levels backend model options
- *
- * @param array $fastOptions fast level backend type and options
- * @param array $cacheOptions all cache options
- * @return array
- */
- protected function _getTwoLevelsBackendOptions($fastOptions, $cacheOptions)
- {
- $options = [];
- $options['fast_backend'] = $fastOptions['type'];
- $options['fast_backend_options'] = $fastOptions['options'];
- $options['fast_backend_custom_naming'] = true;
- $options['fast_backend_autoload'] = true;
- $options['slow_backend_custom_naming'] = true;
- $options['slow_backend_autoload'] = true;
- if (isset($cacheOptions['auto_refresh_fast_cache'])) {
- $options['auto_refresh_fast_cache'] = (bool)$cacheOptions['auto_refresh_fast_cache'];
- } else {
- $options['auto_refresh_fast_cache'] = false;
- }
- if (isset($cacheOptions['slow_backend'])) {
- $options['slow_backend'] = $cacheOptions['slow_backend'];
- } else {
- $options['slow_backend'] = $this->_defaultBackend;
- }
- if (isset($cacheOptions['slow_backend_options'])) {
- $options['slow_backend_options'] = $cacheOptions['slow_backend_options'];
- } else {
- $options['slow_backend_options'] = $this->_backendOptions;
- }
- if ($options['slow_backend'] == 'database') {
- $options['slow_backend'] = \Magento\Framework\Cache\Backend\Database::class;
- $options['slow_backend_options'] = $this->_getDbAdapterOptions();
- if (isset($cacheOptions['slow_backend_store_data'])) {
- $options['slow_backend_options']['store_data'] = (bool)$cacheOptions['slow_backend_store_data'];
- } else {
- $options['slow_backend_options']['store_data'] = false;
- }
- }
- $backend = ['type' => 'TwoLevels', 'options' => $options];
- return $backend;
- }
- /**
- * Get options of cache frontend (options of \Zend_Cache_Core)
- *
- * @param array $cacheOptions
- * @return array
- * @SuppressWarnings(PHPMD.NPathComplexity)
- */
- protected function _getFrontendOptions(array $cacheOptions)
- {
- $options = isset($cacheOptions['frontend_options']) ? $cacheOptions['frontend_options'] : [];
- if (!array_key_exists('caching', $options)) {
- $options['caching'] = true;
- }
- if (!array_key_exists('lifetime', $options)) {
- $options['lifetime'] = isset(
- $cacheOptions['lifetime']
- ) ? $cacheOptions['lifetime'] : self::DEFAULT_LIFETIME;
- }
- if (!array_key_exists('automatic_cleaning_factor', $options)) {
- $options['automatic_cleaning_factor'] = 0;
- }
- $options['type'] =
- isset($cacheOptions['frontend']) ? $cacheOptions['frontend'] : \Magento\Framework\Cache\Core::class;
- return $options;
- }
- }
|