Skip to content

Commit

Permalink
added type guesser
Browse files Browse the repository at this point in the history
  • Loading branch information
loevgaard committed Oct 5, 2018
1 parent afb8b21 commit 71f74cc
Show file tree
Hide file tree
Showing 9 changed files with 203 additions and 1 deletion.
10 changes: 9 additions & 1 deletion DependencyInjection/SetonoCronExpressionExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,23 @@
namespace Setono\CronExpressionBundle\DependencyInjection;

use Setono\CronExpressionBundle\Doctrine\DBAL\Types\CronExpressionType;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\Extension;
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;

final class SetonoCronExpressionExtension extends Extension implements PrependExtensionInterface
{
/**
* {@inheritdoc}
*
* @throws \Exception
*/
public function load(array $config, ContainerBuilder $container): void
{
$loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('services.xml');
}

/**
Expand All @@ -26,7 +32,9 @@ public function load(array $config, ContainerBuilder $container): void
public function prepend(ContainerBuilder $container)
{
if (!$container->hasExtension('doctrine')) {
throw new \Exception('The doctrine extension was not loaded');
@trigger_error('The doctrine extension was not loaded. Install using `composer req doctrine/doctrine-bundle`', E_USER_WARNING);

return;
}

$container->prependExtensionConfig('doctrine', [
Expand Down
71 changes: 71 additions & 0 deletions Form/TypeGuesser/CronExpressionTypeGuesser.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<?php

declare(strict_types=1);

namespace Setono\CronExpressionBundle\Form\TypeGuesser;

use Brick\Reflection\ImportResolver;
use Cron\CronExpression;
use phpDocumentor\Reflection\DocBlock\Tags\Var_;
use Setono\CronExpressionBundle\Form\Type\CronExpressionType;
use Symfony\Component\Form\FormTypeGuesserInterface;
use Symfony\Component\Form\Guess\Guess;
use Symfony\Component\Form\Guess\TypeGuess;

final class CronExpressionTypeGuesser implements FormTypeGuesserInterface
{
public function guessType($class, $property)
{
try {
$reflectionClass = new \ReflectionClass($class);
} catch (\ReflectionException $e) {
return null;
}

$reflectionProperty = $reflectionClass->getProperty($property);

if (false === $reflectionProperty->getDocComment()) {
return null;
}

$factory = \phpDocumentor\Reflection\DocBlockFactory::createInstance();
$docBlock = $factory->create($reflectionProperty->getDocComment());
$varTags = $docBlock->getTagsByName('var');

if (empty($varTags)) {
return null;
}

/** @var Var_ $varTag */
$varTag = $varTags[0];

$typeName = (string) $varTag->getType();

$resolver = new ImportResolver($reflectionClass);

foreach ([$typeName, ltrim($typeName, '\\')] as $item) {
$fqn = $resolver->resolve($item);

if (CronExpression::class === $fqn) {
return new TypeGuess(CronExpressionType::class, [], Guess::VERY_HIGH_CONFIDENCE);
}
}

return null;
}

public function guessRequired($class, $property)
{
return null;
}

public function guessMaxLength($class, $property)
{
return null;
}

public function guessPattern($class, $property)
{
return null;
}
}
11 changes: 11 additions & 0 deletions Resources/config/services.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8" ?>

<container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<defaults public="false" />

<service id="setono_cron_expression.form.type_guesser.cron_expression" class="Setono\CronExpressionBundle\Form\TypeGuesser\CronExpressionTypeGuesser">
<tag name="form.type_guesser" />
</service>
</services>
</container>
28 changes: 28 additions & 0 deletions Tests/DependencyInjection/SetonoCronExpressionExtensionTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

declare(strict_types=1);

namespace Setono\CronExpressionBundle\Tests\DependencyInjection;

use Matthias\SymfonyDependencyInjectionTest\PhpUnit\AbstractExtensionTestCase;
use Setono\CronExpressionBundle\DependencyInjection\SetonoCronExpressionExtension;

final class SetonoCronExpressionExtensionTest extends AbstractExtensionTestCase
{
protected function getContainerExtensions()
{
return [
new SetonoCronExpressionExtension(),
];
}

/**
* @test
*/
public function loadServices(): void
{
$this->load();

$this->assertContainerBuilderHasService('setono_cron_expression.form.type_guesser.cron_expression');
}
}
37 changes: 37 additions & 0 deletions Tests/Form/TypeGuesser/CronExpressionTypeGuesserTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

declare(strict_types=1);

namespace Setono\CronExpressionBundle\Tests\Form\TypeGuesser;

use PHPUnit\Framework\TestCase;
use Setono\CronExpressionBundle\Form\Type\CronExpressionType;
use Setono\CronExpressionBundle\Form\TypeGuesser\CronExpressionTypeGuesser;
use Symfony\Component\Form\Guess\Guess;

final class CronExpressionTypeGuesserTest extends TestCase
{
/**
* @test
*/
public function guessType(): void
{
$guesser = new CronExpressionTypeGuesser();
$res = $guesser->guessType(Stub::class, 'property');

$this->assertSame(CronExpressionType::class, $res->getType());
$this->assertSame(Guess::VERY_HIGH_CONFIDENCE, $res->getConfidence());

$guesser = new CronExpressionTypeGuesser();
$res = $guesser->guessType(StubAliased::class, 'property');

$this->assertSame(CronExpressionType::class, $res->getType());
$this->assertSame(Guess::VERY_HIGH_CONFIDENCE, $res->getConfidence());

$guesser = new CronExpressionTypeGuesser();
$res = $guesser->guessType(StubImported::class, 'property');

$this->assertSame(CronExpressionType::class, $res->getType());
$this->assertSame(Guess::VERY_HIGH_CONFIDENCE, $res->getConfidence());
}
}
13 changes: 13 additions & 0 deletions Tests/Form/TypeGuesser/Stub.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

declare(strict_types=1);

namespace Setono\CronExpressionBundle\Tests\Form\TypeGuesser;

final class Stub
{
/**
* @var \Cron\CronExpression
*/
private $property;
}
15 changes: 15 additions & 0 deletions Tests/Form/TypeGuesser/StubAliased.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

declare(strict_types=1);

namespace Setono\CronExpressionBundle\Tests\Form\TypeGuesser;

use Cron\CronExpression as CronExpr;

final class StubAliased
{
/**
* @var CronExpr
*/
private $property;
}
15 changes: 15 additions & 0 deletions Tests/Form/TypeGuesser/StubImported.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

declare(strict_types=1);

namespace Setono\CronExpressionBundle\Tests\Form\TypeGuesser;

use Cron\CronExpression;

final class StubImported
{
/**
* @var CronExpression
*/
private $property;
}
4 changes: 4 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,17 @@
],
"require": {
"php": "^7.1",
"brick/reflection": "~0.2.1",
"doctrine/doctrine-bundle": "^1.9",
"doctrine/orm": "^2.6",
"dragonmantank/cron-expression": "^2.2",
"phpdocumentor/reflection-docblock": "^4.3",
"symfony/config": "^3.4|^4.1",
"symfony/dependency-injection": "^3.4|^4.1",
"symfony/form": "^3.4|^4.1"
},
"require-dev": {
"matthiasnoback/symfony-dependency-injection-test": "^3.0",
"phpstan/phpstan": "^0.10.3",
"phpunit/phpunit": "^7",
"symplify/easy-coding-standard": "^4.6"
Expand Down

0 comments on commit 71f74cc

Please sign in to comment.