API Apply default logger to all caches

API Rename ‘Logger’ service name to ‘Psr\Log\LoggerInterface’
API DefaultCacheFactory constructor now takes an array of default arguments
This commit is contained in:
Damian Mooyman 2017-03-10 11:20:58 +13:00
parent 8f0f9fa119
commit ce14060913
8 changed files with 102 additions and 48 deletions

View File

@ -5,7 +5,10 @@ SilverStripe\Core\Injector\Injector:
SilverStripe\Core\Cache\CacheFactory: SilverStripe\Core\Cache\CacheFactory:
class: 'SilverStripe\Core\Cache\DefaultCacheFactory' class: 'SilverStripe\Core\Cache\DefaultCacheFactory'
constructor: constructor:
directory: '`TEMP_FOLDER`' args:
directory: '`TEMP_FOLDER`'
version: null
logger: %$Psr\Log\LoggerInterface
Psr\SimpleCache\CacheInterface.GDBackend_Manipulations: Psr\SimpleCache\CacheInterface.GDBackend_Manipulations:
factory: SilverStripe\Core\Cache\CacheFactory factory: SilverStripe\Core\Cache\CacheFactory
constructor: constructor:

View File

@ -5,8 +5,8 @@ SilverStripe\Core\Injector\Injector:
ErrorHandler: ErrorHandler:
class: SilverStripe\Logging\MonologErrorHandler class: SilverStripe\Logging\MonologErrorHandler
properties: properties:
Logger: %$Logger Logger: %$Psr\Log\LoggerInterface
Logger: Psr\Log\LoggerInterface:
type: singleton type: singleton
class: Monolog\Logger class: Monolog\Logger
constructor: constructor:

View File

