Behat stopped generating regular expressions for method stubs - symfony

I've started working with Behat for behavioural testing.
I managed to set behat up for my Symfony2 project, started writing scenarios. I was happy with Behat giving me method stubs with regexp to fill in that'd correspond to the steps in my scenarios.
However, after a while, Behat stopped generating regular expressions and is giving me stub methods like this:
/**
* #Given I am on the page :arg1 <-- this is what I get
*/
public function iAmOnThePage($arg1)
{
throw new PendingException();
}
I'd rather have it work like befor, e.g.:
/**
* #Given /^I open "([^"]*)"$/ <--- I'd expect this
*/
public function iOpen($arg1, $sessionName=null)
{
$this->getSession($sessionName)->visit($arg1);
}
I must have messed somtehing up as I went, but have no idea why the default behaviour changes all of a sudden.
Any suggestions?

Did you update your version of Behat ?
In version 3 it's with the :arg and in v2.5 it's with the regex expressions.
If you like the old way of working you can follow the manual .
Implementing the SnippetAcceptingContext interface tells Behat that
your context is expecting snippets to be generated inside it. Behat
will generate simple pattern snippets for you, but if regular
expressions are your thing, Behat can generate them instead if you
implement Behat\Behat\Context\CustomSnippetAcceptingContext interface
instead and add getAcceptedSnippetType() method returning string
"regex":
public static function getAcceptedSnippetType()
{
return 'regex';
}

Related

Differences between different methods of Symfony service collection

For those of you that are familiar with the building of the Symfony container, do you know what is the differences (if any) between
Tagged service Collector using a Compiler pass
Tagged service Collector using the supported shortcut
Service Locator especially, one that collects services by tags
Specifically, I am wondering about whether these methods differ on making these collected services available sooner or later in the container build process. Also I am wondering about the ‘laziness’ of any of them.
It can certainly be confusing when trying to understand the differences. Keep in mind that the latter two approaches are fairly new. The documentation has not quite caught up. You might actually consider making a new project and doing some experimenting.
Approach 1 is basically an "old school" style. You have:
class MyCollector {
private $handlers = [];
public function addHandler(MyHandler $hamdler) {
$handlers[] = $handler;
# compiler pass
$myCollectorDefinition->addMethodCall('addHandler', [new Reference($handlerServiceId)]);
So basically the container will instantiate MyCollector then explicitly call addHandler for each handler service. In doing so, the handler services will be instantiated unless you do some proxy stuff. So no lazy creation.
The second approach provides a somewhat similar capability but uses an iterable object instead of a plain php array:
class MyCollection {
public function __construct(iterable $handlers)
# services.yaml
App\MyCollection:
arguments:
- !tagged_iterator my.handler
One nice thing about this approach is that the iterable actually ends up connecting to the container via closures and will only instantiate individual handlers when they are actually accessed. So lazy handler creation. Also, there are some variations on how you can specify the key.
I might point out that typically you auto-tag your individual handlers with:
# services.yaml
services:
_instanceof:
App\MyHandlerInterface:
tags: ['my.handler']
So no compiler pass needed.
The third approach is basically the same as the second except that handler services can be accessed individually by an index. This is useful when you need one out of all the possible services. And of course the service selected is only created when you ask for it.
class MyCollection {
public function __construct(ServiceLocator $locator) {
$this->locator = $locator;
}
public function doSomething($handlerKey) {
/** #var MyHandlerInterface $handler */
$handler = $serviceLocator->get($handlerKey);
# services.yaml
App\MyCollection:
arguments: [!tagged_locator { tag: 'app.handler', index_by: 'key' }]
I should point out that in all these cases, the code does not actually know the class of your handler service. Hence the var comment to keep the IDE happy.
There is another approach which I like in which you make your own ServiceLocator and then specify the type of object being located. No need for a var comment. Something like:
class MyHandlerLocator extends ServiceLocator
{
public function get($id) : MyHandlerInterface
{
return parent::get($id);
}
}
The only way I have been able to get this approach to work is a compiler pass. I won't post the code here as it is somewhat outside the scope of the question. But in exchange for a few lines of pass code you get a nice clean custom locator which can also pick up handlers from other bundles.

Symfony and Api-Platform: Use Doctrine and other Services outside controllers

Hello Stackoverflow
We have a problem with Symfony and API-PLATFORM. We tried a lot of things, but couldn't find any solution. We had difficulties using the answers already given on stackoverflow and the git issues they have that are related to this question. This is why this is not a duplicate in any form, since those sadly didn't help us.
The problem is as follows. We have the standard structure in our src folder of api-platform.
- src
-- Annotation
-- Controller
-- Doctrine
-- Emails
-- Entity
-- EventListener
-- EventSubscriber
-- Filters
-- Repository
-- Security
-- Utils
So here is were our problem starts. We have a few classes which are just some utilities for easy use. Those are in the utils folder. This question is about a class in the Utils folder named Phone. (namespace App\Utils\Phone). The thing here is, that we need to use the EntityManager in this Utils class, because we need to store some of the data (Temporarily). We'll do this with the following code (Which works in controllers)
$em = $this->getDoctrine()->getManager();
$em->persist($smsStore);
$em->flush();
Now the error hits: Doctrine doesn't even exist here. It cannot be found. The question here is: How can we use the Doctrine EntityManager outside of the Controllers? We tried extending by using the default AbstractController, but this cannot be correct and doesn't work.
The same thing happens when we want to use our security class to get the current user. ($this->security->getUser()). Even when we import it like with a use. use Symfony\Component\Security\Core\Security;.
We hope we were clear with this question. We're a bit desperate because we're still looking for a solution after a few days. We use PHP version 7.1.3 and API-PLATFORM version 1.1 (composer.json)
EDIT 1: The does not exist is about an undefined method (getDoctrine). We tried a few things to implement this. For example using the AbstractController to extend the class. Another solution that worked is really pass the DoctrineManager with the function. This is however not a good practice.
EDIT 2: The AuthController snippet as requested. It shows how we use the Phone Utils. Could it be that I need to implement the EntityInterface at this function surrounding the following code?
$phone = new Phone();
$phone->overwriteUser($this->getUser());
$phone->newRecipient("4917640733908");
$phone->setBody("Hello, this is a test.");
Entity manager could be handle with the dependency injection(DI) pattern. This pattern is fully integrated in Symfony. This is the fun and magic aspect of Symfony.
All classes implementing an interface are available with dependency injections. With Symfony4+, the autoconfigure is activated. It seems to be complex, but for the final developer, it's pretty easy. Here is a simple example to do it with your Phone classes which seems to be a model where you have implemented you business logic.
class Phone
{
private $entityManager;
//The entity manager will be provided to your constructor with the dependency injection.
public function __construct(EntityManagerInterface $entityManager)
{
$this->entityManager = $entityManager;
}
public function save($smsStore)
{
//you own logic go here
//here is the magic part, the entityManager is available, connected, ready to use.
$this->entityManager->persist($smsStore);
$em->flush();
}
}
When you'll call the Utils classes method, the DI will construct it automatically and you will be able to use its property, the entity manager in this case.
If you want to use you class in a controller, you can do it by adding the phone class in its constructor:
class AuthController extends AbstractController
{
public function __construct(Phone $phoneUtils)
{
$this->phoneUtils = $phoneUtils;
}
public function someAction()
{
//your own logic here
//here is the magic part, the phone Utils is ready, it imports the entitymanager
//when you want to save your smsStore, simply call it
$this->phoneUtils->save($smsStore);
}
}
You are using Api-Platform, no problem! You can reproduce this design pattern in other classes like your DataPersisters, or in your EventListeners. If you look at this example in the ApiPlateform documentation, you can see how author get the Swiftmailer manager in his event listener. Simply replace the swiftmailer by EntityManagerInterface or the Phone utils classes.
(In a controller, it exists a simpliest way to retrieve the phone utils class)
class AuthController extends AbstractController
{
//Do That: ADD Phone $phoneUtils as an argument in the method
public function someAction(Phone $phoneUtils)
{
//your own logic here
//Do not do that: $phoneUtils = new Phone();
//Magic! when you want to save your smsStore, simply call it
$phoneUtils->save($smsStore);
}
}
If you want to get an autowired class (like the security layer), you could do it. To find which classes could be autowired, there are some tips:
symfony console debug:autowiring
symfony console debug:autowiring Security
symfony console debug:autowiring AuthorizationChecker
It will return all the classes corresponding to your search.
(If you do not use the symfony executable, you could replace it by php bin/console debug:autowiring)

Symfony unit test Security (ACL - Annotation)

I'd like to check a method with access control, e.g. a method is only granted with a specific role. Therefore, I know two ways in Symfony:
#Security annotation above the method (SensioFrameworkExtraBundle) OR
Calling authorization_checker explizit within my method
When it comes to unit tests (for my case phpspec, but I think phpunit behaviour is the almost the same in that case), I would like to test that only anonymous users should be able to call a method. With number 2. , it's working fine. Here my setup:
RegistrationHandlerSpec:
class RegistrationHandlerSpec extends ObjectBehavior
{
function let(Container $container, AuthorizationCheckerInterface $auth) {
$container->get('security.authorization_checker')->willReturn($auth);
$this->setContainer($container);
}
function it_should_block_authenticated_users(AuthorizationCheckerInterface $auth)
{
$auth->isGranted("ROLE_USER")->willReturn(true);
$this->shouldThrow('Symfony\Component\Security\Core\Exception\AccessDeniedException')->during('process', array());
}
}
And within the RegistrationHandler, I have the following method:
class RegistrationHandler
{
public function process()
{
$authorizationChecker = $this->get('security.authorization_checker');
if ($authorizationChecker->isGranted('ROLE_USER')) {
throw new AccessDeniedException();
}
// ...
}
}
Well, this approach is working fine - BUT normally, I would prefer using 1. with Security annotation (Sensio FrameworkExtraBundle), and therefore, it's not working / I don't know why no Exception gets triggered when it's written as an annotation:
/**
* #Security("!has_role('ROLE_USER')")
*/
public function process()
{
// ...
}
Does anyone know how to get this example to work by using the first approach with #Security annotation, which is way more readable and best practice recommended of symfony?
In both cases you're testing a behaviour that's provided by third party code (the Symfony framework). Following the rule don't mock what you don't own, rather than writing a unit test you should write an integration test. Otherwise you'll be only making assumptions on how the code works with no proof it really works this way.
In your case your integration test could be a controller test. You'd call the URL with a web test client (provided by the WebTestCase) and verify that in certain conditions you're getting a 401 or 403 response.
PHPSpec is a unit testing tool (a.k.a. a design tool). You need to write integration tests with something else (for example PHPUnit). I usually have at least three testing tools installed in my project:
PhpSpec for unit testing
PHPUnit for integration testing
Behat for acceptance testing (a form of integration testing)

Injecting the Doctrine Entity Manager in services - Bad practice?

Using https://insight.sensiolabs.com to scan / check my code, I get the following warning:
The Doctrine Entity Manager should not be passed as an argument.
Why is it such a bad practice to inject the Entity Manager in a service? What is a solution?
With respect to the comment that repositories cannot persist entities.
class MyRepository extends EntityRepository
{
public function persist($entity) { return $this->_em->persist($entity); }
public function flush () { return $this->_em->flush (); }
I like to make my repositories follow more or less a "standard" repository interface. So I do:
interface NyRepositoryInterface
[
function save($entity);
function commit();
}
class MyRepository extends EntityRepository implements MyRepositoryInterface
{
public function save ($entity) { return $this->_em->persist($entity); }
public function commit() { return $this->_em->flush (); }
This allows me to define and inject non-doctrine repositories.
You might object to having to add these helper functions to every repository. But I find that a bit of copy/paste is worth it. Traits might help here as well.
The idea is move away from the whole concept of an entity manager.
I am working on a quite a large project currently and have recently started following the approach with repositories that can mutate data. I don't really understand the motivation behind having to inject EntityManager as a dependency which is as bad as injecting ServiceManager to any class. It is just a bad design that people try to justify. Such operations like persist, remove and flush can be abstracted into sth like AbstractMutableRepository that every other repository can inherit from. So far it has been doing quite well and makes code more readable and easier to unit test!
Show me at least one example of a service that has EM injected and unit test for it looked correctly? To be able to unit test sth that has EM injected is more about testing implementation than anything else. What happens is then you end up having so many mocks set up for it, you cannot really call it a decent unit test! It is a code coverage hitter, nothing more!

How to auto complete methods from Symfony 2 DI in netbeans

I am starting to develop with symfony 2 and it uses a lot dependency injection. I would like to know if is there any way that makes netbeans detect the type of object based on the string and auto complete with their methods?
For example, $this->container->get('doctrine') returns a Doctrine\Bundle\DoctrineBundle\Registry instance. In the container, the key doctrine corresponds to Doctrine\Bundle\DoctrineBundle\Registry.
Something like it, could be useful for zendframework 2 also.
I don't want to create new methods in the controller and nor use /* #var $var Symfony...*/, I would automatic detection.
As far as I know, there's no way for an IDE to detect the type of the object your container returns. My solution is to wrap those calls to the container into private getter functions. IMHO this improves code readability as well – especially, if you do this call more than once per class.
/**
* #return \Doctrine\Bundle\DoctrineBundle\Registry
*/
private function getDoctrine()
{
return $this->container->get('doctrine');
}
The IDE "PhpStorm" permits to suggest "use" declarations.
And this IDE propose specific features for Symfony2 and Drupal !
edited by JetBrains : http://www.jetbrains.com/phpstorm/
Not free but power full enough to reduce time developpement time (and time is money...)
Enjoy : )
phpStorm:
$foobar= $this->get('foobar'); //returns mixed
/* #var \MyNamespace\FooBar $foobar*/
or
$foobar= $this->get('foobar'); //returns mixed
/* #var FooBar $foobar*/
You can do this with eclipse PDT:
$foobar= $this->get('foobar'); //returns mixed
/* #var $foobar \MyNamespace\FooBar*/
( Walk around ) When comes to Symfony services:
Instead of
$doctrine = $this->container->get('doctrine');
use
$doctrine = $this->getDoctrine();
As you can see, Symfony allows you to access most of it services directly from $this variable. NetBeans will know what auto completion to use.
Lets have a look why this works (inside Controller class)
It is possible because Controller class imports Registry class with USE statement,
use Doctrine\Bundle\DoctrineBundle\Registry;
and then in method comment annotation it declares the returning object type with
/*
* #return Registry
*/
If you call $this->container->get('doctrine'); directly then auto completion will be get omitted and you will have to use whats below.
( Answer ) No magic auto completion works so far. Use Php Storm (it does what you request). For those who pick to stick with NetBeans you need to use manual annotation like in example below:
We can point NetBeans to a class it should be using for auto completion.
1) In terminal from project directory search for service you want to import:
php bin/console debug:container
If you know what you looking for use this instead:
php bin/console d:container | grep doctrine
...
doctrine --------------------------------------------------------
Doctrine\Bundle\DoctrineBundle\Registry
...
2) If this is not a service use get_class() PHP build in function to get class name of the object it particular variable. Or use reflection class. It's up to you.
3) Once you know the class name declare USE statement for better readability
use Doctrine\Bundle\DoctrineBundle\Registry;
4) Now wen we know what is the class name of the object instance in particular variable we are ready to inform NetBeans about what we know by using comment annotations so that it can enable auto completion.
/**
* #var $doctrine Registry
*/
$doctrine = $this->container->get('doctrine');
Now auto completion is enabled. Type
$doctrine->|
then press Ctrl+Space. See the image below:

Resources