Skip to content

Commit

Permalink
Merge pull request #97 from basz/koseduhemak-master
Browse files Browse the repository at this point in the history
Added New AssetStrategy
  • Loading branch information
svycka authored Nov 20, 2017
2 parents 947a4cf + 1eb1e41 commit 225182b
Show file tree
Hide file tree
Showing 7 changed files with 274 additions and 4 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ Changelog
v0.3.0 - TBD
---
* [#95](https://github.com/basz/SlmLocale/pull/95) Added zend-mvc v3 support and removed zf2 support
* [#97](https://github.com/basz/SlmLocale/pull/97) Added new AssetStrategy to disable localization for assets

v0.2.1
---
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ And enable some strategies. The naming is made via the following list:
* **acceptlanguage**: `SlmLocale\Strategy\HttpAcceptLanguageStrategy`
* **query**: `SlmLocale\Strategy\QueryStrategy`
* **uripath**: `SlmLocale\Strategy\UriPathStrategy`
* **asset**: `SlmLocale\Strategy\AssetStrategy`

You can enable one or more of them in the `strategies` list. Mind the priority
is important! You usually want the `acceptlanguage` as last for a fallback:
Expand Down
32 changes: 32 additions & 0 deletions docs/2.Strategies.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,35 @@ To map TLDs to locales, use the aliases array.
],
],
```

Asset strategy - to prevent URIs of assets being rewritten
---
If you use an Asset Manager (f. e. https://github.com/RWOverdijk/AssetManager) you may face the problem of URIs of your assets getting rewritten to a locale-dependent URI (f. e. `http://example.com/de/css/style.css`). Depending how your webserver is configured, this leads to 404 errors.

To cope with such problems use AssetStrategy:
```
'strategies' => [
[
'name' => SlmLocale\Strategy\AssetStrategy::class,
'options' => [
'file_extensions' => [
'css', 'js'
]
]
],
'query',
[
'name' => \SlmLocale\Strategy\UriPathStrategy::class,
'options' => [
'redirect_when_found' => true,
'aliases' => array('de' => 'de_DE', 'en' => 'en_GB'),
]
],
'cookie',
'acceptlanguage'
],
```

The `file_extensions` array should contain all file endings you use for your assets. URIs of files which have one of the specified extensions will not be rewritten (the example above excludes `css` and `js` files).

**Important:** Make sure to add AssetStrategy first / have AssetStrategy added with highest priority in your config. Otherwise some other strategies may rewrite the URI of an asset.
76 changes: 76 additions & 0 deletions src/SlmLocale/Strategy/AssetStrategy.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<?php

namespace SlmLocale\Strategy;

use SlmLocale\LocaleEvent;

/**
* This class checks whether the requested uri should deliver an asset and should therefore not be redirected.
* If it is an asset, we return false to stop further processing of other strategies in SlmLocale\Locale\Detector.
*
* Example config:
* 'slm_locale' => [
* 'default' => 'de_DE',
* 'supported' => ['en_GB', 'de_DE'],
* 'strategies' => [
* [
* 'name' => SlmLocale\Strategy\AssetStrategy::class,
* 'options' => [
* 'file_extensions' => [
* 'css', 'js'
* ]
* ]
* ],
* 'query',
* 'cookie',
* 'acceptlanguage'
* ],
* 'mappings' => [
* 'en' => 'en_GB',
* 'de' => 'de_DE',
* ]
* ],
*
* This example config would ignore the file_extensions ".css", ".CSS", ".js", ".JS".
*
* Class AssetStrategy
* @package SlmLocale\Strategy
*/
final class AssetStrategy extends AbstractStrategy
{
/** @var array */
private $file_extensions = [];

public function detect(LocaleEvent $event)
{
$this->stopPropagationIfAsset($event);
}

public function found(LocaleEvent $event)
{
$this->stopPropagationIfAsset($event);
}

private function stopPropagationIfAsset(LocaleEvent $event)
{
if (! $this->isHttpRequest($event->getRequest())) {
return;
}

$path = $event->getRequest()->getUri();
$path = parse_url($path, PHP_URL_PATH);
$extension = strtolower(pathinfo($path, PATHINFO_EXTENSION));

// if the file extension of the uri is found within the configured file_extensions, we do not rewrite and skip further processing
if (in_array($extension, $this->file_extensions)) {
$event->stopPropagation();
}
}

public function setOptions(array $options = [])
{
if (array_key_exists('file_extensions', $options)) {
$this->file_extensions = (array) $options['file_extensions'];
}
}
}
2 changes: 2 additions & 0 deletions src/SlmLocale/Strategy/StrategyPluginManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ class StrategyPluginManager extends AbstractPluginManager
'acceptlanguage' => HttpAcceptLanguageStrategy::class,
'query' => QueryStrategy::class,
'uripath' => UriPathStrategy::class,
'asset' => AssetStrategy::class,
];

