autoconfigure not tagging commands with symfony dependency-injection - symfony

I have a cli project that I am using Symfony's Dependency Injection and Console components. I am not using a Kernel, controllers, etc.
When using autoconfigure: true, the service doesn't get the console.command tag it is supposed to.
My composer.json:
{
"require": {
"php": "^7.4",
"monolog/monolog": "^2.0",
"symfony/console": "^5.0",
"symfony/dependency-injection": "^5.0",
"symfony/config": "^5.0",
"symfony/yaml": "^5.0"
},
"autoload": {
"psr-4": {"Mudder\\": "src/"}
}
}
./config/services.yaml:
services:
_defaults:
autowire: true
autoconfigure: true
Mudder\:
resource: '../src/*'
exclude: '../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}'
public: true
./src/Mudder/Command/HelloWorld.php:
<?php
namespace Mudder\Command;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class HelloWorld extends Command
{
protected static string $defaultName = 'test';
protected function configure()
{
$this->setDescription('Foo');
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$output->writeln('Hello, world.');
return 0;
}
}
Finally, ./test.php (the cli entrypoint):
<?php
require __DIR__ . '/vendor/autoload.php';
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
$containerBuilder = new ContainerBuilder();
$loader = new YamlFileLoader($containerBuilder, new FileLocator(__DIR__ . '/config'));
$loader->load('services.yaml');
$containerBuilder->compile();
print_r($containerBuilder->getDefinition(\Mudder\Command\HelloWorld::class)->getTags());
Output from the print_r() is an empty array "Array()"

The container itself does know nothing about a Command.
If you want to auto configure your commands, you have to call
$containerBuiler->registerForAutoconfiguration(Command::class)->addTag('console.command');
or load the FrameworkExtension (from symfony FrameworkBundle)

Your command should end with Command. Rename it to HelloWorldCommand.

Related

Can't register Ratchet bundle from private git in AppKernel

