1<?php 2 3/** 4 * @see https://github.com/laminas/laminas-log for the canonical source repository 5 * @copyright https://github.com/laminas/laminas-log/blob/master/COPYRIGHT.md 6 * @license https://github.com/laminas/laminas-log/blob/master/LICENSE.md New BSD License 7 */ 8namespace Laminas\Log\Writer; 9 10use Laminas\Log\Exception; 11use Laminas\Log\Filter\FilterInterface; 12use Laminas\Log\Filter\Priority as PriorityFilter; 13use Laminas\Log\Formatter\FormatterInterface; 14use Laminas\Log\Logger; 15use Laminas\Log\WriterPluginManager; 16use Laminas\ServiceManager\ServiceManager; 17use Laminas\Stdlib\ArrayUtils; 18use Traversable; 19 20/** 21 * Buffers all events until the strategy determines to flush them. 22 * 23 * @see http://packages.python.org/Logbook/api/handlers.html#logbook.FingersCrossedHandler 24 */ 25class FingersCrossed extends AbstractWriter 26{ 27 /** 28 * The wrapped writer 29 * 30 * @var WriterInterface 31 */ 32 protected $writer; 33 34 /** 35 * Writer plugins 36 * 37 * @var WriterPluginManager 38 */ 39 protected $writerPlugins; 40 41 /** 42 * Flag if buffering is enabled 43 * 44 * @var bool 45 */ 46 protected $buffering = true; 47 48 /** 49 * Oldest entries are removed from the buffer if bufferSize is reached. 50 * 0 is infinte buffer size. 51 * 52 * @var int 53 */ 54 protected $bufferSize; 55 56 /** 57 * array of log events 58 * 59 * @var array 60 */ 61 protected $buffer = []; 62 63 /** 64 * Constructor 65 * 66 * @param WriterInterface|string|array|Traversable $writer Wrapped writer or array of configuration options 67 * @param FilterInterface|int $filterOrPriority Filter or log priority which determines buffering of events 68 * @param int $bufferSize Maximum buffer size 69 */ 70 public function __construct($writer, $filterOrPriority = null, $bufferSize = 0) 71 { 72 $this->writer = $writer; 73 74 if ($writer instanceof Traversable) { 75 $writer = ArrayUtils::iteratorToArray($writer); 76 } 77 78 if (is_array($writer)) { 79 $filterOrPriority = isset($writer['priority']) ? $writer['priority'] : null; 80 $bufferSize = isset($writer['bufferSize']) ? $writer['bufferSize'] : null; 81 $writer = isset($writer['writer']) ? $writer['writer'] : null; 82 } 83 84 if (null === $filterOrPriority) { 85 $filterOrPriority = new PriorityFilter(Logger::WARN); 86 } elseif (! $filterOrPriority instanceof FilterInterface) { 87 $filterOrPriority = new PriorityFilter($filterOrPriority); 88 } 89 90 if (is_array($writer) && isset($writer['name'])) { 91 $this->setWriter($writer['name'], $writer['options']); 92 } else { 93 $this->setWriter($writer); 94 } 95 $this->addFilter($filterOrPriority); 96 $this->bufferSize = $bufferSize; 97 } 98 99 /** 100 * Set a new writer 101 * 102 * @param string|WriterInterface $writer 103 * @param array|null $options 104 * @return self 105 * @throws Exception\InvalidArgumentException 106 */ 107 public function setWriter($writer, array $options = null) 108 { 109 if (is_string($writer)) { 110 $writer = $this->writerPlugin($writer, $options); 111 } 112 113 if (! $writer instanceof WriterInterface) { 114 throw new Exception\InvalidArgumentException(sprintf( 115 'Writer must implement %s\WriterInterface; received "%s"', 116 __NAMESPACE__, 117 is_object($writer) ? get_class($writer) : gettype($writer) 118 )); 119 } 120 121 $this->writer = $writer; 122 return $this; 123 } 124 125 /** 126 * Get writer plugin manager 127 * 128 * @return WriterPluginManager 129 */ 130 public function getWriterPluginManager() 131 { 132 if (null === $this->writerPlugins) { 133 $this->setWriterPluginManager(new WriterPluginManager(new ServiceManager())); 134 } 135 return $this->writerPlugins; 136 } 137 138 /** 139 * Set writer plugin manager 140 * 141 * @param string|WriterPluginManager $plugins 142 * @return FingersCrossed 143 * @throws Exception\InvalidArgumentException 144 */ 145 public function setWriterPluginManager($plugins) 146 { 147 if (is_string($plugins)) { 148 $plugins = new $plugins; 149 } 150 if (! $plugins instanceof WriterPluginManager) { 151 throw new Exception\InvalidArgumentException(sprintf( 152 'Writer plugin manager must extend %s\WriterPluginManager; received %s', 153 __NAMESPACE__, 154 is_object($plugins) ? get_class($plugins) : gettype($plugins) 155 )); 156 } 157 158 $this->writerPlugins = $plugins; 159 return $this; 160 } 161 162 /** 163 * Get writer instance 164 * 165 * @param string $name 166 * @param array|null $options 167 * @return WriterInterface 168 */ 169 public function writerPlugin($name, array $options = null) 170 { 171 return $this->getWriterPluginManager()->get($name, $options); 172 } 173 174 /** 175 * Log a message to this writer. 176 * 177 * @param array $event log data event 178 * @return void 179 */ 180 public function write(array $event) 181 { 182 $this->doWrite($event); 183 } 184 185 /** 186 * Check if buffered data should be flushed 187 * 188 * @param array $event event data 189 * @return bool true if buffered data should be flushed 190 */ 191 protected function isActivated(array $event) 192 { 193 foreach ($this->filters as $filter) { 194 if (! $filter->filter($event)) { 195 return false; 196 } 197 } 198 return true; 199 } 200 201 /** 202 * Write message to buffer or delegate event data to the wrapped writer 203 * 204 * @param array $event event data 205 * @return void 206 */ 207 protected function doWrite(array $event) 208 { 209 if (! $this->buffering) { 210 $this->writer->write($event); 211 return; 212 } 213 214 $this->buffer[] = $event; 215 216 if ($this->bufferSize > 0 && count($this->buffer) > $this->bufferSize) { 217 array_shift($this->buffer); 218 } 219 220 if (! $this->isActivated($event)) { 221 return; 222 } 223 224 $this->buffering = false; 225 226 foreach ($this->buffer as $bufferedEvent) { 227 $this->writer->write($bufferedEvent); 228 } 229 } 230 231 /** 232 * Resets the state of the handler. 233 * Stops forwarding records to the wrapped writer 234 */ 235 public function reset() 236 { 237 $this->buffering = true; 238 } 239 240 /** 241 * Stub in accordance to parent method signature. 242 * Fomatters must be set on the wrapped writer. 243 * 244 * @param string|FormatterInterface $formatter 245 * @param array|null $options (unused) 246 * @return WriterInterface 247 */ 248 public function setFormatter($formatter, array $options = null) 249 { 250 return $this->writer; 251 } 252 253 /** 254 * Record shutdown 255 * 256 * @return void 257 */ 258 public function shutdown() 259 { 260 $this->writer->shutdown(); 261 $this->buffer = null; 262 } 263} 264