/**
Expand All @@ -68,5 +69,6 @@ class StrategyPluginManager extends AbstractPluginManager
HttpAcceptLanguageStrategy::class => InvokableFactory::class,
QueryStrategy::class => InvokableFactory::class,
UriPathStrategy::class => UriPathStrategyFactory::class,
AssetStrategy::class => InvokableFactory::class,
];
}
53 changes: 49 additions & 4 deletions tests/SlmLocaleTest/Locale/DetectorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,13 @@

class DetectorTest extends TestCase
{
private $events;

public function setUp()
{
$this->events = new EventManager();
}

public function testDetectEventUsesLocaleEventObject()
{
$detector = new Detector();
Expand Down Expand Up @@ -270,6 +277,46 @@ public function testResponseObjectIsSetInFoundEvent()
$detector->detect(new Request(), $response);
}

public function testResponseObjectIsReturnedIfModified()
{
$detector = new Detector();
$response = new Response();

$this->setEventManager($detector, LocaleEvent::EVENT_FOUND, function ($e) {
$response = $e->getResponse();

// lets pretend we modified response

return $response;
});

$result = $detector->detect(new Request(), $response);
$this->assertInstanceOf(Response::class, $result);
}

public function testResponseObjectCanBeModifiedByMultipleStrategies()
{
$detector = new Detector();
$response = new Response();

$this->setEventManager($detector, LocaleEvent::EVENT_FOUND, function ($e) {
$response = $e->getResponse();
$response->setContent('first');

return $response;
});
$this->events->attach(LocaleEvent::EVENT_FOUND, function ($e) {
$response = $e->getResponse();
$response->setContent($response->getContent() . 'second');

return $response;
});

$result = $detector->detect(new Request(), $response);
$this->assertInstanceOf(Response::class, $result);
$this->assertEquals('firstsecond', $result->getContent());
}

public function testLocaleIsSetInFoundEvent()
{
$detector = new Detector();
Expand All @@ -285,13 +332,11 @@ public function testLocaleIsSetInFoundEvent()

public function setEventManager(Detector $detector, $event = null, $callback = null)
{
$events = new EventManager();

if (null !== $event && null !== $callback) {
$events->attach($event, $callback);
$this->events->attach($event, $callback);
}

$detector->setEventManager($events);
$detector->setEventManager($this->events);

return $detector;
}
Expand Down
113 changes: 113 additions & 0 deletions tests/SlmLocaleTest/Strategy/AssetStrategyTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
<?php

namespace SlmLocaleTest\Strategy;

use PHPUnit_Framework_TestCase as TestCase;
use SlmLocale\Locale\Detector;
use SlmLocale\LocaleEvent;
use SlmLocale\Strategy\AssetStrategy;
use Zend\Console\Request as ConsoleRequest;
use Zend\Console\Response as ConsoleResponse;
use Zend\EventManager\EventManager;
use Zend\Http\PhpEnvironment\Request as HttpRequest;
use Zend\Http\PhpEnvironment\Response as HttpResponse;

class AssetStrategyTest extends TestCase
{
/** @var AssetStrategy */
private $strategy;

/** @var LocaleEvent */
private $event;

public function setup()
{
$this->strategy = new AssetStrategy();
$this->strategy->setOptions(['file_extensions' => ['css', 'js']]);

$this->event = new LocaleEvent();
$this->event->setSupported(['nl', 'de', 'en']);
}

public function testDetectReturnsNullByDefault()
{
$this->event->setRequest(new HttpRequest());
$this->event->setResponse(new HttpResponse());

$locale = $this->strategy->detect($this->event);
$this->assertNull($locale);
}

public function testDetectWithConsoleRequestReturnsNull()
{
$this->event->setRequest(new ConsoleRequest());
$this->event->setResponse(new ConsoleResponse());

$locale = $this->strategy->detect($this->event);
$this->assertNull($locale);
}

/**
* @dataProvider uriProvider
*/
public function testDetectShouldStopPropagationIfFileExtensionWasConfigured($uri, $isAsset)
{
$request = new HttpRequest();
$request->setUri($uri);

$this->event->setRequest($request);

// should stop event propagation if extension was configured to ignore.
$result = $this->strategy->detect($this->event);
$this->assertNull($result);
$this->assertEquals($isAsset, $this->event->propagationIsStopped());
}

/**
* @dataProvider uriProvider
*/
public function testFoundShouldStopPropagationIfFileExtensionWasConfigured($uri, $isAsset)
{
$request = new HttpRequest();
$request->setUri($uri);

$this->event->setRequest($request);

// should stop event propagation if extension was configured to ignore.
$result = $this->strategy->found($this->event);
$this->assertNull($result);
$this->assertEquals($isAsset, $this->event->propagationIsStopped());
}

public function uriProvider()
{
return [
['http://example.com/css/style.css', true],
['http://example.com/css/style.css?ver=123456', true],
['http://example.com/css/script.js', true],
['http://example.com/image/image.jpg', false],
['http://example.com/article/new-asset-strategy', false],
];
}

public function testAssetStrategyCanPreventOtherStrategiesExecution()
{
$request = new HttpRequest();
$request->setUri('http://example.com/css/style.css');
$query = $request->getQuery();
$query->lang = 'de';
$request->setQuery($query);
$this->event->setRequest($request);

$detector = new Detector();
$detector->setEventManager(new EventManager());
$detector->setSupported(['nl', 'de', 'en']);
$detector->setDefault('en');
$detector->addStrategy($this->strategy);
$detector->addStrategy(new \SlmLocale\Strategy\QueryStrategy());
$response = new HttpResponse();

$result = $detector->detect($request, $response);
$this->assertEquals('en', $result);
}
}

0 comments on commit 225182b

Please sign in to comment.