Skip to content

Commit

Permalink
Merge pull request #11 from acsiomatic/factory-as-service
Browse files Browse the repository at this point in the history
Introduce DeviceDetectorFactoryInterface
  • Loading branch information
renedelima authored Mar 18, 2021
2 parents cf456ee + 5700f98 commit ea39b6b
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 12 deletions.
37 changes: 37 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ acsiomatic_device_detector:
## Usage in controllers
You can inject `DeviceDetector` as a service.
This bundle sets up this class according to the configurations under the `acsiomatic_device_detector` section in order to provide information about the current request.

```php
use DeviceDetector\DeviceDetector;
Expand All @@ -67,6 +70,8 @@ Note that you need to call `parse()` to ask for device's information.

## Usage in Twig

The `DeviceDetector` service is assigned to the Twig templates as `device` variable.

```twig
{% do device.parse %}
Expand All @@ -75,6 +80,38 @@ Note that you need to call `parse()` to ask for device's information.
{% endif %}
```

## Parsing custom request

You might want to parse other request than the current one.
This bundle provides a service that implements `DeviceDetectorFactoryInterface`.
This service provides a method that creates fresh `DeviceDetector` instances according to the configurations under the `acsiomatic_device_detector` section, but it doesn't attach them to any request.

```php
use Acsiomatic\DeviceDetectorBundle\Contracts\DeviceDetectorFactoryInterface;
class SmartphoneDeterminer
{
/**
* @var DeviceDetectorFactoryInterface
*/
private $deviceDetectorFactory;
public function __construct(DeviceDetectorFactoryInterface $factory)
{
$this->deviceDetectorFactory = $factory;
}
public function isSmartphone(string $userAgent): bool
{
$deviceDetector = $this->deviceDetectorFactory->createDeviceDetector();
$deviceDetector->setUserAgent($userAgent);
$deviceDetector->parse();
return $deviceDetector->isSmartphone();
}
}
```

[DeviceDetector class]: https://github.com/matomo-org/device-detector/blob/master/DeviceDetector.php
[DeviceDetector]: https://github.com/matomo-org/device-detector
[Symfony]: https://symfony.com/
Expand Down
10 changes: 10 additions & 0 deletions src/Contracts/DeviceDetectorFactoryInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

namespace Acsiomatic\DeviceDetectorBundle\Contracts;

use DeviceDetector\DeviceDetector;

interface DeviceDetectorFactoryInterface
{
public function createDeviceDetector(): DeviceDetector;
}
15 changes: 12 additions & 3 deletions src/DependencyInjection/AcsiomaticDeviceDetectorExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Acsiomatic\DeviceDetectorBundle\DependencyInjection;

use Acsiomatic\DeviceDetectorBundle\Contracts\DeviceDetectorFactoryInterface;
use Acsiomatic\DeviceDetectorBundle\Factory\DeviceDetectorFactory;
use Acsiomatic\DeviceDetectorBundle\Twig\TwigExtension;
use DeviceDetector\DeviceDetector;
Expand All @@ -27,17 +28,25 @@ public function load(array $configs, ContainerBuilder $container)
$config = $this->processConfiguration($configuration, $configs);

$container
->register(DeviceDetector::class, DeviceDetector::class)
->register(DeviceDetectorFactoryInterface::class, DeviceDetectorFactory::class)
->setPublic(false)
->setFactory([DeviceDetectorFactory::class, 'create'])
->setArguments([
new Reference(RequestStack::class),
$config['bot']['skip_detection'],
$config['bot']['discard_information'],
null !== $config['cache']['pool'] ? new Reference($config['cache']['pool']) : null,
])
;

$container
->register(DeviceDetector::class, DeviceDetector::class)
->setPublic(false)
->setFactory([DeviceDetectorFactory::class, 'createDeviceDetectorFromRequestStack'])
->setArguments([
new Reference(DeviceDetectorFactoryInterface::class),
new Reference(RequestStack::class),
])
;

if (null !== $config['twig']['variable_name'] && class_exists(Environment::class)) {
$container
->register(TwigExtension::class, TwigExtension::class)
Expand Down
50 changes: 41 additions & 9 deletions src/Factory/DeviceDetectorFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Acsiomatic\DeviceDetectorBundle\Factory;

use Acsiomatic\DeviceDetectorBundle\Contracts\DeviceDetectorFactoryInterface;
use DeviceDetector\Cache\PSR6Bridge;
use DeviceDetector\DeviceDetector;
use Psr\Cache\CacheItemPoolInterface;
Expand All @@ -10,23 +11,54 @@
/**
* @internal
*/
abstract class DeviceDetectorFactory
final class DeviceDetectorFactory implements DeviceDetectorFactoryInterface
{
public static function create(
RequestStack $stack,
/**
* @var bool
*/
private $skipBotDetection;

/**
* @var bool
*/
private $discardBotInformation;

/**
* @var CacheItemPoolInterface|null
*/
private $cache;

public function __construct(
bool $skipBotDetection,
bool $discardBotInformation,
CacheItemPoolInterface $cache = null
): DeviceDetector {
) {
$this->skipBotDetection = $skipBotDetection;
$this->discardBotInformation = $discardBotInformation;
$this->cache = $cache;
}

public function createDeviceDetector(): DeviceDetector
{
$detector = new DeviceDetector();
$detector->skipBotDetection($skipBotDetection);
$detector->discardBotInformation($discardBotInformation);

if ($cache) {
$detector->setCache(new PSR6Bridge($cache));
$detector->skipBotDetection($this->skipBotDetection);
$detector->discardBotInformation($this->discardBotInformation);

if ($this->cache) {
$detector->setCache(new PSR6Bridge($this->cache));
}

$request = $stack->getMasterRequest();
return $detector;
}

public static function createDeviceDetectorFromRequestStack(
DeviceDetectorFactoryInterface $factory,
RequestStack $requestStack
): DeviceDetector {
$detector = $factory->createDeviceDetector();

$request = $requestStack->getMasterRequest();
if ($request) {
// Third argument is a BC layer for Symfony 4.3 and older
$userAgent = $request->headers->get('user-agent', '', true);
Expand Down
28 changes: 28 additions & 0 deletions tests/ServiceAvailabilityTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Acsiomatic\DeviceDetectorBundle\Tests;

use Acsiomatic\DeviceDetectorBundle\AcsiomaticDeviceDetectorBundle;
use Acsiomatic\DeviceDetectorBundle\Contracts\DeviceDetectorFactoryInterface;
use Acsiomatic\DeviceDetectorBundle\Tests\Util\Compiler\CallbackContainerPass;
use Acsiomatic\DeviceDetectorBundle\Tests\Util\Compiler\CompilerPassFactory;
use Acsiomatic\DeviceDetectorBundle\Tests\Util\HttpKernel\Kernel;
Expand Down Expand Up @@ -52,4 +53,31 @@ public function testDeviceDetectorServiceMustNotBeAutomaticallyParsed()

static::assertFalse($deviceDetector->isParsed());
}

/**
* @return void
*/
public function testDeviceDetectorFactoryService()
{
$kernel = new Kernel('test', true);
$kernel->appendBundle(new FrameworkBundle());
$kernel->appendBundle(new AcsiomaticDeviceDetectorBundle());
$kernel->appendExtensionConfiguration('framework', ['test' => true, 'secret' => '53CR37']);
$kernel->appendCompilerPass(
CompilerPassFactory::createPublicAlias(
'device_detector_factory.public',
DeviceDetectorFactoryInterface::class
)
);

$kernel->boot();

/** @var DeviceDetectorFactoryInterface $deviceDetectorFactory */
$deviceDetectorFactory = $kernel->getContainer()->get('device_detector_factory.public');
$deviceDetector = $deviceDetectorFactory->createDeviceDetector();

static::assertInstanceOf(DeviceDetector::class, $deviceDetector);

$kernel->boot();
}
}

0 comments on commit ea39b6b

Please sign in to comment.