@ -14,8 +14,8 @@ For informational and debug logs, you can use the Logger directly. The Logger is
can be accessed via the `Injector`: can be accessed via the `Injector`:
:::php :::php
Injector::inst()->get('Logger')->info('User has logged in: ID #' . Member::currentUserID()); Injector::inst()->get(LoggerInterface::class)->info('User has logged in: ID #' . Member::currentUserID());
Injector::inst()->get('Logger')->debug('Query executed: ' . $sql); Injector::inst()->get(LoggerInterface::class)->debug('Query executed: ' . $sql);
Although you can raise more important levels of alerts in this way, we recommend using PHP's native error systems for Although you can raise more important levels of alerts in this way, we recommend using PHP's native error systems for
these instead. these instead.
@ -48,16 +48,16 @@ but they can be caught with a try/catch clause.
### Accessing the logger via dependency injection. ### Accessing the logger via dependency injection.
It can quite verbose to call `Injector::inst()->get('Logger')` all the time. More importantly, it also means that you're It can quite verbose to call `Injector::inst()->get(LoggerInterface::class)` all the time. More importantly,
coupling your code to global state, which is a bad design practise. A better approach is to use depedency injection to it also means that you're coupling your code to global state, which is a bad design practise. A better
pass the logger in for you. The [Injector](../extending/Injector) can help with this. The most straightforward is to approach is to use depedency injection to pass the logger in for you. The [Injector](../extending/Injector)
specify a `dependencies` config setting, like this: can help with this. The most straightforward is to specify a `dependencies` config setting, like this:
:::php :::php
class MyController { class MyController {
private static $dependencies = array( private static $dependencies = array(
'logger' => '%$Logger', 'logger' => '%$Psr\Log\LoggerInterface',
); );
// This will be set automatically, as long as MyController is instantiated via Injector // This will be set automatically, as long as MyController is instantiated via Injector

View File

@ -12,8 +12,8 @@ interface CacheFactory extends InjectorFactory
* Note: While the returned object is used as a singleton (by the originating Injector->get() call), * Note: While the returned object is used as a singleton (by the originating Injector->get() call),
* this cache object shouldn't be a singleton itself - it has varying constructor args for the same service name. * this cache object shouldn't be a singleton itself - it has varying constructor args for the same service name.
* *
* @param string $class * @param string $service
* @param array $args * @param array $params
* @return CacheInterface * @return CacheInterface
*/ */
public function create($service, array $params = array()); public function create($service, array $params = array());

View File

@ -2,6 +2,9 @@
namespace SilverStripe\Core\Cache; namespace SilverStripe\Core\Cache;
use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerInterface;
use Psr\SimpleCache\CacheInterface;
use SilverStripe\Core\Injector\Injector; use SilverStripe\Core\Injector\Injector;
use Symfony\Component\Cache\Simple\FilesystemCache; use Symfony\Component\Cache\Simple\FilesystemCache;
use Symfony\Component\Cache\Simple\ApcuCache; use Symfony\Component\Cache\Simple\ApcuCache;
@ -20,25 +23,24 @@ use Symfony\Component\Cache\Adapter\PhpFilesAdapter;
*/ */
class DefaultCacheFactory implements CacheFactory class DefaultCacheFactory implements CacheFactory
{ {
/** /**
* @var string Absolute directory path * @var string Absolute directory path
*/ */
protected $directory; protected $args = [];
/** /**
* @var string APC version for apcu_add() * @var LoggerInterface
*/ */
protected $version; protected $logger;
/** /**
* @param string $directory * @param array $args List of global options to merge with args during create()
* @param string $version * @param LoggerInterface $logger Logger instance to assign
*/ */
public function __construct($directory, $version = null) public function __construct($args = [], LoggerInterface $logger = null)
{ {
$this->directory = $directory; $this->args = $args;
$this->version = $version; $this->logger = $logger;
} }
/** /**
@ -46,33 +48,76 @@ class DefaultCacheFactory implements CacheFactory
*/ */
public function create($service, array $args = array()) public function create($service, array $args = array())
{ {
$namespace = (isset($args['namespace'])) ? $args['namespace'] : ''; // merge args with default
$defaultLifetime = (isset($args['defaultLifetime'])) ? $args['defaultLifetime'] : 0; $args = array_merge($this->args, $args);
$version = $this->version; $namespace = isset($args['namespace']) ? $args['namespace'] : '';
$directory = $this->directory; $defaultLifetime = isset($args['defaultLifetime']) ? $args['defaultLifetime'] : 0;
$directory = isset($args['directory']) ? $args['directory'] : null;
$version = isset($args['version']) ? $args['version'] : null;
$apcuSupported = null; // Check support
$phpFilesSupported = null; $apcuSupported = $this->isAPCUSupported();
$phpFilesSupported = $this->isPHPFilesSupported();
if (null === $apcuSupported) { // If apcu isn't supported, phpfiles is the next best preference
$apcuSupported = ApcuAdapter::isSupported(); if (!$apcuSupported && $phpFilesSupported) {
return $this->createCache(PhpFilesCache::class, [$namespace, $defaultLifetime, $directory]);
} }
if (!$apcuSupported && null === $phpFilesSupported) { // Create filessytem cache
$phpFilesSupported = PhpFilesAdapter::isSupported(); $fs = $this->createCache(FilesystemCache::class, [$namespace, $defaultLifetime, $directory]);
}
if ($phpFilesSupported) {
$opcache = Injector::inst()->create(PhpFilesCache::class, $namespace, $defaultLifetime, $directory);
return $opcache;
}
$fs = Injector::inst()->create(FilesystemCache::class, $namespace, $defaultLifetime, $directory);
if (!$apcuSupported) { if (!$apcuSupported) {
return $fs; return $fs;
} }
$apcu = Injector::inst()->create(ApcuCache::class, $namespace, (int) $defaultLifetime / 5, $version);
return Injector::inst()->create(ChainCache::class, [$apcu, $fs]); // Chain this cache with ApcuCache
$apcu = $this->createCache(ApcuCache::class, [$namespace, (int) $defaultLifetime / 5, $version]);
return $this->createCache(ChainCache::class, [[$apcu, $fs]]);
}
/**
* Determine if apcu is supported
*
* @return bool
*/
protected function isAPCUSupported()
{
static $apcuSupported = null;
if (null === $apcuSupported) {
$apcuSupported = ApcuAdapter::isSupported();
}
return $apcuSupported;
}
/**
* Determine if PHP files is supported
*
* @return bool
*/
protected function isPHPFilesSupported()
{
static $phpFilesSupported = null;
if (null === $phpFilesSupported) {
$phpFilesSupported = PhpFilesAdapter::isSupported();
}
return $phpFilesSupported;
}
/**
* @param string $class
* @param array $args
* @return CacheInterface
*/
protected function createCache($class, $args)
{
/** @var CacheInterface $cache */
$cache = Injector::inst()->createWithArgs($class, $args);
// Assign cache logger
if ($this->logger && $cache instanceof LoggerAwareInterface) {
$cache->setLogger($this->logger);
}
return $cache;
} }
} }

View File

@ -36,8 +36,8 @@ class Log
*/ */
public static function get_logger() public static function get_logger()
{ {
Deprecation::notice('5.0', 'Use Injector::inst()->get(\'Logger\') instead'); Deprecation::notice('5.0', 'Use Injector::inst()->get(LoggerInterface::class) instead');
return Injector::inst()->get('Logger'); return Injector::inst()->get(LoggerInterface::class);
} }
/** /**
@ -55,7 +55,7 @@ class Log
*/ */
public static function log($message, $priority) public static function log($message, $priority)
{ {
Deprecation::notice('5.0', 'Use Injector::inst()->get(\'Logger\')->log($priority, $message) instead'); Deprecation::notice('5.0', 'Use Injector::inst()->get(LoggerInterface::class)->log($priority, $message) instead');
Injector::inst()->get('Logger')->log($priority, $message); Injector::inst()->get(LoggerInterface::class)->log($priority, $message);
} }
} }

