Skip to content

Commit

Permalink
Update to align with Symfony PR
Browse files Browse the repository at this point in the history
  • Loading branch information
andrerom committed Feb 25, 2019
1 parent 2f42296 commit a8b3032
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 137 deletions.
34 changes: 21 additions & 13 deletions README.md
@@ -1,46 +1,54 @@
# ezsystems/symfony-tools
Collection of polyfill (backport) and incubator features for Symfony.
Collection of polyfill (backported) and incubator (proposed) features for Symfony.

Backports Symfony features so they can be used in earlier versions of Symfony, and
aims to serve as incubator for ideas to improve Symfony in the future.
proposed features improving Symfony further.

This bundle is first and foremost aiming to cover needs of [eZ Platform](https://ezplatform.com),
but is placed in own bundle under MIT as we think others can benefit and help collaborate, and
to simplify forward and backport ports to and from Symfony itself.

### Requriments

- Symfony 3.4 _(4.3+ planned spring 2019, 2.8 support might happen if we need it)_
- PHP 7.1+ 3.x branch for Symfony3 _(PHP 5.6+ for 2.x for Symfony2 if we ever add that)_
- Symfony 3.4
- PHP 7.1+ _(due to backported Symfony 4 code being written for PHP 7.1+)_

#### Semantic Versioning exception

Bundle follows [SemVer](https://semver.org/) with one exception:
- Incubator features are allowed to break BC also in Minor versions (x.Y.z), __when__ needed in order to align with changes to the feature when it gets contributed to Symfony.
- Incubator features are allowed to break BC also in Minor versions (x.Y.z), __when__ needed in order to align with
changes to the feature when it gets accepted to Symfony.


!! Tip: As such if you rely on incubator features, make sure to require specific minor versions in composer, like `~1.1.0` or `~1.1.2 || ~1.2.0`
!! Tip: As such if you rely on incubator features, make sure to require specific minor versions in composer, like
`~1.1.0` or `~1.1.2 || ~1.2.0`

### Features

**Polyfill (backport) features:**
- [Redis session handler](doc/RedisSessionHandler.md) _(for Symfony3, native in Symfony4)_

**Incubator features**
-
**Incubator (proposed) features**
- [NativeTagAwareAdapters](doc/NativeTagAwareAdapters.md)


### Contributing

Make sure as much as possible the feature is forward compatible for users, so when they upgrade to Symfony version where it's included, they should ideally not need to adapt their code/config. _(see `Semantic Versioning exception` for how this works for incubators)_
Make sure as much as possible the feature is forward compatible for users, so when they upgrade to Symfony version where
it's included, they should ideally not need to adapt their code/config. _(see `Semantic Versioning exception` for how
this works for incubators)_

**Polyfill (Backports)**
When contributing Symfony backports to this bundle, be aware you commit to help maintain that feature in case there are bug fixes or improvements to that feature in Symfony itself.
When contributing Symfony backports to this bundle, be aware you commit to help maintain that feature in case there are
bug fixes or improvements to that feature in Symfony itself.

**Incubator**
Incubator features should only be proposed here if you intend to contribute this to Symfony itself, and there is at least some certainty it will be accepted. And you also commit to adapt the feature here, if changes are requested once proposed to Symfony. Essentially aiming for the feature here becoming a polyfill/backport feature in the end.
**Incubator (Proposed)**
Incubator features should only be proposed here if also proposed against Symfony itself, and there is at least some
certainty it will be accepted. And you also commit to adapt the feature here, if changes are requested once proposed to
Symfony. Essentially aiming for the feature here becoming a polyfill/backport feature in the end.

As such it's only applicable for smaller features _(e.g. new cache adapter(s))_, not a complete new component or larger changes across Symfony itself for instance.
As such it's only applicable for smaller features _(e.g. new cache adapter(s))_, not a complete new component or larger
changes across Symfony itself for instance.

### License

Expand Down
20 changes: 10 additions & 10 deletions doc/NativeTagAwareAdapters.md
Expand Up @@ -15,23 +15,23 @@ See: https://github.com/symfony/symfony/commits/master/src/Symfony/Component/Cac
## Requirements
- Symfony 3.4, PHP 7.1+
- For usage eZ Platform v2: `ezsystems/ezpublish-kernel` v7.3.5, v7.4.3 or higher.
- For `FilesystemTagAwareAdapter` usage: _No particular needs._
- For `RedisTagAwareAdapter` usage:
- [PHP Redis](https://pecl.php.net/package/redis) extension v3.1.3 or higher, _or_ [Predis](https://packagist.org/packages/predis/predis)
- Redis 3.2 or higher, configured with `noeviction` or any `volatile-*` eviction policy

## Configuration
After installing the bundle, you have to configure proper services in order to use this.
Here is an example on how to do that with eZ Platform:

**Here is an example on how to do that with eZ Platform:**


### File system cache

In `app/config/cache_pool/app.cache.filesystem.yml`, place the following:
In `app/config/cache_pool/app.cache.tagaware.filesystem.yml`, place the following:
```yaml
services:
app.cache.filesystem:
class: EzSystems\SymfonyTools\Incubator\Cache\TagAware\FilesystemTagAwareAdapter
app.cache.tagaware.filesystem:
class: Symfony\Component\Cache\Adapter\TagAware\FilesystemTagAwareAdapter
parent: cache.adapter.filesystem
tags:
- name: cache.pool
Expand All @@ -47,19 +47,19 @@ services:

Once that is done you can enable the handler, for instance by setting the following environment variable for PHP:
```bash
export CACHE_POOL="app.cache.filesystem"
export CACHE_POOL="app.cache.tagaware.filesystem"
```

_Then clear cache and restart web server, you'll be able to verify it's in use on Symfony's web debug toolbar._


### Redis cache

In `app/config/cache_pool/app.cache.redis.yml`, place the following:
In `app/config/cache_pool/app.cache.tagaware.redis.yml`, place the following:
```yaml
services:
app.cache.redis:
class: EzSystems\SymfonyTools\Incubator\Cache\TagAware\RedisTagAwareAdapter
app.cache.tagaware.redis:
class: Symfony\Component\Cache\Adapter\TagAware\RedisTagAwareAdapter
parent: cache.adapter.redis
tags:
- name: cache.pool
Expand All @@ -81,7 +81,7 @@ services:

Once that is done you can enable the handler, for instance by setting the following environment variable for PHP:
```bash
export CACHE_POOL="app.cache.redis"
export CACHE_POOL="app.cache.tagaware.redis"
```
If you don't have redis, for testing you can use:
- Run: `docker run --name my-redis -p 6379:6379 -d redis`.
Expand Down
@@ -1,11 +1,17 @@
<?php

/**
* @copyright Copyright (C) eZ Systems AS. All rights reserved.
* @license For full copyright and license information view LICENSE file distributed with this source code.
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace EzSystems\SymfonyTools\Incubator\Cache\TagAware;
declare(strict_types=1);

namespace Symfony\Component\Cache\Adapter\TagAware;

use Psr\Cache\CacheItemInterface;
use Psr\Log\LoggerAwareInterface;
Expand Down Expand Up @@ -35,7 +41,7 @@ abstract class AbstractTagAwareAdapter implements AdapterInterface, LoggerAwareI
* @var \Symfony\Component\Cache\Marshaller\MarshallerInterface
* NOTE: Not relevant in this way in Symfony 4+ where Abstract trait already uses this
*/
protected $marshaller;
protected static $marshaller;

/**
* @param string $namespace
Expand All @@ -44,9 +50,9 @@ abstract class AbstractTagAwareAdapter implements AdapterInterface, LoggerAwareI
*
* @throws \Symfony\Component\Cache\Exception\CacheException
*/
protected function __construct($namespace = '', $defaultLifetime = 0, MarshallerInterface $marshaller = null)
protected function __construct(string $namespace = '', int $defaultLifetime = 0, MarshallerInterface $marshaller = null)
{
$this->marshaller = $marshaller ?? new DefaultMarshaller();
self::$marshaller = $marshaller ?? new DefaultMarshaller();

$this->namespace = '' === $namespace ? '' : CacheItem::validateKey($namespace) . ':';
if (null !== $this->maxIdLength && \strlen($namespace) > $this->maxIdLength - 24) {
Expand Down Expand Up @@ -261,6 +267,6 @@ private function generateItems($items, &$keys)
*/
protected static function unserialize($value)
{
throw new \Exception('Not in use, use $this->marshaller');
return self::$marshaller->unmarshall($value);
}
}
@@ -1,13 +1,17 @@
<?php

/**
* @copyright Copyright (C) eZ Systems AS. All rights reserved.
* @license For full copyright and license information view LICENSE file distributed with this source code.
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace EzSystems\SymfonyTools\Incubator\Cache\TagAware;
namespace Symfony\Component\Cache\Adapter\TagAware;

use Symfony\Component\Cache\Adapter\TagAwareAdapterInterface;
use Symfony\Component\Cache\Traits\FilesystemTrait;
Expand Down Expand Up @@ -35,7 +39,7 @@ final class FilesystemTagAwareAdapter extends AbstractTagAwareAdapter implements
*/
private $fs;

public function __construct($namespace = '', $defaultLifetime = 0, $directory = null)
public function __construct(string $namespace = '', int $defaultLifetime = 0, string $directory = null)
{
parent::__construct('', $defaultLifetime);
$this->init($namespace, $directory);
Expand All @@ -53,7 +57,7 @@ public function __construct($namespace = '', $defaultLifetime = 0, $directory =
protected function doSave(array $values, $lifetime)
{
$failed = [];
$serialized = $this->marshaller->marshall($values, $failed);
$serialized = self::$marshaller->marshall($values, $failed);
if (empty($serialized)) {
return $failed;
}
Expand Down Expand Up @@ -88,39 +92,6 @@ protected function doSave(array $values, $lifetime)
return $failed;
}

/**
* This method overrides {@see \Symfony\Component\Cache\Traits\FilesystemTrait::doFetch}.
*
* It needs to be overridden due to the usage of `parent::unserialize()` in the original method.
*
* {@inheritdoc}
*/
protected function doFetch(array $ids)
{
$values = [];
$now = time();

foreach ($ids as $id) {
$file = $this->getFile($id);
if (!file_exists($file) || !$h = @fopen($file, 'rb')) {
continue;
}
if (($expiresAt = (int) fgets($h)) && $now >= $expiresAt) {
fclose($h);
@unlink($file);
} else {
$i = rawurldecode(rtrim(fgets($h)));
$value = stream_get_contents($h);
fclose($h);
if ($i === $id) {
$values[$id] = $this->marshaller->unmarshall($value);
}
}
}

return $values;
}

/**
* {@inheritdoc}
*/
Expand All @@ -138,15 +109,15 @@ public function invalidateTags(array $tags)

foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->getTagFolder($tag), \FilesystemIterator::SKIP_DOTS)) as $itemLink) {
if (!$itemLink->isLink()) {
throw new \Exception('Tag link is not a link: ' . $itemLink);
throw new \Exception('Tag link is not a link: '.$itemLink);
}

$valueFile = $itemLink->getRealPath();
if ($valueFile && file_exists($valueFile)) {
@unlink($valueFile);
}

@unlink((string)$itemLink);
@unlink((string) $itemLink);
}
}

Expand All @@ -164,13 +135,13 @@ private function getFile($id, $mkdir = false)
{
// Use MD5 to favor speed over security, which is not an issue here
$hash = str_replace('/', '-', base64_encode(hash('md5', static::class . $id, true)));
$dir = $this->directory.strtoupper($hash[0] . \DIRECTORY_SEPARATOR . $hash[1] . \DIRECTORY_SEPARATOR);
$dir = $this->directory.strtoupper($hash[0].\DIRECTORY_SEPARATOR.$hash[1].\DIRECTORY_SEPARATOR);

if ($mkdir && !file_exists($dir)) {
@mkdir($dir, 0777, true);
}

return $dir . substr($hash, 2, 20);
return $dir.substr($hash, 2, 20);
}

private function getFilesystem(): Filesystem
Expand All @@ -180,22 +151,14 @@ private function getFilesystem(): Filesystem

private function getTagFolder($tag): string
{
return $this->directory . self::TAG_FOLDER . \DIRECTORY_SEPARATOR . str_replace('/', '-', $tag) . \DIRECTORY_SEPARATOR;
return $this->directory.self::TAG_FOLDER.\DIRECTORY_SEPARATOR.str_replace('/', '-', $tag).\DIRECTORY_SEPARATOR;
}

private function getTagIdFile($id): string
{
// Use MD5 to favor speed over security, which is not an issue here
$hash = str_replace('/', '-', base64_encode(hash('md5', static::class . $id, true)));
$hash = str_replace('/', '-', base64_encode(hash('md5', static::class.$id, true)));

return substr($hash, 0, 20);
}

/**
* @internal for unit tests only
*/
public function setFilesystem(Filesystem $fs)
{
$this->fs = $fs;
}
}

0 comments on commit a8b3032

Please sign in to comment.