diff --git a/README.md b/README.md index c181a3b..8031bfa 100644 --- a/README.md +++ b/README.md @@ -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; @@ -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 %} @@ -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/ diff --git a/src/Contracts/DeviceDetectorFactoryInterface.php b/src/Contracts/DeviceDetectorFactoryInterface.php new file mode 100644 index 0000000..b43d479 --- /dev/null +++ b/src/Contracts/DeviceDetectorFactoryInterface.php @@ -0,0 +1,10 @@ +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) diff --git a/src/Factory/DeviceDetectorFactory.php b/src/Factory/DeviceDetectorFactory.php index e7263cc..d31e21b 100644 --- a/src/Factory/DeviceDetectorFactory.php +++ b/src/Factory/DeviceDetectorFactory.php @@ -2,6 +2,7 @@ namespace Acsiomatic\DeviceDetectorBundle\Factory; +use Acsiomatic\DeviceDetectorBundle\Contracts\DeviceDetectorFactoryInterface; use DeviceDetector\Cache\PSR6Bridge; use DeviceDetector\DeviceDetector; use Psr\Cache\CacheItemPoolInterface; @@ -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); diff --git a/tests/ServiceAvailabilityTest.php b/tests/ServiceAvailabilityTest.php index 1ff9611..0eceb16 100644 --- a/tests/ServiceAvailabilityTest.php +++ b/tests/ServiceAvailabilityTest.php @@ -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; @@ -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(); + } }