Commit 915033c4 by lmf

补充vendor忽略文件

parent 140e5076
<?php
/*
* This file is part of the Behat Gherkin.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Behat\Gherkin\Cache;
use Behat\Gherkin\Node\FeatureNode;
/**
* Parser cache interface.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
interface CacheInterface
{
/**
* Checks that cache for feature exists and is fresh.
*
* @param string $path Feature path
* @param integer $timestamp The last time feature was updated
*
* @return bool
*/
public function isFresh($path, $timestamp);
/**
* Reads feature cache from path.
*
* @param string $path Feature path
*
* @return FeatureNode
*/
public function read($path);
/**
* Caches feature node.
*
* @param string $path Feature path
* @param FeatureNode $feature Feature instance
*/
public function write($path, FeatureNode $feature);
}
<?php
/*
* This file is part of the Behat Gherkin.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Behat\Gherkin\Cache;
use Behat\Gherkin\Exception\CacheException;
use Behat\Gherkin\Node\FeatureNode;
use Behat\Gherkin\Gherkin;
/**
* File cache.
* Caches feature into a file.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class FileCache implements CacheInterface
{
private $path;
/**
* Initializes file cache.
*
* @param string $path Path to the folder where to store caches.
*
* @throws CacheException
*/
public function __construct($path)
{
$this->path = rtrim($path, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR.'v'.Gherkin::VERSION;
if (!is_dir($this->path)) {
@mkdir($this->path, 0777, true);
}
if (!is_writeable($this->path)) {
throw new CacheException(sprintf('Cache path "%s" is not writeable. Check your filesystem permissions or disable Gherkin file cache.', $this->path));
}
}
/**
* Checks that cache for feature exists and is fresh.
*
* @param string $path Feature path
* @param integer $timestamp The last time feature was updated
*
* @return bool
*/
public function isFresh($path, $timestamp)
{
$cachePath = $this->getCachePathFor($path);
if (!file_exists($cachePath)) {
return false;
}
return filemtime($cachePath) > $timestamp;
}
/**
* Reads feature cache from path.
*
* @param string $path Feature path
*
* @return FeatureNode
*
* @throws CacheException
*/
public function read($path)
{
$cachePath = $this->getCachePathFor($path);
$feature = unserialize(file_get_contents($cachePath));
if (!$feature instanceof FeatureNode) {
throw new CacheException(sprintf('Can not load cache for a feature "%s" from "%s".', $path, $cachePath ));
}
return $feature;
}
/**
* Caches feature node.
*
* @param string $path Feature path
* @param FeatureNode $feature Feature instance
*/
public function write($path, FeatureNode $feature)
{
file_put_contents($this->getCachePathFor($path), serialize($feature));
}
/**
* Returns feature cache file path from features path.
*
* @param string $path Feature path
*
* @return string
*/
protected function getCachePathFor($path)
{
return $this->path.'/'.md5($path).'.feature.cache';
}
}
<?php
/*
* This file is part of the Behat Gherkin.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Behat\Gherkin\Cache;
use Behat\Gherkin\Node\FeatureNode;
/**
* Memory cache.
* Caches feature into a memory.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class MemoryCache implements CacheInterface
{
private $features = array();
private $timestamps = array();
/**
* Checks that cache for feature exists and is fresh.
*
* @param string $path Feature path
* @param integer $timestamp The last time feature was updated
*
* @return bool
*/
public function isFresh($path, $timestamp)
{
if (!isset($this->features[$path])) {
return false;
}
return $this->timestamps[$path] > $timestamp;
}
/**
* Reads feature cache from path.
*
* @param string $path Feature path
*
* @return FeatureNode
*/
public function read($path)
{
return $this->features[$path];
}
/**
* Caches feature node.
*
* @param string $path Feature path
* @param FeatureNode $feature Feature instance
*/
public function write($path, FeatureNode $feature)
{
$this->features[$path] = $feature;
$this->timestamps[$path] = time();
}
}
<?php
namespace Codeception\PHPUnit\Log;
use Codeception\Configuration;
use Codeception\Test\Interfaces\Reported;
use Codeception\Test\Test;
use PHPUnit\Framework\TestCase;
class JUnit extends \Codeception\PHPUnit\NonFinal\JUnit
{
protected $strictAttributes = ['file', 'name', 'class'];
public function startTest(\PHPUnit\Framework\Test $test):void
{
if (!$test instanceof Reported) {
parent::startTest($test);
return;
}
$this->currentTestCase = $this->document->createElement('testcase');
$isStrict = Configuration::config()['settings']['strict_xml'];
foreach ($test->getReportFields() as $attr => $value) {
if ($isStrict and !in_array($attr, $this->strictAttributes)) {
continue;
}
$this->currentTestCase->setAttribute($attr, $value);
}
}
public function endTest(\PHPUnit\Framework\Test $test, float $time):void
{
if ($this->currentTestCase !== null and $test instanceof Test) {
$numAssertions = $test->getNumAssertions();
$this->testSuiteAssertions[$this->testSuiteLevel] += $numAssertions;
$this->currentTestCase->setAttribute(
'assertions',
$numAssertions
);
}
if ($test instanceof TestCase) {
parent::endTest($test, $time);
return;
}
// since PhpUnit 7.4.0, parent::endTest ignores tests that aren't instances of TestCase
// so I copied this code from PhpUnit 7.3.5
$this->currentTestCase->setAttribute(
'time',
\sprintf('%F', $time)
);
$this->testSuites[$this->testSuiteLevel]->appendChild(
$this->currentTestCase
);
$this->testSuiteTests[$this->testSuiteLevel]++;
$this->testSuiteTimes[$this->testSuiteLevel] += $time;
$this->currentTestCase = null;
}
}
<?php
namespace Codeception\PHPUnit\Log;
use Codeception\Configuration;
use Codeception\Test\Interfaces\Reported;
use Codeception\Test\Test;
use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\TestSuite;
class PhpUnit extends \Codeception\PHPUnit\NonFinal\JUnit
{
const SUITE_LEVEL = 1;
const FILE_LEVEL = 2;
protected $strictAttributes = ['file', 'name', 'class'];
private $currentFile;
private $currentFileSuite;
public function startTest(\PHPUnit\Framework\Test $test):void
{
if (method_exists($test, 'getFileName') ) {
$filename = $test->getFileName();
} else {
$reflector = new \ReflectionClass($test);
$filename = $reflector->getFileName();
}
if ($filename !== $this->currentFile) {
if ($this->currentFile !== null) {
parent::endTestSuite(new TestSuite());
}
//initialize all values to avoid warnings
$this->testSuiteAssertions[self::FILE_LEVEL] = 0;
$this->testSuiteTests[self::FILE_LEVEL] = 0;
$this->testSuiteTimes[self::FILE_LEVEL] = 0;
$this->testSuiteErrors[self::FILE_LEVEL] = 0;
$this->testSuiteFailures[self::FILE_LEVEL] = 0;
$this->testSuiteSkipped[self::FILE_LEVEL] = 0;
$this->testSuiteLevel = self::FILE_LEVEL;
$this->currentFile = $filename;
$this->currentFileSuite = $this->document->createElement('testsuite');
if ($test instanceof Reported) {
$reportFields = $test->getReportFields();
$class = isset($reportFields['class']) ? $reportFields['class'] : $reportFields['name'];
$this->currentFileSuite->setAttribute('name', $class);
} else {
$this->currentFileSuite->setAttribute('name', get_class($test));
}
$this->currentFileSuite->setAttribute('file', $filename);
$this->testSuites[self::SUITE_LEVEL]->appendChild($this->currentFileSuite);
$this->testSuites[self::FILE_LEVEL] = $this->currentFileSuite;
}
if (!$test instanceof Reported) {
parent::startTest($test);
return;
}
$this->currentTestCase = $this->document->createElement('testcase');
$isStrict = Configuration::config()['settings']['strict_xml'];
foreach ($test->getReportFields() as $attr => $value) {
if ($isStrict and !in_array($attr, $this->strictAttributes)) {
continue;
}
$this->currentTestCase->setAttribute($attr, $value);
}
}
public function endTest(\PHPUnit\Framework\Test $test, float $time):void
{
if ($this->currentTestCase !== null && $test instanceof Test) {
$numAssertions = $test->getNumAssertions();
$this->testSuiteAssertions[$this->testSuiteLevel] += $numAssertions;
$this->currentTestCase->setAttribute(
'assertions',
$numAssertions
);
}
if ($test instanceof TestCase) {
parent::endTest($test, $time);
return;
}
// In PhpUnit 7.4.*, parent::endTest ignores tests that aren't instances of TestCase
// so I copied this code from PhpUnit 7.3.5
$this->currentTestCase->setAttribute(
'time',
\sprintf('%F', $time)
);
$this->testSuites[$this->testSuiteLevel]->appendChild(
$this->currentTestCase
);
$this->testSuiteTests[$this->testSuiteLevel]++;
$this->testSuiteTimes[$this->testSuiteLevel] += $time;
$this->currentTestCase = null;
}
/**
* Cleans the mess caused by test suite manipulation in startTest
*/
public function endTestSuite(TestSuite $suite): void
{
if ($suite->getName()) {
if ($this->currentFile) {
//close last file in the test suite
parent::endTestSuite(new TestSuite());
$this->currentFile = null;
}
$this->testSuiteLevel = self::SUITE_LEVEL;
}
parent::endTestSuite($suite);
}
}
<?php
/*
* This file is part of PHP CS Fixer.
*
* (c) Fabien Potencier <fabien@symfony.com>
* Dariusz Rumiński <dariusz.ruminski@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace PhpCsFixer\Cache;
/**
* @author Andreas Möller <am@localheinz.com>
*
* @internal
*/
final class Cache implements CacheInterface
{
/**
* @var SignatureInterface
*/
private $signature;
/**
* @var array
*/
private $hashes = [];
public function __construct(SignatureInterface $signature)
{
$this->signature = $signature;
}
public function getSignature()
{
return $this->signature;
}
public function has($file)
{
return \array_key_exists($file, $this->hashes);
}
public function get($file)
{
if (!$this->has($file)) {
return null;
}
return $this->hashes[$file];
}
public function set($file, $hash)
{
$this->hashes[$file] = $hash;
}
public function clear($file)
{
unset($this->hashes[$file]);
}
public function toJson()
{
$json = json_encode([
'php' => $this->getSignature()->getPhpVersion(),
'version' => $this->getSignature()->getFixerVersion(),
'indent' => $this->getSignature()->getIndent(),
'lineEnding' => $this->getSignature()->getLineEnding(),
'rules' => $this->getSignature()->getRules(),
'hashes' => $this->hashes,
]);
if (JSON_ERROR_NONE !== json_last_error()) {
throw new \UnexpectedValueException(sprintf(
'Can not encode cache signature to JSON, error: "%s". If you have non-UTF8 chars in your signature, like in license for `header_comment`, consider enabling `ext-mbstring` or install `symfony/polyfill-mbstring`.',
json_last_error_msg()
));
}
return $json;
}
/**
* @param string $json
*
* @throws \InvalidArgumentException
*
* @return Cache
*/
public static function fromJson($json)
{
$data = json_decode($json, true);
if (null === $data && JSON_ERROR_NONE !== json_last_error()) {
throw new \InvalidArgumentException(sprintf(
'Value needs to be a valid JSON string, got "%s", error: "%s".',
$json,
json_last_error_msg()
));
}
$requiredKeys = [
'php',
'version',
'indent',
'lineEnding',
'rules',
'hashes',
];
$missingKeys = array_diff_key(array_flip($requiredKeys), $data);
if (\count($missingKeys)) {
throw new \InvalidArgumentException(sprintf(
'JSON data is missing keys "%s"',
implode('", "', $missingKeys)
));
}
$signature = new Signature(
$data['php'],
$data['version'],
$data['indent'],
$data['lineEnding'],
$data['rules']
);
$cache = new self($signature);
$cache->hashes = $data['hashes'];
return $cache;
}
}
<?php
/*
* This file is part of PHP CS Fixer.
*
* (c) Fabien Potencier <fabien@symfony.com>
* Dariusz Rumiński <dariusz.ruminski@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace PhpCsFixer\Cache;
/**
* @author Andreas Möller <am@localheinz.com>
*
* @internal
*/
interface CacheInterface
{
/**
* @return SignatureInterface
*/
public function getSignature();
/**
* @param string $file
*
* @return bool
*/
public function has($file);
/**
* @param string $file
*
* @return null|int
*/
public function get($file);
/**
* @param string $file
* @param int $hash
*/
public function set($file, $hash);
/**
* @param string $file
*/
public function clear($file);
/**
* @return string
*/
public function toJson();
}
<?php
/*
* This file is part of PHP CS Fixer.
*
* (c) Fabien Potencier <fabien@symfony.com>
* Dariusz Rumiński <dariusz.ruminski@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace PhpCsFixer\Cache;
/**
* @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
*
* @internal
*/
interface CacheManagerInterface
{
/**
* @param string $file
* @param string $fileContent
*
* @return bool
*/
public function needFixing($file, $fileContent);
/**
* @param string $file
* @param string $fileContent
*/
public function setFile($file, $fileContent);
}
<?php
/*
* This file is part of PHP CS Fixer.
*
* (c) Fabien Potencier <fabien@symfony.com>
* Dariusz Rumiński <dariusz.ruminski@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace PhpCsFixer\Cache;
/**
* @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
*
* @internal
*/
final class Directory implements DirectoryInterface
{
/**
* @var string
*/
private $directoryName;
/**
* @param string $directoryName
*/
public function __construct($directoryName)
{
$this->directoryName = $directoryName;
}
public function getRelativePathTo($file)
{
$file = $this->normalizePath($file);
if (
'' === $this->directoryName
|| 0 !== stripos($file, $this->directoryName.\DIRECTORY_SEPARATOR)
) {
return $file;
}
return substr($file, \strlen($this->directoryName) + 1);
}
private function normalizePath($path)
{
return str_replace(['\\', '/'], \DIRECTORY_SEPARATOR, $path);
}
}
<?php
/*
* This file is part of PHP CS Fixer.
*
* (c) Fabien Potencier <fabien@symfony.com>
* Dariusz Rumiński <dariusz.ruminski@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace PhpCsFixer\Cache;
/**
* @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
*/
interface DirectoryInterface
{
/**
* @param string $file
*
* @return string
*/
public function getRelativePathTo($file);
}
<?php
/*
* This file is part of PHP CS Fixer.
*
* (c) Fabien Potencier <fabien@symfony.com>
* Dariusz Rumiński <dariusz.ruminski@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace PhpCsFixer\Cache;
/**
* Class supports caching information about state of fixing files.
*
* Cache is supported only for phar version and version installed via composer.
*
* File will be processed by PHP CS Fixer only if any of the following conditions is fulfilled:
* - cache is corrupt
* - fixer version changed
* - rules changed
* - file is new
* - file changed
*
* @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
*
* @internal
*/
final class FileCacheManager implements CacheManagerInterface
{
/**
* @var FileHandlerInterface
*/
private $handler;
/**
* @var SignatureInterface
*/
private $signature;
/**
* @var CacheInterface
*/
private $cache;
/**
* @var bool
*/
private $isDryRun;
/**
* @var DirectoryInterface
*/
private $cacheDirectory;
/**
* @param bool $isDryRun
*/
public function __construct(
FileHandlerInterface $handler,
SignatureInterface $signature,
$isDryRun = false,
DirectoryInterface $cacheDirectory = null
) {
$this->handler = $handler;
$this->signature = $signature;
$this->isDryRun = $isDryRun;
$this->cacheDirectory = $cacheDirectory ?: new Directory('');
$this->readCache();
}
public function __destruct()
{
$this->writeCache();
}
/**
* This class is not intended to be serialized,
* and cannot be deserialized (see __wakeup method).
*/
public function __sleep()
{
throw new \BadMethodCallException('Cannot serialize '.__CLASS__);
}
/**
* Disable the deserialization of the class to prevent attacker executing
* code by leveraging the __destruct method.
*
* @see https://owasp.org/www-community/vulnerabilities/PHP_Object_Injection
*/
public function __wakeup()
{
throw new \BadMethodCallException('Cannot unserialize '.__CLASS__);
}
public function needFixing($file, $fileContent)
{
$file = $this->cacheDirectory->getRelativePathTo($file);
return !$this->cache->has($file) || $this->cache->get($file) !== $this->calcHash($fileContent);
}
public function setFile($file, $fileContent)
{
$file = $this->cacheDirectory->getRelativePathTo($file);
$hash = $this->calcHash($fileContent);
if ($this->isDryRun && $this->cache->has($file) && $this->cache->get($file) !== $hash) {
$this->cache->clear($file);
return;
}
$this->cache->set($file, $hash);
}
private function readCache()
{
$cache = $this->handler->read();
if (!$cache || !$this->signature->equals($cache->getSignature())) {
$cache = new Cache($this->signature);
}
$this->cache = $cache;
}
private function writeCache()
{
$this->handler->write($this->cache);
}
private function calcHash($content)
{
return crc32($content);
}
}
<?php
/*
* This file is part of PHP CS Fixer.
*
* (c) Fabien Potencier <fabien@symfony.com>
* Dariusz Rumiński <dariusz.ruminski@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace PhpCsFixer\Cache;
use Symfony\Component\Filesystem\Exception\IOException;
/**
* @author Andreas Möller <am@localheinz.com>
*
* @internal
*/
final class FileHandler implements FileHandlerInterface
{
/**
* @var string
*/
private $file;
/**
* @param string $file
*/
public function __construct($file)
{
$this->file = $file;
}
public function getFile()
{
return $this->file;
}
public function read()
{
if (!file_exists($this->file)) {
return null;
}
$content = file_get_contents($this->file);
try {
$cache = Cache::fromJson($content);
} catch (\InvalidArgumentException $exception) {
return null;
}
return $cache;
}
public function write(CacheInterface $cache)
{
$content = $cache->toJson();
if (file_exists($this->file)) {
if (is_dir($this->file)) {
throw new IOException(
sprintf('Cannot write cache file "%s" as the location exists as directory.', realpath($this->file)),
0,
null,
$this->file
);
}
if (!is_writable($this->file)) {
throw new IOException(
sprintf('Cannot write to file "%s" as it is not writable.', realpath($this->file)),
0,
null,
$this->file
);
}
} else {
$dir = \dirname($this->file);
if (!is_dir($dir)) {
throw new IOException(
sprintf('Directory of cache file "%s" does not exists.', $this->file),
0,
null,
$this->file
);
}
@touch($this->file);
@chmod($this->file, 0666);
}
$bytesWritten = @file_put_contents($this->file, $content);
if (false === $bytesWritten) {
$error = error_get_last();
throw new IOException(
sprintf('Failed to write file "%s", "%s".', $this->file, isset($error['message']) ? $error['message'] : 'no reason available'),
0,
null,
$this->file
);
}
}
}
<?php
/*
* This file is part of PHP CS Fixer.
*
* (c) Fabien Potencier <fabien@symfony.com>
* Dariusz Rumiński <dariusz.ruminski@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace PhpCsFixer\Cache;
/**
* @author Andreas Möller <am@localheinz.com>
*
* @internal
*/
interface FileHandlerInterface
{
/**
* @return string
*/
public function getFile();
/**
* @return null|CacheInterface
*/
public function read();
public function write(CacheInterface $cache);
}
<?php
/*
* This file is part of PHP CS Fixer.
*
* (c) Fabien Potencier <fabien@symfony.com>
* Dariusz Rumiński <dariusz.ruminski@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace PhpCsFixer\Cache;
/**
* @author Andreas Möller <am@localheinz.com>
*
* @internal
*/
final class NullCacheManager implements CacheManagerInterface
{
public function needFixing($file, $fileContent)
{
return true;
}
public function setFile($file, $fileContent)
{
}
}
<?php
/*
* This file is part of PHP CS Fixer.
*
* (c) Fabien Potencier <fabien@symfony.com>
* Dariusz Rumiński <dariusz.ruminski@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace PhpCsFixer\Cache;
/**
* @author Andreas Möller <am@localheinz.com>
*
* @internal
*/
final class Signature implements SignatureInterface
{
/**
* @var string
*/
private $phpVersion;
/**
* @var string
*/
private $fixerVersion;
/**
* @var string
*/
private $indent;
/**
* @var string
*/
private $lineEnding;
/**
* @var array
*/
private $rules;
/**
* @param string $phpVersion
* @param string $fixerVersion
* @param string $indent
* @param string $lineEnding
*/
public function __construct($phpVersion, $fixerVersion, $indent, $lineEnding, array $rules)
{
$this->phpVersion = $phpVersion;
$this->fixerVersion = $fixerVersion;
$this->indent = $indent;
$this->lineEnding = $lineEnding;
$this->rules = self::utf8Encode($rules);
}
public function getPhpVersion()
{
return $this->phpVersion;
}
public function getFixerVersion()
{
return $this->fixerVersion;
}
public function getIndent()
{
return $this->indent;
}
public function getLineEnding()
{
return $this->lineEnding;
}
public function getRules()
{
return $this->rules;
}
public function equals(SignatureInterface $signature)
{
return $this->phpVersion === $signature->getPhpVersion()
&& $this->fixerVersion === $signature->getFixerVersion()
&& $this->indent === $signature->getIndent()
&& $this->lineEnding === $signature->getLineEnding()
&& $this->rules === $signature->getRules();
}
private static function utf8Encode(array $data)
{
if (!\function_exists('mb_detect_encoding')) {
return $data;
}
array_walk_recursive($data, static function (&$item) {
if (\is_string($item) && !mb_detect_encoding($item, 'utf-8', true)) {
$item = utf8_encode($item);
}
});
return $data;
}
}
<?php
/*
* This file is part of PHP CS Fixer.
*
* (c) Fabien Potencier <fabien@symfony.com>
* Dariusz Rumiński <dariusz.ruminski@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace PhpCsFixer\Cache;
/**
* @author Andreas Möller <am@localheinz.com>
*
* @internal
*/
interface SignatureInterface
{
/**
* @return string
*/
public function getPhpVersion();
/**
* @return string
*/
public function getFixerVersion();
/**
* @return string
*/
public function getIndent();
/**
* @return string
*/
public function getLineEnding();
/**
* @return array
*/
public function getRules();
/**
* @param SignatureInterface $signature
*
* @return bool
*/
public function equals(self $signature);
}
<?php
declare(strict_types=1);
namespace Metadata\Cache;
use Metadata\ClassMetadata;
interface CacheInterface
{
/**
* Loads a class metadata instance from the cache
*/
public function load(string $class): ?ClassMetadata;
/**
* Puts a class metadata instance into the cache
*/
public function put(ClassMetadata $metadata): void;
/**
* Evicts the class metadata for the given class from the cache.
*/
public function evict(string $class): void;
}
<?php
declare(strict_types=1);
namespace Metadata\Cache;
/**
* @author Alexander Strizhak <gam6itko@gmail.com>
*/
interface ClearableCacheInterface
{
/**
* Clear all classes metadata from the cache.
*/
public function clear(): bool;
}
<?php
declare(strict_types=1);
namespace Metadata\Cache;
use Doctrine\Common\Cache\Cache;
use Metadata\ClassMetadata;
/**
* @author Henrik Bjornskov <henrik@bjrnskov.dk>
*/
class DoctrineCacheAdapter implements CacheInterface, ClearableCacheInterface
{
/**
* @var string
*/
private $prefix;
/**
* @var Cache
*/
private $cache;
public function __construct(string $prefix, Cache $cache)
{
$this->prefix = $prefix;
$this->cache = $cache;
}
public function load(string $class): ?ClassMetadata
{
$cache = $this->cache->fetch($this->prefix . $class);
return false === $cache ? null : $cache;
}
public function put(ClassMetadata $metadata): void
{
$this->cache->save($this->prefix . $metadata->name, $metadata);
}
public function evict(string $class): void
{
$this->cache->delete($this->prefix . $class);
}
public function clear(): bool
{
if (method_exists($this->cache, 'deleteAll')) { // or $this->cache instanceof ClearableCache
return call_user_func([$this->cache, 'deleteAll']);
}
return false;
}
}
<?php
declare(strict_types=1);
namespace Metadata\Cache;
use Metadata\ClassMetadata;
class FileCache implements CacheInterface, ClearableCacheInterface
{
/**
* @var string
*/
private $dir;
public function __construct(string $dir)
{
if (!is_dir($dir) && false === @mkdir($dir, 0777, true)) {
throw new \InvalidArgumentException(sprintf('Can\'t create directory for cache at "%s"', $dir));
}
$this->dir = rtrim($dir, '\\/');
}
public function load(string $class): ?ClassMetadata
{
$path = $this->getCachePath($class);
if (!is_readable($path)) {
return null;
}
try {
$metadata = include $path;
if ($metadata instanceof ClassMetadata) {
return $metadata;
}
// if the file does not return anything, the return value is integer `1`.
} catch (\Error $e) {
// ignore corrupted cache
}
return null;
}
public function put(ClassMetadata $metadata): void
{
if (!is_writable($this->dir)) {
throw new \InvalidArgumentException(sprintf('The directory "%s" is not writable.', $this->dir));
}
$path = $this->getCachePath($metadata->name);
if (!is_writable(dirname($path))) {
throw new \RuntimeException(sprintf('Cache file "%s" is not writable.', $path));
}
$tmpFile = tempnam($this->dir, 'metadata-cache');
if (false === $tmpFile) {
$this->evict($metadata->name);
return;
}
$data = '<?php return unserialize(' . var_export(serialize($metadata), true) . ');';
$bytesWritten = file_put_contents($tmpFile, $data);
// use strlen and not mb_strlen. if there is utf8 in the code, it also writes more bytes.
if ($bytesWritten !== strlen($data)) {
@unlink($tmpFile);
// also evict the cache to not use an outdated version.
$this->evict($metadata->name);
return;
}
// Let's not break filesystems which do not support chmod.
@chmod($tmpFile, 0666 & ~umask());
$this->renameFile($tmpFile, $path);
}
/**
* Renames a file with fallback for windows
*/
private function renameFile(string $source, string $target): void
{
if (false === @rename($source, $target)) {
if (defined('PHP_WINDOWS_VERSION_BUILD')) {
if (false === copy($source, $target)) {
throw new \RuntimeException(sprintf('(WIN) Could not write new cache file to %s.', $target));
}
if (false === unlink($source)) {
throw new \RuntimeException(sprintf('(WIN) Could not delete temp cache file to %s.', $source));
}
} else {
throw new \RuntimeException(sprintf('Could not write new cache file to %s.', $target));
}
}
}
public function evict(string $class): void
{
$path = $this->getCachePath($class);
if (file_exists($path)) {
@unlink($path);
}
}
public function clear(): bool
{
$result = true;
$files = glob($this->dir . '/*.cache.php');
foreach ($files as $file) {
if (is_file($file)) {
$result = $result && @unlink($file);
}
}
return $result;
}
/**
* This function computes the cache file path.
*
* If anonymous class is to be cached, it contains invalid path characters that need to be removed/replaced
* Example of anonymous class name: class@anonymous\x00/app/src/Controller/DefaultController.php0x7f82a7e026ec
*/
private function getCachePath(string $key): string
{
$fileName = str_replace(['\\', "\0", '@', '/', '$', '{', '}', ':'], '-', $key);
return $this->dir . '/' . $fileName . '.cache.php';
}
}
<?php
declare(strict_types=1);
namespace Metadata\Cache;
use Metadata\ClassMetadata;
use Psr\Cache\CacheItemPoolInterface;
class PsrCacheAdapter implements CacheInterface, ClearableCacheInterface
{
/**
* @var string
*/
private $prefix;
/**
* @var CacheItemPoolInterface
*/
private $pool;
/**
* @var CacheItemPoolInterface
*/
private $lastItem;
public function __construct(string $prefix, CacheItemPoolInterface $pool)
{
$this->prefix = $prefix;
$this->pool = $pool;
}
public function load(string $class): ?ClassMetadata
{
$this->lastItem = $this->pool->getItem($this->sanitizeCacheKey($this->prefix . $class));
return $this->lastItem->get();
}
public function put(ClassMetadata $metadata): void
{
$key = $this->sanitizeCacheKey($this->prefix . $metadata->name);
if (null === $this->lastItem || $this->lastItem->getKey() !== $key) {
$this->lastItem = $this->pool->getItem($key);
}
$this->pool->save($this->lastItem->set($metadata));
}
public function evict(string $class): void
{
$this->pool->deleteItem($this->sanitizeCacheKey($this->prefix . $class));
}
public function clear(): bool
{
return $this->pool->clear();
}
/**
* If anonymous class is to be cached, it contains invalid path characters that need to be removed/replaced
* Example of anonymous class name: class@anonymous\x00/app/src/Controller/DefaultController.php0x7f82a7e026ec
*/
private function sanitizeCacheKey(string $key): string
{
return str_replace(['\\', "\0", '@', '/', '$', '{', '}', ':'], '-', $key);
}
}
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\CodeMessDetector\Rule\Design;
use PHPMD\AbstractNode;
use PHPMD\AbstractRule;
use PHPMD\Rule\ClassAware;
use PHPMD\Rule\MethodAware;
/**
* Magento is a highly extensible and customizable platform.
* Usage of final classes and methods is prohibited.
*/
class FinalImplementation extends AbstractRule implements ClassAware, MethodAware
{
/**
* @inheritdoc
*/
public function apply(AbstractNode $node)
{
if ($node->isFinal()) {
$this->addViolation($node, [$node->getType(), $node->getFullQualifiedName()]);
}
}
}
<?xml version="1.0"?>
<!--
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
-->
<ruleset name="Magento Specific Design Rules"
xmlns="http://pmd.sf.net/ruleset/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0 http://pmd.sf.net/ruleset_xml_schema.xsd"
xsi:noNamespaceSchemaLocation="http://pmd.sf.net/ruleset_xml_schema.xsd">
<rule name="FinalImplementation"
class="Magento\CodeMessDetector\Rule\Design\FinalImplementation"
message= "The {0} {1} declared as final.">
<description>
<![CDATA[
Final keyword is prohibited in Magento as this decreases extensibility and customizability.
Final classes and method are not compatible with plugins and proxies.
]]>
</description>
<priority>1</priority>
<properties />
<example>
<![CDATA[
final class Foo
{
public function bar() {}
}
class Baz {
final public function bad() {}
}
]]>
</example>
</rule>
</ruleset>
<?xml version='1.0' encoding="UTF-8"?>
<!--
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
-->
<ruleset name="Magento PHPMD rule set" xmlns="http://pmd.sf.net/ruleset/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0 http://pmd.sf.net/ruleset_xml_schema.xsd"
xsi:noNamespaceSchemaLocation="http://pmd.sf.net/ruleset_xml_schema.xsd">
<description>Magento Code Check Rules</description>
<php-includepath>../../../static</php-includepath>
<!-- Code Size Rules -->
<rule ref="rulesets/codesize.xml/CyclomaticComplexity" />
<rule ref="rulesets/codesize.xml/NPathComplexity" />
<rule ref="rulesets/codesize.xml/ExcessiveMethodLength" />
<rule ref="rulesets/codesize.xml/ExcessiveParameterList" />
<rule ref="rulesets/codesize.xml/ExcessivePublicCount" />
<rule ref="rulesets/codesize.xml/TooManyFields" />
<rule ref="rulesets/codesize.xml/ExcessiveClassComplexity">
<properties>
<property name="maximum" value="100" />
</properties>
</rule>
<!-- Unused code rules -->
<rule ref="rulesets/unusedcode.xml/UnusedPrivateField" />
<rule ref="rulesets/unusedcode.xml/UnusedPrivateMethod" />
<rule ref="rulesets/unusedcode.xml/UnusedFormalParameter" />
<rule ref="rulesets/unusedcode.xml/UnusedLocalVariable" >
<properties>
<property name="allow-unused-foreach-variables" value="true"/>
</properties>
</rule>
<!-- Code design rules -->
<rule ref="rulesets/design.xml/ExitExpression" />
<rule ref="rulesets/design.xml/EvalExpression" />
<rule ref="rulesets/design.xml/GotoStatement" />
<rule ref="rulesets/design.xml/NumberOfChildren" />
<rule ref="rulesets/design.xml/DepthOfInheritance">
<properties>
<property name="minimum" value="8" />
</properties>
</rule>
<rule ref="rulesets/design.xml/CouplingBetweenObjects" />
<!-- Naming Rules -->
<rule ref="rulesets/naming.xml/ShortMethodName" />
<rule ref="rulesets/naming.xml/ConstantNamingConventions" />
<rule ref="rulesets/naming.xml/BooleanGetMethodName" />
<!-- Magento Specific Rules -->
<rule ref="Magento/CodeMessDetector/resources/rulesets/design.xml/FinalImplementation" />
</ruleset>
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Sniffs\Arrays;
use PHP_CodeSniffer\Sniffs\Sniff;
use PHP_CodeSniffer\Files\File;
class ShortArraySyntaxSniff implements Sniff
{
/**
* {@inheritdoc}
*/
public function register()
{
return [T_ARRAY];
}
/**
* {@inheritdoc}
*/
public function process(File $sourceFile, $stackPtr)
{
$sourceFile->addError(
'Short array syntax must be used; expected "[]" but found "array()"',
$stackPtr,
'ShortArraySyntax'
);
}
}
<?php
/**
* Parses and verifies the variable doc comment.
*
* @author Greg Sherwood <gsherwood@squiz.net>
* @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
*/
namespace Magento\Sniffs\Commenting;
use PHP_CodeSniffer\Sniffs\AbstractVariableSniff;
use PHP_CodeSniffer\Files\File;
use PHP_CodeSniffer\Util\Common;
class VariableCommentSniff extends AbstractVariableSniff
{
/**
* Called to process class member vars.
*
* @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
* @param int $stackPtr The position of the current token
* in the stack passed in $tokens.
*
* @return void
*/
public function processMemberVar(File $phpcsFile, $stackPtr)
{
$tokens = $phpcsFile->getTokens();
$ignore = array(
T_PUBLIC,
T_PRIVATE,
T_PROTECTED,
T_VAR,
T_STATIC,
T_WHITESPACE,
);
$commentEnd = $phpcsFile->findPrevious($ignore, ($stackPtr - 1), null, true);
if ($commentEnd === false
|| ($tokens[$commentEnd]['code'] !== T_DOC_COMMENT_CLOSE_TAG
&& $tokens[$commentEnd]['code'] !== T_COMMENT)
) {
$phpcsFile->addError('Missing member variable doc comment', $stackPtr, 'Missing');
return;
}
if ($tokens[$commentEnd]['code'] === T_COMMENT) {
$phpcsFile->addError('You must use "/**" style comments for a member variable comment', $stackPtr, 'WrongStyle');
return;
}
$commentStart = $tokens[$commentEnd]['comment_opener'];
$foundVar = null;
foreach ($tokens[$commentStart]['comment_tags'] as $tag) {
if ($tokens[$tag]['content'] === '@var') {
if ($foundVar !== null) {
$error = 'Only one @var tag is allowed in a member variable comment';
$phpcsFile->addError($error, $tag, 'DuplicateVar');
} else {
$foundVar = $tag;
}
} else if ($tokens[$tag]['content'] === '@see') {
// Make sure the tag isn't empty.
$string = $phpcsFile->findNext(T_DOC_COMMENT_STRING, $tag, $commentEnd);
if ($string === false || $tokens[$string]['line'] !== $tokens[$tag]['line']) {
$error = 'Content missing for @see tag in member variable comment';
$phpcsFile->addError($error, $tag, 'EmptySees');
}
} else {
$error = '%s tag is not allowed in member variable comment';
$data = array($tokens[$tag]['content']);
$phpcsFile->addWarning($error, $tag, 'TagNotAllowed', $data);
}//end if
}//end foreach
// The @var tag is the only one we require.
if ($foundVar === null) {
$error = 'Missing @var tag in member variable comment';
$phpcsFile->addError($error, $commentEnd, 'MissingVar');
return;
}
$firstTag = $tokens[$commentStart]['comment_tags'][0];
if ($foundVar !== null && $tokens[$firstTag]['content'] !== '@var') {
$error = 'The @var tag must be the first tag in a member variable comment';
$phpcsFile->addError($error, $foundVar, 'VarOrder');
}
// Make sure the tag isn't empty and has the correct padding.
$string = $phpcsFile->findNext(T_DOC_COMMENT_STRING, $foundVar, $commentEnd);
if ($string === false || $tokens[$string]['line'] !== $tokens[$foundVar]['line']) {
$error = 'Content missing for @var tag in member variable comment';
$phpcsFile->addError($error, $foundVar, 'EmptyVar');
return;
}
$varType = $tokens[($foundVar + 2)]['content'];
$suggestedType = Common::suggestType($varType);
if ($varType !== $suggestedType) {
$error = 'Expected "%s" but found "%s" for @var tag in member variable comment';
$data = array(
$suggestedType,
$varType,
);
$fix = $phpcsFile->addFixableError($error, ($foundVar + 2), 'IncorrectVarType', $data);
if ($fix === true) {
$phpcsFile->fixer->replaceToken(($foundVar + 2), $suggestedType);
}
}
}//end processMemberVar()
/**
* Called to process a normal variable.
*
* Not required for this sniff.
*
* @param \PHP_CodeSniffer\Files\File $phpcsFile The PHP_CodeSniffer file where this token was found.
* @param int $stackPtr The position where the double quoted
* string was found.
*
* @return void
*/
protected function processVariable(File $phpcsFile, $stackPtr)
{
}//end processVariable()
/**
* Called to process variables found in double quoted strings.
*
* Not required for this sniff.
*
* @param \PHP_CodeSniffer\Files\File $phpcsFile The PHP_CodeSniffer file where this token was found.
* @param int $stackPtr The position where the double quoted
* string was found.
*
* @return void
*/
protected function processVariableInString(File $phpcsFile, $stackPtr)
{
}//end processVariableInString()
}//end class
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Sniffs\Files;
use PHP_CodeSniffer\Standards\Generic\Sniffs\Files\LineLengthSniff as FilesLineLengthSniff;
/**
* Line length sniff which ignores long lines in case they contain strings intended for translation.
*/
class LineLengthSniff extends FilesLineLengthSniff
{
/**
* Having previous line content allows to ignore long lines in case of multi-line declaration.
*
* @var string
*/
protected $previousLineContent = '';
/**
* {@inheritdoc}
*/
protected function checkLineLength($phpcsFile, $stackPtr, $lineContent)
{
$previousLineRegexp = '~__\($|\bPhrase\($~';
$currentLineRegexp = '~__\(.+\)|\bPhrase\(.+\)~';
$currentLineMatch = preg_match($currentLineRegexp, $lineContent) !== 0;
$previousLineMatch = preg_match($previousLineRegexp, $this->previousLineContent) !== 0;
$this->previousLineContent = $lineContent;
if (! $currentLineMatch && !$previousLineMatch) {
parent::checkLineLength($phpcsFile, $stackPtr, $lineContent);
}
}
}
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Sniffs\LiteralNamespaces;
use PHP_CodeSniffer\Sniffs\Sniff;
use PHP_CodeSniffer\Files\File;
/**
* Custom phpcs sniff to detect usages of literal class and interface names.
*/
class LiteralNamespacesSniff implements Sniff
{
/**
* @var string
*/
private $literalNamespacePattern = '/^[\\\]{0,2}[A-Z][A-Za-z]+([\\\]{1,2}[A-Z][A-Za-z]+){2,}(?!\\\+)$/';
/**
* @var array
*/
private $classNames = [];
/**
* @inheritdoc
*/
public function register()
{
return [
T_CONSTANT_ENCAPSED_STRING,
T_DOUBLE_QUOTED_STRING,
];
}
/**
* @inheritdoc
*/
public function process(File $sourceFile, $stackPtr)
{
$tokens = $sourceFile->getTokens();
if ($sourceFile->findPrevious(T_STRING_CONCAT, $stackPtr, $stackPtr - 3) ||
$sourceFile->findNext(T_STRING_CONCAT, $stackPtr, $stackPtr + 3)
) {
return;
}
$content = trim($tokens[$stackPtr]['content'], "\"'");
// replace double slashes from class name for avoiding problems with class autoload
if (strpos($content, '\\') !== false) {
$content = preg_replace('|\\\{2,}|', '\\', $content);
}
if (preg_match($this->literalNamespacePattern, $content) === 1 && $this->classExists($content)) {
$sourceFile->addError(
"Use ::class notation instead.",
$stackPtr,
'LiteralClassUsage'
);
}
}
/**
* @param string $className
* @return bool
*/
private function classExists($className)
{
if (!isset($this->classNames[$className])) {
$this->classNames[$className] = class_exists($className) || interface_exists($className);
}
return $this->classNames[$className];
}
}
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Sniffs\MicroOptimizations;
use PHP_CodeSniffer\Sniffs\Sniff;
use PHP_CodeSniffer\Files\File;
class IsNullSniff implements Sniff
{
/**
* @var string
*/
protected $blocklist = 'is_null';
/**
* @inheritdoc
*/
public function register()
{
return [T_STRING];
}
/**
* @inheritdoc
*/
public function process(File $sourceFile, $stackPtr)
{
$tokens = $sourceFile->getTokens();
if ($tokens[$stackPtr]['content'] === $this->blocklist) {
$sourceFile->addError(
"is_null must be avoided. Use strict comparison instead.",
$stackPtr,
'IsNullUsage'
);
}
}
}
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Sniffs\NamingConventions;
use PHP_CodeSniffer\Sniffs\Sniff;
use PHP_CodeSniffer\Files\File;
class InterfaceNameSniff implements Sniff
{
const INTERFACE_SUFFIX = 'Interface';
/**
* {@inheritdoc}
*/
public function register()
{
return [T_INTERFACE];
}
/**
* {@inheritdoc}
*/
public function process(File $sourceFile, $stackPtr)
{
$tokens = $sourceFile->getTokens();
$declarationLine = $tokens[$stackPtr]['line'];
$suffixLength = strlen(self::INTERFACE_SUFFIX);
// Find first T_STRING after 'interface' keyword in the line and verify it
while ($tokens[$stackPtr]['line'] == $declarationLine) {
if ($tokens[$stackPtr]['type'] == 'T_STRING') {
if (substr($tokens[$stackPtr]['content'], 0 - $suffixLength) != self::INTERFACE_SUFFIX) {
$sourceFile->addError(
'Interface should have name that ends with "Interface" suffix.',
$stackPtr,
'WrongInterfaceName'
);
}
break;
}
$stackPtr++;
}
}
}
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Sniffs\NamingConventions;
use PHP_CodeSniffer\Sniffs\Sniff;
use PHP_CodeSniffer\Files\File;
class ReservedWordsSniff implements Sniff
{
/**
* The following words cannot be used to name a class, interface or trait,
* and they are also prohibited from being used in namespaces.
*
* @link http://php.net/manual/en/reserved.other-reserved-words.php
*
* @var string[]
*/
protected $reservedWords = [
'int' => '7',
'float' => '7',
'bool' => '7',
'string' => '7',
'true' => '7',
'false' => '7',
'null' => '7',
'void' => '7.1',
'iterable' => '7.1',
'resource' => '7',
'object' => '7',
'mixed' => '7',
'numeric' => '7',
];
/**
* {@inheritdoc}
*/
public function register()
{
return [T_CLASS, T_INTERFACE, T_TRAIT, T_NAMESPACE];
}
/**
* Check all namespace parts
*
* @param File $sourceFile
* @param int $stackPtr
* @return void
*/
protected function validateNamespace(File $sourceFile, $stackPtr)
{
$stackPtr += 2;
$tokens = $sourceFile->getTokens();
while ($stackPtr < $sourceFile->numTokens && $tokens[$stackPtr]['code'] !== T_SEMICOLON) {
if ($tokens[$stackPtr]['code'] === T_WHITESPACE || $tokens[$stackPtr]['code'] === T_NS_SEPARATOR) {
$stackPtr++; //skip "namespace" and whitespace
continue;
}
$namespacePart = $tokens[$stackPtr]['content'];
if (isset($this->reservedWords[strtolower($namespacePart)])) {
$sourceFile->addError(
'Cannot use "%s" in namespace as it is reserved since PHP %s',
$stackPtr,
'Namespace',
[$namespacePart, $this->reservedWords[$namespacePart]]
);
}
$stackPtr++;
}
}
/**
* Check class name not having reserved words
*
* @param File $sourceFile
* @param int $stackPtr
* @return void
*/
protected function validateClass(File $sourceFile, $stackPtr)
{
$tokens = $sourceFile->getTokens();
$stackPtr += 2; //skip "class" and whitespace
$className = strtolower($tokens[$stackPtr]['content']);
if (isset($this->reservedWords[$className])) {
$sourceFile->addError(
'Cannot use "%s" as class name as it is reserved since PHP %s',
$stackPtr,
'Class',
[$className, $this->reservedWords[$className]]
);
}
}
/**
* {@inheritdoc}
*/
public function process(File $sourceFile, $stackPtr)
{
$tokens = $sourceFile->getTokens();
switch ($tokens[$stackPtr]['code']) {
case T_CLASS:
case T_INTERFACE:
case T_TRAIT:
$this->validateClass($sourceFile, $stackPtr);
break;
case T_NAMESPACE:
$this->validateNamespace($sourceFile, $stackPtr);
break;
}
}
}
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Sniffs\Whitespace;
use PHP_CodeSniffer\Sniffs\Sniff;
use PHP_CodeSniffer\Files\File;
/**
* Class EmptyLineMissedSniff
*/
class EmptyLineMissedSniff implements Sniff
{
/**
* {@inheritdoc}
*/
public function register()
{
return [T_DOC_COMMENT];
}
/**
* {@inheritdoc}
*/
public function process(File $phpcsFile, $stackPtr)
{
$tokens = $phpcsFile->getTokens();
if ($this->doCheck($phpcsFile, $stackPtr, $tokens)) {
$previous = $phpcsFile->findPrevious(T_WHITESPACE, $stackPtr - 1, null, true);
if ($tokens[$stackPtr]['line'] - $tokens[$previous]['line'] < 2) {
$error = 'Empty line missed';
$phpcsFile->addError($error, $stackPtr, '', null);
}
}
}
/**
* @param File $phpcsFile
* @param int $stackPtr
* @param array $tokens
* @return bool
*/
private function doCheck(File $phpcsFile, $stackPtr, $tokens)
{
$result = false;
if ($phpcsFile->hasCondition($stackPtr, T_CLASS) || $phpcsFile->hasCondition($stackPtr, T_INTERFACE)) {
$result = true;
}
if ($phpcsFile->hasCondition($stackPtr, T_FUNCTION)) {
$result = false;
}
$previous = $phpcsFile->findPrevious(T_WHITESPACE, $stackPtr - 1, null, true);
if ($tokens[$previous]['type'] === 'T_OPEN_CURLY_BRACKET') {
$result = false;
}
if (strpos($tokens[$stackPtr]['content'], '/**') === false) {
$result = false;
}
return $result;
}
}
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Sniffs\Whitespace;
use PHP_CodeSniffer\Sniffs\Sniff;
use PHP_CodeSniffer\Files\File;
/**
* Class MultipleEmptyLinesSniff
*/
class MultipleEmptyLinesSniff implements Sniff
{
/**
* {@inheritdoc}
*/
public function register()
{
return [T_WHITESPACE];
}
/**
* {@inheritdoc}
*/
public function process(File $phpcsFile, $stackPtr)
{
$tokens = $phpcsFile->getTokens();
if ($phpcsFile->hasCondition($stackPtr, T_FUNCTION)
|| $phpcsFile->hasCondition($stackPtr, T_CLASS)
|| $phpcsFile->hasCondition($stackPtr, T_INTERFACE)
) {
if ($tokens[($stackPtr - 1)]['line'] < $tokens[$stackPtr]['line']
&& $tokens[($stackPtr - 2)]['line'] === $tokens[($stackPtr - 1)]['line']
) {
// This is an empty line and the line before this one is not
// empty, so this could be the start of a multiple empty line block
$next = $phpcsFile->findNext(T_WHITESPACE, $stackPtr, null, true);
$lines = $tokens[$next]['line'] - $tokens[$stackPtr]['line'];
if ($lines > 1) {
$error = 'Code must not contain multiple empty lines in a row; found %s empty lines';
$data = [$lines];
$phpcsFile->addError($error, $stackPtr, 'MultipleEmptyLines', $data);
}
}
}
}
}
<?xml version="1.0"?>
<!--
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
-->
<ruleset name="Magento2FunctionalTestingFramework">
<description>Custom Magento2 Functional Testing Framework coding standard.</description>
<rule ref="PSR2"/>
<rule ref="Magento.Files.LineLength">
<properties>
<property name="lineLimit" value="120"/>
<property name="absoluteLineLimit" value="120"/>
</properties>
</rule>
<rule ref="Magento.LiteralNamespaces.LiteralNamespaces">
<exclude-pattern>*/_files/*</exclude-pattern>
</rule>
<rule ref="Magento.Commenting.FunctionComment">
<exclude-pattern>*/dev/tests*</exclude-pattern>
</rule>
<rule ref="Magento.Commenting.VariableComment"/>
<rule ref="Generic.Functions.CallTimePassByReference"/>
<rule ref="Generic.PHP.DeprecatedFunctions"/>
<rule ref="Squiz.Commenting.DocCommentAlignment"/>
<rule ref="Squiz.Functions.GlobalFunction"/>
<rule ref="Squiz.WhiteSpace.LogicalOperatorSpacing"/>
<!-- Codeception Webdriver violates this, cannot fix as we extend from them -->
<rule ref="PSR2.Methods.MethodDeclaration.Underscore">
<severity>0</severity>
</rule>
</ruleset>
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\FunctionalTestingFramework\Code\Reader;
class ClassReader implements ClassReaderInterface
{
/**
* Read class constructor signature
*
* @param string $className
* @return array|null
* @throws \ReflectionException
*/
public function getConstructor($className)
{
$class = new \ReflectionClass($className);
$result = null;
$constructor = $class->getConstructor();
if ($constructor) {
$result = [];
/** @var $parameter \ReflectionParameter */
foreach ($constructor->getParameters() as $parameter) {
try {
$result[] = [
$parameter->getName(),
$parameter->getClass() !== null ? $parameter->getClass()->getName() : null,
!$parameter->isOptional(),
$parameter->isOptional()
? ($parameter->isDefaultValueAvailable() ? $parameter->getDefaultValue() : null)
: null,
];
} catch (\ReflectionException $e) {
$message = $e->getMessage();
throw new \ReflectionException($message, 0, $e);
}
}
}
return $result;
}
/**
* Retrieve parent relation information for type in a following format
* array(
* 'Parent_Class_Name',
* 'Interface_1',
* 'Interface_2',
* ...
* )
*
* @param string $className
* @return string[]
*/
public function getParents($className)
{
$parentClass = get_parent_class($className);
if ($parentClass) {
$result = [];
$interfaces = class_implements($className);
if ($interfaces) {
$parentInterfaces = class_implements($parentClass);
if ($parentInterfaces) {
$result = array_values(array_diff($interfaces, $parentInterfaces));
} else {
$result = array_values($interfaces);
}
}
array_unshift($result, $parentClass);
} else {
$result = array_values(class_implements($className));
if ($result) {
array_unshift($result, null);
} else {
$result = [];
}
}
return $result;
}
}
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\FunctionalTestingFramework\Code\Reader;
interface ClassReaderInterface
{
/**
* Read class constructor signature
*
* @param string $className
* @return array|null
* @throws \ReflectionException
*/
public function getConstructor($className);
/**
* Retrieve parent relation information for type in a following format
* array(
* 'Parent_Class_Name',
* 'Interface_1',
* 'Interface_2',
* ...
* )
*
* @param string $className
* @return string[]
*/
public function getParents($className);
}
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\FunctionalTestingFramework\Helper\Code;
/**
* Class ClassReader
*
* @internal
*/
class ClassReader
{
/**
* Read class method signature
*
* @param string $className
* @param string $method
* @return array|null
* @throws \ReflectionException
*/
public function getParameters($className, $method)
{
$class = new \ReflectionClass($className);
$result = null;
$method = $class->getMethod($method);
if ($method) {
$result = [];
/** @var $parameter \ReflectionParameter */
foreach ($method->getParameters() as $parameter) {
try {
$result[$parameter->getName()] = [
'type' => $parameter->getType() === null ? null : $parameter->getType()->getName(),
'variableName' => $parameter->getName(),
'isOptional' => $parameter->isOptional(),
'optionalValue' => $parameter->isOptional() ?
$parameter->isDefaultValueAvailable() ? $parameter->getDefaultValue() : null :
null
];
} catch (\ReflectionException $e) {
$message = $e->getMessage();
throw new \ReflectionException($message, 0, $e);
}
}
}
return $result;
}
}
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\FunctionalTestingFramework\System\Code;
/**
* Class ClassReader
*
* @internal
*/
class ClassReader
{
/**
* Read class method signature
*
* @param string $className
* @param string $method
* @return array|null
* @throws \ReflectionException
*/
public function getParameters($className, $method)
{
$class = new \ReflectionClass($className);
$result = null;
$method = $class->getMethod($method);
if ($method) {
$result = [];
/** @var $parameter \ReflectionParameter */
foreach ($method->getParameters() as $parameter) {
try {
$result[$parameter->getName()] = [
$parameter->getName(),
($parameter->getClass() !== null) ? $parameter->getClass()->getName() : null,
!$parameter->isOptional(),
$parameter->isOptional() ?
$parameter->isDefaultValueAvailable() ? $parameter->getDefaultValue() : null :
null
];
} catch (\ReflectionException $e) {
$message = $e->getMessage();
throw new \ReflectionException($message, 0, $e);
}
}
}
return $result;
}
}
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Cache
* @subpackage Zend_Cache_Backend
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id$
*/
/**
* @package Zend_Cache
* @subpackage Zend_Cache_Backend
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Cache_Backend
{
/**
* Frontend or Core directives
*
* =====> (int) lifetime :
* - Cache lifetime (in seconds)
* - If null, the cache is valid forever
*
* =====> (int) logging :
* - if set to true, a logging is activated throw Zend_Log
*
* @var array directives
*/
protected $_directives = array(
'lifetime' => 3600,
'logging' => false,
'logger' => null
);
/**
* Available options
*
* @var array available options
*/
protected $_options = array();
/**
* Constructor
*
* @param array $options Associative array of options
*/
public function __construct(array $options = array())
{
foreach ($options as $name => $value) {
$this->setOption($name, $value);
}
}
/**
* Set the frontend directives
*
* @param array $directives Assoc of directives
* @throws Zend_Cache_Exception
* @return void
*/
public function setDirectives($directives)
{
if (!is_array($directives)) Zend_Cache::throwException('Directives parameter must be an array');
foreach ($directives as $name => $value) {
if (!is_string($name)) {
Zend_Cache::throwException("Incorrect option name : $name");
}
$name = strtolower($name);
if (array_key_exists($name, $this->_directives)) {
$this->_directives[$name] = $value;
}
}
$this->_loggerSanity();
}
/**
* Set an option
*
* @param string $name
* @param mixed $value
* @throws Zend_Cache_Exception
* @return void
*/
public function setOption($name, $value)
{
if (!is_string($name)) {
Zend_Cache::throwException("Incorrect option name : $name");
}
$name = strtolower($name);
if (array_key_exists($name, $this->_options)) {
$this->_options[$name] = $value;
}
}
/**
* Returns an option
*
* @param string $name Optional, the options name to return
* @throws Zend_Cache_Exceptions
* @return mixed
*/
public function getOption($name)
{
$name = strtolower($name);
if (array_key_exists($name, $this->_options)) {
return $this->_options[$name];
}
if (array_key_exists($name, $this->_directives)) {
return $this->_directives[$name];
}
Zend_Cache::throwException("Incorrect option name : {$name}");
}
/**
* Get the life time
*
* if $specificLifetime is not false, the given specific life time is used
* else, the global lifetime is used
*
* @param int $specificLifetime
* @return int Cache life time
*/
public function getLifetime($specificLifetime)
{
if ($specificLifetime === false) {
return $this->_directives['lifetime'];
}
return $specificLifetime;
}
/**
* Return true if the automatic cleaning is available for the backend
*
* DEPRECATED : use getCapabilities() instead
*
* @deprecated
* @return boolean
*/
public function isAutomaticCleaningAvailable()
{
return true;
}
/**
* Determine system TMP directory and detect if we have read access
*
* inspired from Zend_File_Transfer_Adapter_Abstract
*
* @return string
* @throws Zend_Cache_Exception if unable to determine directory
*/
public function getTmpDir()
{
$tmpdir = array();
foreach (array($_ENV, $_SERVER) as $tab) {
foreach (array('TMPDIR', 'TEMP', 'TMP', 'windir', 'SystemRoot') as $key) {
if (isset($tab[$key]) && is_string($tab[$key])) {
if (($key == 'windir') or ($key == 'SystemRoot')) {
$dir = realpath($tab[$key] . '\\temp');
} else {
$dir = realpath($tab[$key]);
}
if ($this->_isGoodTmpDir($dir)) {
return $dir;
}
}
}
}
$upload = ini_get('upload_tmp_dir');
if ($upload) {
$dir = realpath($upload);
if ($this->_isGoodTmpDir($dir)) {
return $dir;
}
}
if (function_exists('sys_get_temp_dir')) {
$dir = sys_get_temp_dir();
if ($this->_isGoodTmpDir($dir)) {
return $dir;
}
}
// Attemp to detect by creating a temporary file
$tempFile = tempnam(md5(uniqid(rand(), TRUE)), '');
if ($tempFile) {
$dir = realpath(dirname($tempFile));
unlink($tempFile);
if ($this->_isGoodTmpDir($dir)) {
return $dir;
}
}
if ($this->_isGoodTmpDir('/tmp')) {
return '/tmp';
}
if ($this->_isGoodTmpDir('\\temp')) {
return '\\temp';
}
Zend_Cache::throwException('Could not determine temp directory, please specify a cache_dir manually');
}
/**
* Verify if the given temporary directory is readable and writable
*
* @param string $dir temporary directory
* @return boolean true if the directory is ok
*/
protected function _isGoodTmpDir($dir)
{
if (is_readable($dir)) {
if (is_writable($dir)) {
return true;
}
}
return false;
}
/**
* Make sure if we enable logging that the Zend_Log class
* is available.
* Create a default log object if none is set.
*
* @throws Zend_Cache_Exception
* @return void
*/
protected function _loggerSanity()
{
if (!isset($this->_directives['logging']) || !$this->_directives['logging']) {
return;
}
if (isset($this->_directives['logger'])) {
if ($this->_directives['logger'] instanceof Zend_Log) {
return;
}
Zend_Cache::throwException('Logger object is not an instance of Zend_Log class.');
}
// Create a default logger to the standard output stream
#require_once 'Zend/Log.php';
#require_once 'Zend/Log/Writer/Stream.php';
#require_once 'Zend/Log/Filter/Priority.php';
$logger = new Zend_Log(new Zend_Log_Writer_Stream('php://output'));
$logger->addFilter(new Zend_Log_Filter_Priority(Zend_Log::WARN, '<='));
$this->_directives['logger'] = $logger;
}
/**
* Log a message at the WARN (4) priority.
*
* @param string $message
* @param int $priority
* @return void
*/
protected function _log($message, $priority = 4)
{
if (!$this->_directives['logging']) {
return;
}
if (!isset($this->_directives['logger'])) {
Zend_Cache::throwException('Logging is enabled but logger is not set.');
}
$logger = $this->_directives['logger'];
if (!$logger instanceof Zend_Log) {
Zend_Cache::throwException('Logger object is not an instance of Zend_Log class.');
}
$logger->log($message, $priority);
}
}
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Cache
* @subpackage Zend_Cache_Backend
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id$
*/
/**
* @see Zend_Cache_Backend_Interface
*/
#require_once 'Zend/Cache/Backend/ExtendedInterface.php';
/**
* @see Zend_Cache_Backend
*/
#require_once 'Zend/Cache/Backend.php';
/**
* @package Zend_Cache
* @subpackage Zend_Cache_Backend
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Cache_Backend_BlackHole
extends Zend_Cache_Backend
implements Zend_Cache_Backend_ExtendedInterface
{
/**
* Test if a cache is available for the given id and (if yes) return it (false else)
*
* @param string $id cache id
* @param boolean $doNotTestCacheValidity if set to true, the cache validity won't be tested
* @return string|false cached datas
*/
public function load($id, $doNotTestCacheValidity = false)
{
return false;
}
/**
* Test if a cache is available or not (for the given id)
*
* @param string $id cache id
* @return mixed false (a cache is not available) or "last modified" timestamp (int) of the available cache record
*/
public function test($id)
{
return false;
}
/**
* Save some string datas into a cache record
*
* Note : $data is always "string" (serialization is done by the
* core not by the backend)
*
* @param string $data Datas to cache
* @param string $id Cache id
* @param array $tags Array of strings, the cache record will be tagged by each string entry
* @param int $specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime)
* @return boolean true if no problem
*/
public function save($data, $id, $tags = array(), $specificLifetime = false)
{
return true;
}
/**
* Remove a cache record
*
* @param string $id cache id
* @return boolean true if no problem
*/
public function remove($id)
{
return true;
}
/**
* Clean some cache records
*
* Available modes are :
* 'all' (default) => remove all cache entries ($tags is not used)
* 'old' => remove too old cache entries ($tags is not used)
* 'matchingTag' => remove cache entries matching all given tags
* ($tags can be an array of strings or a single string)
* 'notMatchingTag' => remove cache entries not matching one of the given tags
* ($tags can be an array of strings or a single string)
* 'matchingAnyTag' => remove cache entries matching any given tags
* ($tags can be an array of strings or a single string)
*
* @param string $mode clean mode
* @param tags array $tags array of tags
* @return boolean true if no problem
*/
public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array())
{
return true;
}
/**
* Return an array of stored cache ids
*
* @return array array of stored cache ids (string)
*/
public function getIds()
{
return array();
}
/**
* Return an array of stored tags
*
* @return array array of stored tags (string)
*/
public function getTags()
{
return array();
}
/**
* Return an array of stored cache ids which match given tags
*
* In case of multiple tags, a logical AND is made between tags
*
* @param array $tags array of tags
* @return array array of matching cache ids (string)
*/
public function getIdsMatchingTags($tags = array())
{
return array();
}
/**
* Return an array of stored cache ids which don't match given tags
*
* In case of multiple tags, a logical OR is made between tags
*
* @param array $tags array of tags
* @return array array of not matching cache ids (string)
*/
public function getIdsNotMatchingTags($tags = array())
{
return array();
}
/**
* Return an array of stored cache ids which match any given tags
*
* In case of multiple tags, a logical AND is made between tags
*
* @param array $tags array of tags
* @return array array of any matching cache ids (string)
*/
public function getIdsMatchingAnyTags($tags = array())
{
return array();
}
/**
* Return the filling percentage of the backend storage
*
* @return int integer between 0 and 100
* @throws Zend_Cache_Exception
*/
public function getFillingPercentage()
{
return 0;
}
/**
* Return an array of metadatas for the given cache id
*
* The array must include these keys :
* - expire : the expire timestamp
* - tags : a string array of tags
* - mtime : timestamp of last modification time
*
* @param string $id cache id
* @return array array of metadatas (false if the cache id is not found)
*/
public function getMetadatas($id)
{
return false;
}
/**
* Give (if possible) an extra lifetime to the given cache id
*
* @param string $id cache id
* @param int $extraLifetime
* @return boolean true if ok
*/
public function touch($id, $extraLifetime)
{
return false;
}
/**
* Return an associative array of capabilities (booleans) of the backend
*
* The array must include these keys :
* - automatic_cleaning (is automating cleaning necessary)
* - tags (are tags supported)
* - expired_read (is it possible to read expired cache records
* (for doNotTestCacheValidity option for example))
* - priority does the backend deal with priority when saving
* - infinite_lifetime (is infinite lifetime can work with this backend)
* - get_list (is it possible to get the list of cache ids and the complete list of tags)
*
* @return array associative of with capabilities
*/
public function getCapabilities()
{
return array(
'automatic_cleaning' => true,
'tags' => true,
'expired_read' => true,
'priority' => true,
'infinite_lifetime' => true,
'get_list' => true,
);
}
/**
* PUBLIC METHOD FOR UNIT TESTING ONLY !
*
* Force a cache record to expire
*
* @param string $id cache id
*/
public function ___expire($id)
{
}
}
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Cache
* @subpackage Zend_Cache_Backend
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id$
*/
/**
* @see Zend_Cache_Backend_Interface
*/
#require_once 'Zend/Cache/Backend/Interface.php';
/**
* @package Zend_Cache
* @subpackage Zend_Cache_Backend
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
interface Zend_Cache_Backend_ExtendedInterface extends Zend_Cache_Backend_Interface
{
/**
* Return an array of stored cache ids
*
* @return array array of stored cache ids (string)
*/
public function getIds();
/**
* Return an array of stored tags
*
* @return array array of stored tags (string)
*/
public function getTags();
/**
* Return an array of stored cache ids which match given tags
*
* In case of multiple tags, a logical AND is made between tags
*
* @param array $tags array of tags
* @return array array of matching cache ids (string)
*/
public function getIdsMatchingTags($tags = array());
/**
* Return an array of stored cache ids which don't match given tags
*
* In case of multiple tags, a logical OR is made between tags
*
* @param array $tags array of tags
* @return array array of not matching cache ids (string)
*/
public function getIdsNotMatchingTags($tags = array());
/**
* Return an array of stored cache ids which match any given tags
*
* In case of multiple tags, a logical AND is made between tags
*
* @param array $tags array of tags
* @return array array of any matching cache ids (string)
*/
public function getIdsMatchingAnyTags($tags = array());
/**
* Return the filling percentage of the backend storage
*
* @return int integer between 0 and 100
*/
public function getFillingPercentage();
/**
* Return an array of metadatas for the given cache id
*
* The array must include these keys :
* - expire : the expire timestamp
* - tags : a string array of tags
* - mtime : timestamp of last modification time
*
* @param string $id cache id
* @return array array of metadatas (false if the cache id is not found)
*/
public function getMetadatas($id);
/**
* Give (if possible) an extra lifetime to the given cache id
*
* @param string $id cache id
* @param int $extraLifetime
* @return boolean true if ok
*/
public function touch($id, $extraLifetime);
/**
* Return an associative array of capabilities (booleans) of the backend
*
* The array must include these keys :
* - automatic_cleaning (is automating cleaning necessary)
* - tags (are tags supported)
* - expired_read (is it possible to read expired cache records
* (for doNotTestCacheValidity option for example))
* - priority does the backend deal with priority when saving
* - infinite_lifetime (is infinite lifetime can work with this backend)
* - get_list (is it possible to get the list of cache ids and the complete list of tags)
*
* @return array associative of with capabilities
*/
public function getCapabilities();
}
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Cache
* @subpackage Zend_Cache_Backend
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id$
*/
/**
* @package Zend_Cache
* @subpackage Zend_Cache_Backend
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
interface Zend_Cache_Backend_Interface
{
/**
* Set the frontend directives
*
* @param array $directives assoc of directives
*/
public function setDirectives($directives);
/**
* Test if a cache is available for the given id and (if yes) return it (false else)
*
* Note : return value is always "string" (unserialization is done by the core not by the backend)
*
* @param string $id Cache id
* @param boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested
* @return string|false cached datas
*/
public function load($id, $doNotTestCacheValidity = false);
/**
* Test if a cache is available or not (for the given id)
*
* @param string $id cache id
* @return mixed|false (a cache is not available) or "last modified" timestamp (int) of the available cache record
*/
public function test($id);
/**
* Save some string datas into a cache record
*
* Note : $data is always "string" (serialization is done by the
* core not by the backend)
*
* @param string $data Datas to cache
* @param string $id Cache id
* @param array $tags Array of strings, the cache record will be tagged by each string entry
* @param int $specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime)
* @return boolean true if no problem
*/
public function save($data, $id, $tags = array(), $specificLifetime = false);
/**
* Remove a cache record
*
* @param string $id Cache id
* @return boolean True if no problem
*/
public function remove($id);
/**
* Clean some cache records
*
* Available modes are :
* Zend_Cache::CLEANING_MODE_ALL (default) => remove all cache entries ($tags is not used)
* Zend_Cache::CLEANING_MODE_OLD => remove too old cache entries ($tags is not used)
* Zend_Cache::CLEANING_MODE_MATCHING_TAG => remove cache entries matching all given tags
* ($tags can be an array of strings or a single string)
* Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG => remove cache entries not {matching one of the given tags}
* ($tags can be an array of strings or a single string)
* Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG => remove cache entries matching any given tags
* ($tags can be an array of strings or a single string)
*
* @param string $mode Clean mode
* @param array $tags Array of tags
* @return boolean true if no problem
*/
public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array());
}
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Cache
* @subpackage Zend_Cache_Backend
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id$
*/
/**
* @see Zend_Cache_Backend_Interface
*/
#require_once 'Zend/Cache/Backend/Interface.php';
/**
* @see Zend_Cache_Backend
*/
#require_once 'Zend/Cache/Backend.php';
/**
* @package Zend_Cache
* @subpackage Zend_Cache_Backend
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Cache_Backend_Xcache extends Zend_Cache_Backend implements Zend_Cache_Backend_Interface
{
/**
* Log message
*/
const TAGS_UNSUPPORTED_BY_CLEAN_OF_XCACHE_BACKEND = 'Zend_Cache_Backend_Xcache::clean() : tags are unsupported by the Xcache backend';
const TAGS_UNSUPPORTED_BY_SAVE_OF_XCACHE_BACKEND = 'Zend_Cache_Backend_Xcache::save() : tags are unsupported by the Xcache backend';
/**
* Available options
*
* =====> (string) user :
* xcache.admin.user (necessary for the clean() method)
*
* =====> (string) password :
* xcache.admin.pass (clear, not MD5) (necessary for the clean() method)
*
* @var array available options
*/
protected $_options = array(
'user' => null,
'password' => null
);
/**
* Constructor
*
* @param array $options associative array of options
* @throws Zend_Cache_Exception
* @return void
*/
public function __construct(array $options = array())
{
if (!extension_loaded('xcache')) {
Zend_Cache::throwException('The xcache extension must be loaded for using this backend !');
}
parent::__construct($options);
}
/**
* Test if a cache is available for the given id and (if yes) return it (false else)
*
* WARNING $doNotTestCacheValidity=true is unsupported by the Xcache backend
*
* @param string $id cache id
* @param boolean $doNotTestCacheValidity if set to true, the cache validity won't be tested
* @return string cached datas (or false)
*/
public function load($id, $doNotTestCacheValidity = false)
{
if ($doNotTestCacheValidity) {
$this->_log("Zend_Cache_Backend_Xcache::load() : \$doNotTestCacheValidity=true is unsupported by the Xcache backend");
}
$tmp = xcache_get($id);
if (is_array($tmp)) {
return $tmp[0];
}
return false;
}
/**
* Test if a cache is available or not (for the given id)
*
* @param string $id cache id
* @return mixed false (a cache is not available) or "last modified" timestamp (int) of the available cache record
*/
public function test($id)
{
if (xcache_isset($id)) {
$tmp = xcache_get($id);
if (is_array($tmp)) {
return $tmp[1];
}
}
return false;
}
/**
* Save some string datas into a cache record
*
* Note : $data is always "string" (serialization is done by the
* core not by the backend)
*
* @param string $data datas to cache
* @param string $id cache id
* @param array $tags array of strings, the cache record will be tagged by each string entry
* @param int $specificLifetime if != false, set a specific lifetime for this cache record (null => infinite lifetime)
* @return boolean true if no problem
*/
public function save($data, $id, $tags = array(), $specificLifetime = false)
{
$lifetime = $this->getLifetime($specificLifetime);
$result = xcache_set($id, array($data, time()), $lifetime);
if (count($tags) > 0) {
$this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_XCACHE_BACKEND);
}
return $result;
}
/**
* Remove a cache record
*
* @param string $id cache id
* @return boolean true if no problem
*/
public function remove($id)
{
return xcache_unset($id);
}
/**
* Clean some cache records
*
* Available modes are :
* 'all' (default) => remove all cache entries ($tags is not used)
* 'old' => unsupported
* 'matchingTag' => unsupported
* 'notMatchingTag' => unsupported
* 'matchingAnyTag' => unsupported
*
* @param string $mode clean mode
* @param array $tags array of tags
* @throws Zend_Cache_Exception
* @return boolean true if no problem
*/
public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array())
{
switch ($mode) {
case Zend_Cache::CLEANING_MODE_ALL:
// Necessary because xcache_clear_cache() need basic authentification
$backup = array();
if (isset($_SERVER['PHP_AUTH_USER'])) {
$backup['PHP_AUTH_USER'] = $_SERVER['PHP_AUTH_USER'];
}
if (isset($_SERVER['PHP_AUTH_PW'])) {
$backup['PHP_AUTH_PW'] = $_SERVER['PHP_AUTH_PW'];
}
if ($this->_options['user']) {
$_SERVER['PHP_AUTH_USER'] = $this->_options['user'];
}
if ($this->_options['password']) {
$_SERVER['PHP_AUTH_PW'] = $this->_options['password'];
}
$cnt = xcache_count(XC_TYPE_VAR);
for ($i=0; $i < $cnt; $i++) {
xcache_clear_cache(XC_TYPE_VAR, $i);
}
if (isset($backup['PHP_AUTH_USER'])) {
$_SERVER['PHP_AUTH_USER'] = $backup['PHP_AUTH_USER'];
$_SERVER['PHP_AUTH_PW'] = $backup['PHP_AUTH_PW'];
}
return true;
break;
case Zend_Cache::CLEANING_MODE_OLD:
$this->_log("Zend_Cache_Backend_Xcache::clean() : CLEANING_MODE_OLD is unsupported by the Xcache backend");
break;
case Zend_Cache::CLEANING_MODE_MATCHING_TAG:
case Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG:
case Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG:
$this->_log(self::TAGS_UNSUPPORTED_BY_CLEAN_OF_XCACHE_BACKEND);
break;
default:
Zend_Cache::throwException('Invalid mode for clean() method');
break;
}
}
/**
* Return true if the automatic cleaning is available for the backend
*
* @return boolean
*/
public function isAutomaticCleaningAvailable()
{
return false;
}
}
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Cache
* @subpackage Zend_Cache_Backend
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id$
*/
/** @see Zend_Cache_Backend_Interface */
#require_once 'Zend/Cache/Backend/Interface.php';
/** @see Zend_Cache_Backend */
#require_once 'Zend/Cache/Backend.php';
/**
* @package Zend_Cache
* @subpackage Zend_Cache_Backend
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
abstract class Zend_Cache_Backend_ZendServer extends Zend_Cache_Backend implements Zend_Cache_Backend_Interface
{
/**
* Available options
*
* =====> (string) namespace :
* Namespace to be used for chaching operations
*
* @var array available options
*/
protected $_options = array(
'namespace' => 'zendframework'
);
/**
* Store data
*
* @param mixed $data Object to store
* @param string $id Cache id
* @param int $timeToLive Time to live in seconds
* @throws Zend_Cache_Exception
*/
abstract protected function _store($data, $id, $timeToLive);
/**
* Fetch data
*
* @param string $id Cache id
* @throws Zend_Cache_Exception
*/
abstract protected function _fetch($id);
/**
* Unset data
*
* @param string $id Cache id
*/
abstract protected function _unset($id);
/**
* Clear cache
*/
abstract protected function _clear();
/**
* Test if a cache is available for the given id and (if yes) return it (false else)
*
* @param string $id cache id
* @param boolean $doNotTestCacheValidity if set to true, the cache validity won't be tested
* @return string cached datas (or false)
*/
public function load($id, $doNotTestCacheValidity = false)
{
$tmp = $this->_fetch($id);
if ($tmp !== null) {
return $tmp;
}
return false;
}
/**
* Test if a cache is available or not (for the given id)
*
* @param string $id cache id
* @return mixed false (a cache is not available) or "last modified" timestamp (int) of the available cache record
* @throws Zend_Cache_Exception
*/
public function test($id)
{
$tmp = $this->_fetch('internal-metadatas---' . $id);
if ($tmp !== false) {
if (!is_array($tmp) || !isset($tmp['mtime'])) {
Zend_Cache::throwException('Cache metadata for \'' . $id . '\' id is corrupted' );
}
return $tmp['mtime'];
}
return false;
}
/**
* Compute & return the expire time
*
* @return int expire time (unix timestamp)
*/
private function _expireTime($lifetime)
{
if ($lifetime === null) {
return 9999999999;
}
return time() + $lifetime;
}
/**
* Save some string datas into a cache record
*
* Note : $data is always "string" (serialization is done by the
* core not by the backend)
*
* @param string $data datas to cache
* @param string $id cache id
* @param array $tags array of strings, the cache record will be tagged by each string entry
* @param int $specificLifetime if != false, set a specific lifetime for this cache record (null => infinite lifetime)
* @return boolean true if no problem
*/
public function save($data, $id, $tags = array(), $specificLifetime = false)
{
$lifetime = $this->getLifetime($specificLifetime);
$metadatas = array(
'mtime' => time(),
'expire' => $this->_expireTime($lifetime),
);
if (count($tags) > 0) {
$this->_log('Zend_Cache_Backend_ZendServer::save() : tags are unsupported by the ZendServer backends');
}
return $this->_store($data, $id, $lifetime) &&
$this->_store($metadatas, 'internal-metadatas---' . $id, $lifetime);
}
/**
* Remove a cache record
*
* @param string $id cache id
* @return boolean true if no problem
*/
public function remove($id)
{
$result1 = $this->_unset($id);
$result2 = $this->_unset('internal-metadatas---' . $id);
return $result1 && $result2;
}
/**
* Clean some cache records
*
* Available modes are :
* 'all' (default) => remove all cache entries ($tags is not used)
* 'old' => unsupported
* 'matchingTag' => unsupported
* 'notMatchingTag' => unsupported
* 'matchingAnyTag' => unsupported
*
* @param string $mode clean mode
* @param array $tags array of tags
* @throws Zend_Cache_Exception
* @return boolean true if no problem
*/
public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array())
{
switch ($mode) {
case Zend_Cache::CLEANING_MODE_ALL:
$this->_clear();
return true;
break;
case Zend_Cache::CLEANING_MODE_OLD:
$this->_log("Zend_Cache_Backend_ZendServer::clean() : CLEANING_MODE_OLD is unsupported by the Zend Server backends.");
break;
case Zend_Cache::CLEANING_MODE_MATCHING_TAG:
case Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG:
case Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG:
$this->_clear();
$this->_log('Zend_Cache_Backend_ZendServer::clean() : tags are unsupported by the Zend Server backends.');
break;
default:
Zend_Cache::throwException('Invalid mode for clean() method');
break;
}
}
}
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Cache
* @subpackage Zend_Cache_Backend
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id$
*/
/** @see Zend_Cache_Backend_Interface */
#require_once 'Zend/Cache/Backend/Interface.php';
/** @see Zend_Cache_Backend_ZendServer */
#require_once 'Zend/Cache/Backend/ZendServer.php';
/**
* @package Zend_Cache
* @subpackage Zend_Cache_Backend
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Cache_Backend_ZendServer_Disk extends Zend_Cache_Backend_ZendServer implements Zend_Cache_Backend_Interface
{
/**
* Constructor
*
* @param array $options associative array of options
* @throws Zend_Cache_Exception
*/
public function __construct(array $options = array())
{
if (!function_exists('zend_disk_cache_store')) {
Zend_Cache::throwException('Zend_Cache_ZendServer_Disk backend has to be used within Zend Server environment.');
}
parent::__construct($options);
}
/**
* Store data
*
* @param mixed $data Object to store
* @param string $id Cache id
* @param int $timeToLive Time to live in seconds
* @return boolean true if no problem
*/
protected function _store($data, $id, $timeToLive)
{
if (zend_disk_cache_store($this->_options['namespace'] . '::' . $id,
$data,
$timeToLive) === false) {
$this->_log('Store operation failed.');
return false;
}
return true;
}
/**
* Fetch data
*
* @param string $id Cache id
* @return mixed|null
*/
protected function _fetch($id)
{
return zend_disk_cache_fetch($this->_options['namespace'] . '::' . $id);
}
/**
* Unset data
*
* @param string $id Cache id
* @return boolean true if no problem
*/
protected function _unset($id)
{
return zend_disk_cache_delete($this->_options['namespace'] . '::' . $id);
}
/**
* Clear cache
*/
protected function _clear()
{
zend_disk_cache_clear($this->_options['namespace']);
}
}
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Cache
* @subpackage Zend_Cache_Backend
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id$
*/
/** @see Zend_Cache_Backend_Interface */
#require_once 'Zend/Cache/Backend/Interface.php';
/** @see Zend_Cache_Backend_ZendServer */
#require_once 'Zend/Cache/Backend/ZendServer.php';
/**
* @package Zend_Cache
* @subpackage Zend_Cache_Backend
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Cache_Backend_ZendServer_ShMem extends Zend_Cache_Backend_ZendServer implements Zend_Cache_Backend_Interface
{
/**
* Constructor
*
* @param array $options associative array of options
* @throws Zend_Cache_Exception
*/
public function __construct(array $options = array())
{
if (!function_exists('zend_shm_cache_store')) {
Zend_Cache::throwException('Zend_Cache_ZendServer_ShMem backend has to be used within Zend Server environment.');
}
parent::__construct($options);
}
/**
* Store data
*
* @param mixed $data Object to store
* @param string $id Cache id
* @param int $timeToLive Time to live in seconds
* @return bool
*/
protected function _store($data, $id, $timeToLive)
{
if (zend_shm_cache_store($this->_options['namespace'] . '::' . $id,
$data,
$timeToLive) === false) {
$this->_log('Store operation failed.');
return false;
}
return true;
}
/**
* Fetch data
*
* @param string $id Cache id
* @return mixed|null
*/
protected function _fetch($id)
{
return zend_shm_cache_fetch($this->_options['namespace'] . '::' . $id);
}
/**
* Unset data
*
* @param string $id Cache id
* @return boolean true if no problem
*/
protected function _unset($id)
{
return zend_shm_cache_delete($this->_options['namespace'] . '::' . $id);
}
/**
* Clear cache
*/
protected function _clear()
{
zend_shm_cache_clear($this->_options['namespace']);
}
}
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Cache
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id$
*/
/**
* @see Zend_Exception
*/
#require_once 'Zend/Exception.php';
/**
* @package Zend_Cache
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Cache_Exception extends Zend_Exception {}
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Cache
* @subpackage Zend_Cache_Frontend
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id$
*/
/**
* @see Zend_Cache_Core
*/
#require_once 'Zend/Cache/Core.php';
/**
* @package Zend_Cache
* @subpackage Zend_Cache_Frontend
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Cache_Frontend_Capture extends Zend_Cache_Core
{
/**
* Page identifiers
* @var array
*/
protected $_idStack = array();
/**
* Tags
* @var array
*/
protected $_tags = array();
protected $_extension = null;
/**
* Start the cache
*
* @param string $id Cache id
* @return mixed True if the cache is hit (false else) with $echoData=true (default) ; string else (datas)
*/
public function start($id, array $tags, $extension = null)
{
$this->_tags = $tags;
$this->_extension = $extension;
ob_start(array($this, '_flush'));
ob_implicit_flush(false);
$this->_idStack[] = $id;
return false;
}
/**
* callback for output buffering
* (shouldn't really be called manually)
*
* @param string $data Buffered output
* @return string Data to send to browser
*/
public function _flush($data)
{
$id = array_pop($this->_idStack);
if ($id === null) {
Zend_Cache::throwException('use of _flush() without a start()');
}
if ($this->_extension) {
$this->save(serialize(array($data, $this->_extension)), $id, $this->_tags);
} else {
$this->save($data, $id, $this->_tags);
}
return $data;
}
}
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Cache
* @subpackage Zend_Cache_Frontend
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id$
*/
/**
* @see Zend_Cache_Core
*/
#require_once 'Zend/Cache/Core.php';
/**
* @package Zend_Cache
* @subpackage Zend_Cache_Frontend
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Cache_Frontend_Class extends Zend_Cache_Core
{
/**
* Available options
*
* ====> (mixed) cached_entity :
* - if set to a class name, we will cache an abstract class and will use only static calls
* - if set to an object, we will cache this object methods
*
* ====> (boolean) cache_by_default :
* - if true, method calls will be cached by default
*
* ====> (array) cached_methods :
* - an array of method names which will be cached (even if cache_by_default = false)
*
* ====> (array) non_cached_methods :
* - an array of method names which won't be cached (even if cache_by_default = true)
*
* @var array available options
*/
protected $_specificOptions = array(
'cached_entity' => null,
'cache_by_default' => true,
'cached_methods' => array(),
'non_cached_methods' => array()
);
/**
* Tags array
*
* @var array
*/
protected $_tags = array();
/**
* SpecificLifetime value
*
* false => no specific life time
*
* @var bool|int
*/
protected $_specificLifetime = false;
/**
* The cached object or the name of the cached abstract class
*
* @var mixed
*/
protected $_cachedEntity = null;
/**
* The class name of the cached object or cached abstract class
*
* Used to differentiate between different classes with the same method calls.
*
* @var string
*/
protected $_cachedEntityLabel = '';
/**
* Priority (used by some particular backends)
*
* @var int
*/
protected $_priority = 8;
/**
* Constructor
*
* @param array $options Associative array of options
* @throws Zend_Cache_Exception
*/
public function __construct(array $options = array())
{
foreach ($options as $name => $value) {
$this->setOption($name, $value);
}
if ($this->_specificOptions['cached_entity'] === null) {
Zend_Cache::throwException('cached_entity must be set !');
}
$this->setCachedEntity($this->_specificOptions['cached_entity']);
$this->setOption('automatic_serialization', true);
}
/**
* Set a specific life time
*
* @param bool|int $specificLifetime
* @return void
*/
public function setSpecificLifetime($specificLifetime = false)
{
$this->_specificLifetime = $specificLifetime;
}
/**
* Set the priority (used by some particular backends)
*
* @param int $priority integer between 0 (very low priority) and 10 (maximum priority)
*/
public function setPriority($priority)
{
$this->_priority = $priority;
}
/**
* Public frontend to set an option
*
* Just a wrapper to get a specific behaviour for cached_entity
*
* @param string $name Name of the option
* @param mixed $value Value of the option
* @throws Zend_Cache_Exception
* @return void
*/
public function setOption($name, $value)
{
if ($name == 'cached_entity') {
$this->setCachedEntity($value);
} else {
parent::setOption($name, $value);
}
}
/**
* Specific method to set the cachedEntity
*
* if set to a class name, we will cache an abstract class and will use only static calls
* if set to an object, we will cache this object methods
*
* @param mixed $cachedEntity
*/
public function setCachedEntity($cachedEntity)
{
if (!is_string($cachedEntity) && !is_object($cachedEntity)) {
Zend_Cache::throwException(
'cached_entity must be an object or a class name'
);
}
$this->_cachedEntity = $cachedEntity;
$this->_specificOptions['cached_entity'] = $cachedEntity;
if (is_string($this->_cachedEntity)) {
$this->_cachedEntityLabel = $this->_cachedEntity;
} else {
$ro = new ReflectionObject($this->_cachedEntity);
$this->_cachedEntityLabel = $ro->getName();
}
}
/**
* Set the cache array
*
* @param array $tags
* @return void
*/
public function setTagsArray($tags = array())
{
$this->_tags = $tags;
}
/**
* Main method : call the specified method or get the result from cache
*
* @param string $name Method name
* @param array $parameters Method parameters
* @return mixed Result
* @throws Exception
*/
public function __call($name, $parameters)
{
$callback = array($this->_cachedEntity, $name);
if (!is_callable($callback, false)) {
Zend_Cache::throwException('Invalid callback');
}
$cacheBool1 = $this->_specificOptions['cache_by_default'];
$cacheBool2 = in_array($name, $this->_specificOptions['cached_methods']);
$cacheBool3 = in_array($name, $this->_specificOptions['non_cached_methods']);
$cache = (($cacheBool1 || $cacheBool2) && (!$cacheBool3));
if (!$cache) {
// We do not have not cache
return call_user_func_array($callback, $parameters);
}
$id = $this->makeId($name, $parameters);
if (($rs = $this->load($id)) && (array_key_exists(0, $rs))
&& (array_key_exists(1, $rs))
) {
// A cache is available
$output = $rs[0];
$return = $rs[1];
} else {
// A cache is not available (or not valid for this frontend)
ob_start();
ob_implicit_flush(false);
try {
$return = call_user_func_array($callback, $parameters);
$output = ob_get_clean();
$data = array($output, $return);
$this->save(
$data, $id, $this->_tags, $this->_specificLifetime,
$this->_priority
);
} catch (Exception $e) {
ob_end_clean();
throw $e;
}
}
echo $output;
return $return;
}
/**
* ZF-9970
*
* @deprecated
*/
private function _makeId($name, $args)
{
return $this->makeId($name, $args);
}
/**
* Make a cache id from the method name and parameters
*
* @param string $name Method name
* @param array $args Method parameters
* @return string Cache id
*/
public function makeId($name, array $args = array())
{
return md5($this->_cachedEntityLabel . '__' . $name . '__' . serialize($args));
}
}
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Cache
* @subpackage Zend_Cache_Frontend
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id$
*/
/**
* @see Zend_Cache_Core
*/
#require_once 'Zend/Cache/Core.php';
/**
* @package Zend_Cache
* @subpackage Zend_Cache_Frontend
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Cache_Frontend_File extends Zend_Cache_Core
{
/**
* Consts for master_files_mode
*/
const MODE_AND = 'AND';
const MODE_OR = 'OR';
/**
* Available options
*
* ====> (string) master_file :
* - a complete path of the master file
* - deprecated (see master_files)
*
* ====> (array) master_files :
* - an array of complete path of master files
* - this option has to be set !
*
* ====> (string) master_files_mode :
* - Zend_Cache_Frontend_File::MODE_AND or Zend_Cache_Frontend_File::MODE_OR
* - if MODE_AND, then all master files have to be touched to get a cache invalidation
* - if MODE_OR (default), then a single touched master file is enough to get a cache invalidation
*
* ====> (boolean) ignore_missing_master_files
* - if set to true, missing master files are ignored silently
* - if set to false (default), an exception is thrown if there is a missing master file
* @var array available options
*/
protected $_specificOptions = array(
'master_file' => null,
'master_files' => null,
'master_files_mode' => 'OR',
'ignore_missing_master_files' => false
);
/**
* Master file mtimes
*
* Array of int
*
* @var array
*/
private $_masterFile_mtimes = null;
/**
* Constructor
*
* @param array $options Associative array of options
* @throws Zend_Cache_Exception
* @return void
*/
public function __construct(array $options = array())
{
foreach ($options as $name => $value) {
$this->setOption($name, $value);
}
if (!isset($this->_specificOptions['master_files'])) {
Zend_Cache::throwException('master_files option must be set');
}
}
/**
* Change the master_files option
*
* @param array $masterFiles the complete paths and name of the master files
*/
public function setMasterFiles(array $masterFiles)
{
$this->_specificOptions['master_file'] = null; // to keep a compatibility
$this->_specificOptions['master_files'] = null;
$this->_masterFile_mtimes = array();
clearstatcache();
$i = 0;
foreach ($masterFiles as $masterFile) {
if (file_exists($masterFile)) {
$mtime = filemtime($masterFile);
} else {
$mtime = false;
}
if (!$this->_specificOptions['ignore_missing_master_files'] && !$mtime) {
Zend_Cache::throwException('Unable to read master_file : ' . $masterFile);
}
$this->_masterFile_mtimes[$i] = $mtime;
$this->_specificOptions['master_files'][$i] = $masterFile;
if ($i === 0) { // to keep a compatibility
$this->_specificOptions['master_file'] = $masterFile;
}
$i++;
}
}
/**
* Change the master_file option
*
* To keep the compatibility
*
* @deprecated
* @param string $masterFile the complete path and name of the master file
*/
public function setMasterFile($masterFile)
{
$this->setMasterFiles(array($masterFile));
}
/**
* Public frontend to set an option
*
* Just a wrapper to get a specific behaviour for master_file
*
* @param string $name Name of the option
* @param mixed $value Value of the option
* @throws Zend_Cache_Exception
* @return void
*/
public function setOption($name, $value)
{
if ($name == 'master_file') {
$this->setMasterFile($value);
} else if ($name == 'master_files') {
$this->setMasterFiles($value);
} else {
parent::setOption($name, $value);
}
}
/**
* Test if a cache is available for the given id and (if yes) return it (false else)
*
* @param string $id Cache id
* @param boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested
* @param boolean $doNotUnserialize Do not serialize (even if automatic_serialization is true) => for internal use
* @return mixed|false Cached datas
*/
public function load($id, $doNotTestCacheValidity = false, $doNotUnserialize = false)
{
if (!$doNotTestCacheValidity) {
if ($this->test($id)) {
return parent::load($id, true, $doNotUnserialize);
}
return false;
}
return parent::load($id, true, $doNotUnserialize);
}
/**
* Test if a cache is available for the given id
*
* @param string $id Cache id
* @return int|false Last modified time of cache entry if it is available, false otherwise
*/
public function test($id)
{
$lastModified = parent::test($id);
if ($lastModified) {
if ($this->_specificOptions['master_files_mode'] == self::MODE_AND) {
// MODE_AND
foreach($this->_masterFile_mtimes as $masterFileMTime) {
if ($masterFileMTime) {
if ($lastModified > $masterFileMTime) {
return $lastModified;
}
}
}
} else {
// MODE_OR
$res = true;
foreach($this->_masterFile_mtimes as $masterFileMTime) {
if ($masterFileMTime) {
if ($lastModified <= $masterFileMTime) {
return false;
}
}
}
return $lastModified;
}
}
return false;
}
}
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Cache
* @subpackage Zend_Cache_Frontend
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id$
*/
/**
* @see Zend_Cache_Core
*/
#require_once 'Zend/Cache/Core.php';
/**
* @package Zend_Cache
* @subpackage Zend_Cache_Frontend
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Cache_Frontend_Function extends Zend_Cache_Core
{
/**
* This frontend specific options
*
* ====> (boolean) cache_by_default :
* - if true, function calls will be cached by default
*
* ====> (array) cached_functions :
* - an array of function names which will be cached (even if cache_by_default = false)
*
* ====> (array) non_cached_functions :
* - an array of function names which won't be cached (even if cache_by_default = true)
*
* @var array options
*/
protected $_specificOptions = array(
'cache_by_default' => true,
'cached_functions' => array(),
'non_cached_functions' => array()
);
/**
* Constructor
*
* @param array $options Associative array of options
* @return void
*/
public function __construct(array $options = array())
{
foreach ($options as $name => $value) {
$this->setOption($name, $value);
}
$this->setOption('automatic_serialization', true);
}
/**
* Main method : call the specified function or get the result from cache
*
* @param callback $callback A valid callback
* @param array $parameters Function parameters
* @param array $tags Cache tags
* @param int $specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime)
* @param int $priority integer between 0 (very low priority) and 10 (maximum priority) used by some particular backends
* @return mixed Result
*/
public function call($callback, array $parameters = array(), $tags = array(), $specificLifetime = false, $priority = 8)
{
if (!is_callable($callback, true, $name)) {
Zend_Cache::throwException('Invalid callback');
}
$cacheBool1 = $this->_specificOptions['cache_by_default'];
$cacheBool2 = in_array($name, $this->_specificOptions['cached_functions']);
$cacheBool3 = in_array($name, $this->_specificOptions['non_cached_functions']);
$cache = (($cacheBool1 || $cacheBool2) && (!$cacheBool3));
if (!$cache) {
// Caching of this callback is disabled
return call_user_func_array($callback, $parameters);
}
$id = $this->_makeId($callback, $parameters);
if ( ($rs = $this->load($id)) && isset($rs[0], $rs[1])) {
// A cache is available
$output = $rs[0];
$return = $rs[1];
} else {
// A cache is not available (or not valid for this frontend)
ob_start();
ob_implicit_flush(false);
$return = call_user_func_array($callback, $parameters);
$output = ob_get_clean();
$data = array($output, $return);
$this->save($data, $id, $tags, $specificLifetime, $priority);
}
echo $output;
return $return;
}
/**
* ZF-9970
*
* @deprecated
*/
private function _makeId($callback, array $args)
{
return $this->makeId($callback, $args);
}
/**
* Make a cache id from the function name and parameters
*
* @param callback $callback A valid callback
* @param array $args Function parameters
* @throws Zend_Cache_Exception
* @return string Cache id
*/
public function makeId($callback, array $args = array())
{
if (!is_callable($callback, true, $name)) {
Zend_Cache::throwException('Invalid callback');
}
// functions, methods and classnames are case-insensitive
$name = strtolower($name);
// generate a unique id for object callbacks
if (is_object($callback)) { // Closures & __invoke
$object = $callback;
} elseif (isset($callback[0])) { // array($object, 'method')
$object = $callback[0];
}
if (isset($object)) {
try {
$tmp = @serialize($callback);
} catch (Exception $e) {
Zend_Cache::throwException($e->getMessage());
}
if (!$tmp) {
$lastErr = error_get_last();
Zend_Cache::throwException("Can't serialize callback object to generate id: {$lastErr['message']}");
}
$name.= '__' . $tmp;
}
// generate a unique id for arguments
$argsStr = '';
if ($args) {
try {
$argsStr = @serialize(array_values($args));
} catch (Exception $e) {
Zend_Cache::throwException($e->getMessage());
}
if (!$argsStr) {
$lastErr = error_get_last();
throw Zend_Cache::throwException("Can't serialize arguments to generate id: {$lastErr['message']}");
}
}
return md5($name . $argsStr);
}
}
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Cache
* @subpackage Zend_Cache_Frontend
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id$
*/
/**
* @see Zend_Cache_Core
*/
#require_once 'Zend/Cache/Core.php';
/**
* @package Zend_Cache
* @subpackage Zend_Cache_Frontend
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Cache_Frontend_Output extends Zend_Cache_Core
{
private $_idStack = array();
/**
* Constructor
*
* @param array $options Associative array of options
* @return void
*/
public function __construct(array $options = array())
{
parent::__construct($options);
$this->_idStack = array();
}
/**
* Start the cache
*
* @param string $id Cache id
* @param boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested
* @param boolean $echoData If set to true, datas are sent to the browser if the cache is hit (simply returned else)
* @return mixed True if the cache is hit (false else) with $echoData=true (default) ; string else (datas)
*/
public function start($id, $doNotTestCacheValidity = false, $echoData = true)
{
$data = $this->load($id, $doNotTestCacheValidity);
if ($data !== false) {
if ( $echoData ) {
echo($data);
return true;
} else {
return $data;
}
}
ob_start();
ob_implicit_flush(false);
$this->_idStack[] = $id;
return false;
}
/**
* Stop the cache
*
* @param array $tags Tags array
* @param int $specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime)
* @param string $forcedDatas If not null, force written datas with this
* @param boolean $echoData If set to true, datas are sent to the browser
* @param int $priority integer between 0 (very low priority) and 10 (maximum priority) used by some particular backends
* @return void
*/
public function end($tags = array(), $specificLifetime = false, $forcedDatas = null, $echoData = true, $priority = 8)
{
if ($forcedDatas === null) {
$data = ob_get_clean();
} else {
$data =& $forcedDatas;
}
$id = array_pop($this->_idStack);
if ($id === null) {
Zend_Cache::throwException('use of end() without a start()');
}
$this->save($data, $id, $tags, $specificLifetime, $priority);
if ($echoData) {
echo($data);
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment