I am trying to setup Behat 3.0. I want to change the path of where my features go.
Currently, my behat.yml config looks like this:
default:
autoload:
'': app/tests/acceptance
Running behat --init wil create the acceptance/FeatureContext.php in the app/tests directory.
However, it will create the features folder in the root of my project. I would instead want this features folder to be placed in the app/tests/acceptance folder.
How can I do this?
Behat 3 has support for suites and profiles.
Only thing you have to do is to add custom paths to the default profile:
default:
autoload:
'': %paths.base%/app/tests/acceptance
suites:
default:
paths: [ %paths.base%/app/tests/acceptance/features ]
Tip 1
Always use the %paths.base% variable to be able to run your Behat tests from a different directory.
Tip 2
Depending on Behat's PSR-0 autoload mechanism can be problematic when you'll have more contexts implemented.
Good practice is to use the composer's PSR-4 autoload mechanism to be able to run namespaced Behat features.
After you have setup Behat as in the example above you need to delete the autoload section in the bahat.yml and add contexts to the default profile:
default:
suites:
default:
paths: [ %paths.base%/app/tests/acceptance/features ]
contexts: [ MyApp\Tests\Acceptance\FeatureContext ]
Add autoloading configuration to composer.json:
{
[...]
"autoload-dev": {
"psr-4": {
"MyApp\\Tests\\Acceptance\\": "app/tests/acceptance"
}
}
[...]
}
And then simply dump the autoloader with composer dump-autoload.
I suffered a lot with it, so here is my (simple) solution, in the hope it will save time to someone oneday. Using behat 3.8.1.
My files layout:
behat.yml
test/acceptance/bootstrap/FeatureContext.php
test/acceptance/features/myAcceptanceTest.feature
My behat.yml file:
default:
autoload: [ '%paths.base%/test/acceptance/bootstrap' ]
suites:
default:
paths: [ '%paths.base%/test/acceptance/features' ]
contexts: [ test\acceptance\bootstrap\FeatureContext ]
Unlike everything I read, including the documentation, I had to add quotes to be able to use the %paths.base% variable.
The autoload parameter tells Behat where to find your context php file(s).
The paths parameter tells Behat where to find your features file(s).
The tricky part is the contexts parameter: it gives the namespace path of your FeatureContext class. You need to make sure that it matches what you have at the top of your FeatureContext.php file:
<?php
namespace test\acceptance\bootstrap;
...
class FeatureContext implements Context
{
...
}
With all these planets properly aligned, it works beautifully. From the project folder:
$ vendor/bin/behat
HTH
Related
I'm having autowiring issues within symfony since I have updated my Docker to the latest version.
I am not entirely sure of the causality here but certainly, my issues started appearing only after updating my docker. Since this was the case I obviously tried to revert back to a previous docker version but still had the same issues as on the new build. That's why I am doubtful of the causality.
I'm now on: Docker version 3.5.2 with Docker Engine v20.10.7
docker-engine config is the unchanged config:
{
"registry-mirrors": [],
"insecure-registries": [],
"debug": false,
"experimental": false,
"features": {
"buildkit": true
},
"builder": {
"gc": {
"enabled": true,
"defaultKeepStorage": "20GB"
}
}
}
when I started my first project I had an issue with the composer not reading my lib-folder. This was solved as described below but it might provide some more insight, context and things I have checked/done
At first my mind went to this Windows env variable. Alas, it was set so it was not the problem.
Secondly, my mind went to file ownership or file permissions but also not the problem. Everything in my containers was owned by root and had rwx permissions.
Thirdly I thought it might be because of the new WSL2 backend I had to install. Until the day of the update I had still been running on the Hyper-V backend. Luckily there is a setting in docker where you can switch off the use of WSL-2 and revert to Hyper-V but this was also not the solution to my problem.
My composer.json looked like this:
"autoload": {
"classmap": [
"scripts/composer/ScriptHandler.php",
"lib/",
...
],
"psr-4": {
...
}
},
Everything but (some) files of lib were present in my autoload_classmap.php
After fiddling about for too long I finally tried the following and suddenly my problems on my first project were gone
"autoload": {
"classmap": [
"scripts/composer/ScriptHandler.php",
"lib/*",
...
],
"psr-4": {
...
}
},
I still don't understand why the first one should not work. It has worked until this thursday since the infamous update.
Now on to the second project and I really can't figure out what's going on and I'm at a loss for words. My colleagues can't seem to figure out what's wrong either. This second project is something more recent so not loading a classmap anymore and everything follows PSR-4 standards.
This is the autoload part of the composer.json:
"autoload": {
"psr-4": {
"App\\": "src/",
"Project\\": "scripts/"
}
},
This is my services.yaml (These are just the standard symfony settings AFAIK):
services:
# default configuration for services in *this* file
_defaults:
autowire: true # Automatically injects dependencies in your services.
autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
public: false # Allows optimizing the container by removing unused services; this also means
# fetching services directly from the container via $container->get() won't work.
# The best practice is to be explicit about your dependencies anyway.
# makes classes in src/ available to be used as services
# this creates a service per class whose id is the fully-qualified class name
App\:
resource: '../src/*'
exclude: '../src/{Entity,Migrations,Tests,Kernel.php}'
This is my docker PHP container:
php:
container_name: "${DOCKER_PROJECT_NAME}_php"
environment:
COLUMNS: 80
PHP_FPM_GROUP: wodby
PHP_FPM_USER: wodby
PHP_SENDMAIL_PATH: "/usr/sbin/sendmail -t -i -S mailhog:1025"
PHP_DEFAULT_CHARSET: 'utf-8'
PHP_DATE_TIMEZONE: 'UTC'
PHP_UPLOAD_MAX_FILESIZE: '10M'
PHP_POST_MAX_SIZE: '10M'
PHP_DISPLAY_ERRORS: 'On'
PHP_DISPLAY_STARTUP_ERRORS: 'On'
PHP_MAX_EXECUTION_TIME: '30000'
PHP_MAX_INPUT_TIME: '60'
PHP_MAX_INPUT_VARS: '2000'
PHP_ERROR_REPORTING: 'E_ALL'
PHP_LOG_ERRORS: 'On'
PHP_LOG_ERRORS_MAX_LEN: '0'
PHP_MEMORY_LIMIT: '512M'
PHP_SESSION_GC_MAXLIFETIME: '700000'
PHP_REALPATH_CACHE_SIZE: '4096K'
PHP_REALPATH_CACHE_TTL: '3600'
PHP_XHPROF: $PROFILING_ENABLED
env_file:
- .env
image: "wodby/php:7.4-dev-4.16.2"
volumes:
- "./:/var/www/html"
## For php profiler traces
- "files:/mnt/files"
On startup I am getting the following Runtime Exception:
Cannot autowire service "App\Form\Wizard\DaysOffType": argument "$daycareTransformer" of method "__construct()" references class "App\Form\DaycareTransformer" but no such service exists.
This class is not new, it's been in code for 2 years. It's in the right folder and the namespacing is correct. Also the src folder is included in the autoload_psr4.php.
The DaycareTransformer that "can't be found" is located in src/Form under the namespace App\Form as per psr4 namespace convention
<?php
namespace App\Form;
use App\Entity\Daycare;
use App\Service\DaycareService;
use Symfony\Component\Form\DataTransformerInterface;
use Symfony\Component\Form\Exception\TransformationFailedException;
class DaycareTransformer implements DataTransformerInterface
{
private $daycareService;
public function __construct(DaycareService $daycareService)
{
$this->daycareService = $daycareService;
}
...
}
There have not been any recent changes to this code. Not to the DaysOffType which has the DaycareTransformer injected and not to the DaycareTransformer.
I am the only person having these issues as I am the only one who runs Docker on a Windows machine. Production and QA environments are all up and running so there is no structural problem in the code.
It could be because the project running symphony in this case was locate at Windows partition (C: or D: or whatever inside your window) and not Linux distro.
If you are using WSL (most likely), you should always store Linux related project inside your distro (Ubuntu in my case, I store it it ~/...). You should not store Linux related project in /mnt/... when using WSL.
When I said "Linux related" I mean whatever project usually want to run on Linux environment, or using docker
Don't know if this could solve it for others because there could be a wide range of reason for this problem. But this is how I solve mine.
We've got the same problem on a Windows machine with Docker and Symfony 5.x.
We continued to work on this machine, but we changed our configuration.
For example, for your error I would use the following config.
Cannot autowire service "App\Form\Wizard\DaysOffType": argument "$daycareTransformer" of method "__construct()" references class "App\Form\DaycareTransformer" but no such service exists.
config/services.yml or config/services_dev.yml
services:
App\Form\DaycareTransformer: ~
We defined all the required classes from our errors and it solved our problem. But it solved problem only for one URL instead of all. You need to check each your routes or classes that use Symfony's autowire.
Unfortunately, the solution like declaration of resources didn't for us. We had to define all the required classes from our errors.
services:
App\DataTransformer\:
resource: '../src/DataTransformer/'
Don't redefined your classes that have already defined in your config, because it replaces your configuration and may make other errors.
You can do it in config/services.yml and commit it or you can use config/service_dev.yml and don't commit it if you haven't use this config before. In the second way you also can change .gitignore and add there the filename.
# Ignore changes for the file and don't track it.
config/services_dev.yml
WARNING! If you still have problems with it define all the required classes in services.yml instead of two or more config files.
We don't have this problem on Linux and MacOS machines.
I tried to find any documentation about using Symfony Flex but so far no luck.
Almost all docs point to installing a bundle that uses symfony Flex, not how to create a bundle that is using it.
I even tried to reverse engineer some of the packages but again, no luck.
My goal is to generate a default configuration file for my bundle in config/packages/my_bundle.yaml.
What I need to know is where do I need to put it and what env variables (if any) will I have available?
What is a Flex Recipe?
Keep in mind that the flex recipe is a separate repository from your package repository, that needs to be hosted separately from the Bundle package.
In the most likely scenario that your is a public bundle/recipe, you'll have to submit your recipe to the "contrib" repository, get it approved and merged, so it's available as a community recipe.
Additionally, it's important to remember that most users will not have the contrib repository enabled by default. So if this is important for installing this bundle, you should tell your users how to do so before they install your recipe (e.g. in your bundle's readme file).
Private Recipes
The other option would be having a private Flex recipe, as described here. The easiest way to generate a private recipe is to follow the same steps that Symfony does. Check this question and its answers for more details: How to generate a private recipe JSON from the contents of a recipe directory?
With that out of the way: Basically, a Flex recipe is a repository with a manifest.json file with specific keys to enable certain "configurators".
The available manifest.json configurators are:
Bundles
Which bundles should be enabled on bundles.php. These are added when the recipe is installed, and removed when the recipe is uninstalled.
{
"bundles": {
"Symfony\\Bundle\\DebugBundle\\DebugBundle": ["dev", "test"],
"Symfony\\Bundle\\MonologBundle\\MonologBundle": ["all"]
}
}
Configuration
The "configuration" configurator deals with two keys: copy-from-recipe and copy-from-package. The first one can copy files from the recipe repository, the second one copies files from the package repository.
{
"copy-from-package": {
"bin/check.php": "%BIN_DIR%/check.php"
},
"copy-from-recipe": {
"config/": "%CONFIG_DIR%/",
"src/": "%SRC_DIR%/"
}
}
In this example, a file bin/check.php in the package will be copied to the projects %BIN_DIR%, and the contents of config and src on the recipe package will be copied the corresponding directory.
This is the typical use case to provide default configuration files, for example. From what you ask, this is your stated purpose for wanting to create a flex recipe.
Env Vars
This configurator simply adds the appropriate environment variable values to the project's .env and .env.dist. (Again, these would be removed if you uninstalled the recipe)
{
"env": {
"APP_ENV": "dev",
"APP_DEBUG": "1"
}
}
Composer Scripts
This configurator adds tasks to the scripts:auto-scripts array from the project's composer.json. The auto-scripts are tasks that are executed every time composer update or composer install are executed in the project.
{
"composer-scripts": {
"vendor/bin/security-checker security:check": "php-script",
"make cache-warmup": "script",
"assets:install --symlink --relative %PUBLIC_DIR%": "symfony-cmd"
}
}
The second part on each line specifies what kind of command it is: a regular PHP script (php-script), a shell script (script), or a Symfony command (symfony-cmd, executed via bin/console).
Gitignore
This will add entries to the project's .gitignore file.
{
"gitignore": [
"/phpunit.xml"
]
}
A complete example of a manifest.json (lifted from here, as most other examples on this post):
{
"bundles": {
"Symfony\\Bundle\\FrameworkBundle\\FrameworkBundle": ["all"]
},
"copy-from-recipe": {
"config/": "%CONFIG_DIR%/",
"public/": "%PUBLIC_DIR%/",
"src/": "%SRC_DIR%/"
},
"composer-scripts": {
"make cache-warmup": "script",
"assets:install --symlink --relative %PUBLIC_DIR%": "symfony-cmd"
},
"env": {
"APP_ENV": "dev",
"APP_DEBUG": "1",
"APP_SECRET": "%generate(secret)%"
},
"gitignore": [
".env",
"/public/bundles/",
"/var/",
"/vendor/"
]
}
Additional configurators
There are two configurators which do not rely on the manifest.json file:
Post-install output.
If a file named post-install.txt exists in the recipe's package, its content is displayed when installation is complete. You can even use styles as defined here, for additional prettiness/obnoxiousness.
Example:
<bg=green;fg=white> </>
<bg=green;fg=white> Much success!! </>
<bg=green;fg=white> </>
* <fg=yellow>Next steps:</>
1. Foo
2. <comment>bar</>;
3. Baz <comment>https://example.com/</>.
This will be presented to the user after the installation is complete.
Makefile
If a file named Makefile exists in the recipe's repository, the tasks defined here would be added to the project's Makefile (creating the Makefile if it didn't exist).
cache-clear:
#test -f bin/console && bin/console cache:clear --no-warmup || rm -rf var/cache/*
.PHONY: cache-clear
Simple as that. I guess than most packages would not need a makefile command, so this would have much less use than other configurators.
You can read the full documentation here.
I've problem in configuring Propel with Composer in my php project.
this is how appears my tree directory:
project/
|--/public_html/index.php
|--/app/
| |--data/
| | |--propel.json
| | |--schema.xml
| |--vendor/
| |--composer.json
In /data/ folder I would store all my propel files, that is generated-classes/ , generated-conf/ and generated-sql/ .
To realize this purpose, with a terminal in /data/ folder, I put the commands in the following sequence:
$ propel sql:build
$ propel model:build
$ propel config:convert
and all go right.
To make more suitable work, in composer.json I've added this extra feature:
"autoload": {
"classmap": ["./data/generated-classes/"]
}
so that, almost in theory, putting
require '../app/vendor/autoload.php';
inside index.php should be enough. Unfortunately, when I try to use one propel classes inside this page, returns the error
Type: Propel\Runtime\Exception\RuntimeException
Message: No connection defined for database "my_api". Did you forget to define a connection or is it wrong written?
File: 'C:\pathToMyProject'\project\app\vendor\propel\propel\src\Propel\Runtime\ServiceContainer\StandardServiceContainer.php
Line: 279
I thought that propel doesn't find the propel.json file stored in /data/folder.
As extra, if in index.php I simply add
require_once '../app/data/generated-conf/config.php';
all goes right.
There's a trick to autoload propel without use this last require_once? (obviously keep the tree as is).
Thanks for reading.
The order of CLI commands is important:
composer install or update to fetch propel
then the commands to generate the models with propel
then re-scan / re-generate the autoloading files with composer dump-autoload --optimize
You could include the configuration file in the bootstrap process of your application - like you already have.
Or you could use the files directive in Composers autoload section
to define file(s), which should be included on every request.
Referencing: https://getcomposer.org/doc/04-schema.md#files
"autoload": {
"files": ["./data/generated-conf/config.php"],
"classmap": ["./data/generated-classes/"]
}
I'm trying to run Behat (first time for me) and it worked.
But i have a configuration problem. I tried to change the paths of features and bootstrap like so:
#behat.yml
default:
paths:
features: app/tests/features
bootstrap: %behat.paths.features%/bootstrap
Now i'm getting an exception:
[Symfony\Component\Config\Definition\Exception\InvalidConfigurationException] Unrecognized options "paths" under "testwork"
What did i do wrong?
Behat 3 is out by now. You configure paths as follows:
#behat.yml
default:
autoload:
'': %paths.base%/tests/features/bootstrap
suites:
default:
paths:
- %paths.base%/tests/features
The path given in the autoload section sets the path where Behat looks for context classes. The paths in the suites section are where the feature definitions (of the default suite in this case) live in.
You're trying to use Behat 3, which is not released yet - use version 2.5 instead.
using composer in a Php project, with Twig and my own framework.
I would like to "override" the Twig_Node_Expression_GetAttr class from Twig with my own class.
Everything it's working fine, but I have to manually add in composer autoload_classmap.php file :
'Twig_Node_Expression_GetAttr' => 'ebuildy/ebuildy/src/eBuildy/Templating/Twig_Node_Expression_GetAttr.php',
How can I declare this in my composer.json description file ?
Thanks,
You can just define the classmap entry in your project's composer.json, or using PSR-0 mapping as well. See the composer docs on autoloading for details. If you define the PSR-0 namespace with a more restrictive namespace than what Twig has, then you're sure yours will take over, .e.g:
{
"autoload": {
"psr-0": {
"Twig_Node_": "path/to/src/"
}
}
}
This however only works if in this src/ dir you have a file called: src/Twig/Node/Expression/GetAttr.php.