View File

@ -10,17 +10,22 @@ use Monolog\ErrorHandler;
*/ */
class MonologErrorHandler class MonologErrorHandler
{ {
/**
* @var LoggerInterface
*/
private $logger; private $logger;
/** /**
* Set the PSR-3 logger to send errors & exceptions to * Set the PSR-3 logger to send errors & exceptions to
*
* @param LoggerInterface $logger
*/ */
function setLogger(LoggerInterface $logger) public function setLogger(LoggerInterface $logger)
{ {
$this->logger = $logger; $this->logger = $logger;
} }
function start() public function start()
{ {
if (!$this->logger) { if (!$this->logger) {
throw new \InvalidArgumentException("No Logger property passed to MonologErrorHandler." throw new \InvalidArgumentException("No Logger property passed to MonologErrorHandler."

View File

@ -48,6 +48,7 @@
use Monolog\Logger; use Monolog\Logger;
use Monolog\Handler\StreamHandler; use Monolog\Handler\StreamHandler;
use Psr\Log\LoggerInterface;
use SilverStripe\Control\Email\Email; use SilverStripe\Control\Email\Email;
use SilverStripe\Core\Injector\Injector; use SilverStripe\Core\Injector\Injector;
use SilverStripe\Dev\Install\DatabaseAdapterRegistry; use SilverStripe\Dev\Install\DatabaseAdapterRegistry;
@ -138,7 +139,7 @@ if ($useBasicAuth = getenv('SS_USE_BASIC_AUTH')) {
} }
if ($errorLog = getenv('SS_ERROR_LOG')) { if ($errorLog = getenv('SS_ERROR_LOG')) {
$logger = Injector::inst()->get('Logger'); $logger = Injector::inst()->get(LoggerInterface::class);
if ($logger instanceof Logger) { if ($logger instanceof Logger) {
$logger->pushHandler(new StreamHandler(BASE_PATH . '/' . $errorLog, Logger::WARNING)); $logger->pushHandler(new StreamHandler(BASE_PATH . '/' . $errorLog, Logger::WARNING));
} else { } else {