So a little context: I have an old project in symfony 2.8 and php 5.6
Composer have been abandonned by the previous developper and i'm trying to make it work again. I had a bunch of conflicting versions, url to previous svn, i've updated some package ect.
Now everything is installing fine but the clear cache from the post-update-cmd crash with this error :
PHP Fatal error: Class 'P2\Bundle\RatchetBundle\P2RatchetBundle' not found in /Project/app/AppKernel.php on line 19
I'm loading 2 vendor from private gitlab, both are installed but no matter which one i try to call in registerBundles()
I can't find the real cause of this error.
So here the code :
composer.json :
...
"repositories" : [
{
"type": "package",
"package": {
"name": "p2/ratchet-bundle",
"version": "dev-master",
"type": "package",
"source": {
"url": "https://git-dev.my-company.fr/my-company-bundles/ratchet-bundle.git",
"type": "git",
"reference": "master"
}
}
}
...
"require" : {
"p2/ratchet-bundle" : "dev-master",
...
}
AppKernel.php
class AppKernel extends Kernel {
public function registerBundles() {
$bundles = array(
...
new P2\Bundle\RatchetBundle\P2RatchetBundle(),
...
);
return $bundles;
}
public function registerContainerConfiguration(LoaderInterface $loader) {
$loader->load(__DIR__ . '/config/config_' . $this->getEnvironment() . '.yml');
}
}
There is no problem to get the bundle from the gitlab repo. It appears into the installed.json and installed.php of composer vendor
This bundle is installed in Project/vendor/p2/ratchet-bundle/P2RatchetBundle.php
namespace P2\Bundle\RatchetBundle;
/**
* Class P2RatchetBundle
* #package P2\Bundle\RatchetBundle
*/
class P2RatchetBundle extends Bundle
{
At the moment, i can't use the console or load any page with this new setup. It's probably just a small thing i missed but i can't figure what.
If you want some more information just ask

Minimal symfony setup with annonations

i want to create a simple api based on Symfony framework.
The controllers are already implemented.
1) What is the minimal setup of composer packages i need?
2) How can i setup a working index.php file that creates the routes from the annotations, match the urls and outputs the response?
Thank you very much!
Here is an example code of one of my controllers located in src/Bitter/Cloud/Server/Controller/PhotosController.php:
<?php
namespace Bitter\Cloud\Server\Controller;
use Bitter\Cloud\Cloud;
use Bitter\Cloud\Services\PhotosService;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
class PhotosController extends AbstractController
{
protected Request $request;
protected PhotosService $service;
public function __construct()
{
$this->request = Request::createFromGlobals();
$this->service = Cloud::getServices()->getPhotos();
}
/**
* Send a request to fetch photos and videos from the photo service.
*
* #Route("/photos/get_photos")
*
* #link project://docs/services/photos/get-photos.md
*/
public function getPhotos(): JsonResponse
{
$this->service->init();
return new JsonResponse([
"success" => true,
"photos" => $this->service->getPhotos()
]);
}
}
All other controllers are similar.
Here is my composer.json setup:
{
"name": "bitter/cloud-server",
"description": "Cloud Server for PHP.",
"license": "MIT",
"type": "project",
"homepage": "*********removed*********",
"authors": [
{
"name": "*********removed*********",
"email": "*********removed*********",
"role": "Developer"
}
],
"minimum-stability": "dev",
"repositories": [
{
"name": "bitter/cloud-api",
"type": "vcs",
"url": "git#bitbucket.org:*********removed*********"
}
],
"keywords": [
"cloud",
"php",
"api"
],
"support": {
"issues": "*********removed*********"
},
"require": {
"bitter/cloud-api": "*",
"symfony/http-foundation": "5.0.0",
"symfony/routing": "5.0.0",
"symfony/config": "5.0.0",
"doctrine/annotations": "1.8.0",
"symfony/framework-bundle": "5.0.0",
"doctrine/cache": "1.8.0"
},
"autoload": {
"psr-4": {
"Bitter\\Cloud\\Server\\": "src/Bitter/Cloud/Server"
}
}
}
All you need to do is create a simple application with composer:
composer create-project symfony/skeleton
then add an annotations package:
composer require annotations
There are many ways to use API with composer the most know are https://symfony.com/doc/master/bundles/FOSRestBundle/index.html fosRestBundle and https://symfony.com/projects/apiplatform it depends on your need the code you showed is a basic idea of an api
Apiplatform might be your best solution to build an API based on Symfony, it is a full fledged system though (json, json+ld, graphql, auth, documentation, pagination, etc...).
Or if you just need a basic setup your solution might be fine (assuming you're using the Symfony skeleton). Just setup routes in annotations in your controller and return data in JSON format.
As for the bundles you need it depends on what you want to able to achieve.
The security bundle might be a good idea if you need authentication for instance. See this doc to setup authentication for an API in Symfony.
The maker bundle is very useful to create entities and migrations. The Doctrine ORM bundle is very handy to store and retrieve data from your database and maintain it. But it's all up to you to chose from these, see some popular bundles in Symfony.

Functional tests inside a standalone Symfony2's bundle

I need to make some functional tests directly in a standalone bundle. I don't want to test a controller, just some interaction between real services.
I would like to know if there is a standard/best way to do that. I did it one way but would like to know if there is a better one.
Here is my own solution (I summarize all the process for testing in a standalone bundle):
1. First, a good bundle has its own composer.json to define its dependencies:
{
"name": "my/own-bundle",
"type": "symfony-bundle",
"description": "Symfony2 bundle that provides ...",
"keywords": ["my","own"],
"license": "MIT",
"authors": [
{
"name": "John Doe",
"email": "john.doe#omg.wtf"
}
],
"require": {
"php": ">=5.3.2",
"symfony/framework-bundle": ">=2.3"
},
"require-dev": {
"phpunit/phpunit": "3.7.*"
},
"autoload": {
"psr-0": { "My\\OwnBundle": "" }
},
"target-dir": "My/OwnBundle",
"minimum-stability": "dev"
}
Note the use of the dependency on symfony/framework-bundle which is needed for our tests on services. You certainly can lower the dependencies in specifying your own real dependencies on the symfony core.
With this file I can process the command (do it) to build the vendor directory of my bundle:
$ composer update
2. Then, I set my phpunit config file:
<!-- phpunit.xml.dist -->
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
backupStaticAttributes="false"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
syntaxCheck="false"
bootstrap="Tests/bootstrap.php"
>
<testsuites>
<testsuite name="MyOwnBundle Test Suite">
<directory>./Tests/</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory>./</directory>
<exclude>
<directory>./Resources</directory>
<directory>./Tests</directory>
<directory>./vendor</directory>
</exclude>
</whitelist>
</filter>
</phpunit>
3. Then, I set the php bootstrap for the autoload of the class in my test directory:
// Tests/bootstrap.php
$file = __DIR__.'/../vendor/autoload.php';
if (!file_exists($file))
{
$file = __DIR__.'/../../../../../../vendor/autoload.php';
if (!file_exists($file))
throw new RuntimeException('Install dependencies to run test suite.');
}
$autoload = require_once $file;
These steps are standard for any test in a standalone bundle.
4. Now, I want to simulate an application to make some functionnal tests on my services:
I need a kernel class:
// Tests/AppKernel.php (you can define it in a subdirectory /Fixtures if you prefer)
use Symfony\Component\HttpKernel\Kernel;
use Symfony\Component\Config\Loader\LoaderInterface;
class AppKernel extends Kernel
{
public function registerBundles()
{
$bundles = array();
if (in_array($this->getEnvironment(), array('test'))) {
$bundles[] = new Symfony\Bundle\FrameworkBundle\FrameworkBundle();
$bundles[] = new My\OwnBundle\MyOwnBundle();
}
return $bundles;
}
public function registerContainerConfiguration(LoaderInterface $loader)
{
$loader->load(__DIR__.'/config.yml');
}
}
And the corresponding config.yml:
# Tests/config.yml
framework:
secret: test
session:
storage_id: session.storage.mock_file
my_own:
test: 2
Here is an example with a mock for the session. Don't forget to specify the correct framework configuration nodes if you want to have access to some services (if you don't specify the node session, you have no service session for instance).
5. Finally, I can retrieve my services like the following in my test classes:
// Tests/Functional/Handling/Handler.php
namespace My\OwnBundle\Tests\Functional\Handling;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
class HandlerTest extends WebTestCase
{
private $handler;
protected function setUp()
{
require_once __DIR__.'/../../AppKernel.php';
$kernel = new \AppKernel('test', true);
$kernel->boot();
$container = $kernel->getContainer();
$this->handler = $container->get('my_own.handling.handler');
}
public function testHandle()
{
$this->assert($this->handler->handle());
}
}

Testing a symfony 2.1 project using behat and mink

I'm trying to use Behat and Mink to test a symfony 2.1 project.
My FeatureContext.php:
<?php
use Behat\Behat\Context\ClosuredContextInterface,
Behat\Behat\Context\BehatContext,
Behat\Behat\Exception\PendingException,
Behat\Behat\Context\Step;
use Behat\Gherkin\Node\PyStringNode,
Behat\Gherkin\Node\TableNode;
use Behat\MinkExtension\Context\MinkContext;
//
// Require 3rd-party libraries here:
//
// require_once 'PHPUnit/Autoload.php';
// require_once 'PHPUnit/Framework/Assert/Functions.php';
//
/**
* Features context.
*/
class FeatureContext extends Behat\MinkExtension\Context\MinkContext {
/**
* Initializes context.
* Every scenario gets it's own context object.
*
* #param array $parameters context parameters (set them up through behat.yml)
*/
public function __construct(array $parameters)
{
// Initialize your context here
}
//
// Place your definition and hook methods here:
//
// /**
// * #Given /^I have done something with "([^"]*)"$/
// */
// public function iHaveDoneSomethingWith($argument)
// {
// doSomethingWith($argument);
// }
//
}
composer.json
"behat/behat": ">=2.2.2",
"behat/mink": ">=1.3.2",
"behat/symfony2-extension": "*",
"behat/mink-extension": "*",
"behat/mink-browserkit-driver": "*",
"behat/mink-selenium-driver": "*"
app/config/behat.yml
default:
extensions:
Behat\Symfony2Extension\Extension:
mink_driver: true
kernel:
env: test
debug: true
Behat\MinkExtension\Extension:
base_url: 'http://localhost:8080/app_test.php/'
default_session: symfony2
javascript_session: selenium
selenium:
host: 127.0.0.1
port: 4444
When I do ./bin/behat I get:
Feature: Login
In order to login
As a user
I need to be able to validate the username and password
Scenario: Link to login page # features/login.feature:7
PHP Fatal error: Call to a member function getSession() on a non-object in vendor/behat/mink-extension/src/Behat/MinkExtension/Context/RawMinkContext.php on line 81
Fatal error: Call to a member function getSession() on a non-object in vendor/behat/mink-extension/src/Behat/MinkExtension/Context/RawMinkContext.php on line 81
Any idea?
v.
Your behat.yml should not be located in app/config/behat.yml , but in your/project/root/behat.yml
Thanks for #Stuart and #spiritoo answers here.
Firstly, move the behat.yml from /config to project root.
Secondly, content for the behat.yml:
default:
suites:
my_suite:
contexts:
- FeatureContext
extensions:
Behat\Symfony2Extension: ~
Behat\MinkExtension:
base_url: http://en.wikipedia.org
goutte: ~
sessions:
default:
symfony2: ~
Finally, in project root, run:
vendor/bin/behat features/{YOUR TEST FILE HERE}
My composer.json file:
"require-dev": {
"behat/behat": "^3.3",
"behat/mink": "^1.7",
"behat/mink-extension": "^2.2",
"behat/mink-browserkit-driver": "^1.3",
"behat/mink-goutte-driver": "^1.2",
"behat/symfony2-extension": "^2.1",
"behat/mink-selenium2-driver": "^1.3"
}

How do I correctly declare a Dependency to another Bundle within a Bundle?

I am trying to use a Bundle inside a Bundle but somehow it is failig.
"repositories": [
{
"type": "vcs",
"url": "https://github.com/myname/mybundle"
}
],
"require": {
"php": ">=5.3.3",
"symfony/symfony": "2.1.*",
(...)
"myname/mybundle": "*"
},
this seems to work so far. But I can't figure out how to declare another dependency within "myname/mybundle".
I tried the following in the composer.json file of myname/mybundle but none of them worked :(
"repositories": [
{
"type": "vcs",
"url": "url": "https://github.com/drymek/PheanstalkBundle"
}
],
"require": {
(...)
"drymek/PheanstalkBundle": "dev-master"
}
and
"repositories": [
{
"type": "package",
"package": {
"name": "drymek/PheanstalkBundle",
"version": "dev-master",
"source": {
"url": "https://github.com/drymek/PheanstalkBundle.git",
"type": "git",
"reference": "master"
}
}
}
],
"require": {
(...)
"drymek/PheanstalkBundle": "dev-master"
}
when I rum composer.phar update all i get is
- myname/mybundle dev-master requires drymek/pheanstalkbundle dev-master -> no matching package found.
Okay I've found an answer here
It states: Repositories are not resolved recursively. You can only add them to your main composer.json. Repository declarations of dependencies' composer.jsons are ignored.
That's too bad... but now at least I know where to put my dependeny (in the root composer.json file)
For bundle dependencies, please see my library https://github.com/AshleyDawson/MultiBundle. As an example, extend the MultiBundle and implement the getBundles() method, like so:
<?php
namespace Acme\MyBundle;
use AshleyDawson\MultiBundle\AbstractMultiBundle;
class AcmeMyBundle extends AbstractMultiBundle
{
/**
* Optional: define a protected constructor to stop instantiation outside of registerInto()
*/
protected function __construct()
{
}
/**
* Define bundles that this bundle depends on
*/
protected static function getBundles()
{
return array(
new Acme\FooBundle\AcmeFooBundle(),
new Acme\BarBundle\AcmeBarBundle(),
);
}
}
And then in the AppKernel register the bundle and it's dependencies:
// app/AppKernel.php
// ...
class AppKernel extends Kernel
{
// ...
public function registerBundles()
{
$bundles = array(
// ...,
);
// Register my bundle and its dependencies
\Acme\MyBundle\AcmeMyBundle::registerInto($bundles);
// ...
}
}

Resources