I'm trying to test my RoomRepository with PHPUnit and Symfony 4. I installed symfony/phpunit-bridge using composer. I created a simple entity called Room with one id and name attributs and a repository method to get a Room by its id.
public function get(int $id): ?Room
{
/** #var Room $room */
$room = $this->findOneBy(['id' => $id]);
return $room;
}
My test is quite simple as you can see :
public function testGet(): void
{
/** #var RoomRepository $repository */
$repository = $this->em->getRepository(Room::class);
$room = $repository->get(1);
$this->assertCount(1, $room);
}
I am new with test and I don't know if it's the right way to proceed. I followed the Symfony documentation.
So, when I execute the following command :
./vendor/bin/simple-phpunit
I am getting this error :
Doctrine\DBAL\Exception\ConnectionException: An exception occurred in driver: SQLSTATE[HY000] [2002] No such file or directory
I am pretty sure this is a commun mistake and very easy to fix...
Furthermore, I wrote other simple asserts that worked very well. I don't think it's about PHPUnit configuration.
Here some informations about my env :
PHP 7.1
Symfony4.0.5
PHPUnit 5.7.27
Docker with Laradock (containers : mysql, apache2, workspace)
Thanks guys for reading my post and have a nice day :)
I had the same problem – I just forgot to add the database url to the phpunit.xml.dist file. You have to add:
<phpunit ...>
<php>
...
<env name="DATABASE_URL" value="mysql://username:password#server:port/database" />
...
</php>
...
</phpunit>
Of course with your own credentials instead of the placeholders.
Related
I'am currenty face to this error when i try to get my article page : Cannot autowire argument $article of "App\Controller\HomeController::show()": it references class "App\Entity\Article" but no such service exists.
I just created a very new small symfony 5 application :
The code in my controller is :
/**
* #Route("/show/{id}", name="show")
*/
public function show(Article $article): Response
{
if(!$article) {
return $this->redirectToRoute('home');
}
return $this->render('show/index.html.twig', [
'article' => $article,
]);
}
I'am following a tutorial on Udemy and i guess that i did the same thing than the former. Maybe version difference ?
Thanks in advance for your helps.
Thierry
The error you have is saying that it cannot find the auto-wire path to your entity. Using the Symfony installer will automatically configure parts like this for you.
The main part which auto-wires the Entity to the Dependency Injection layer is through Doctrine configuration and the Symfony ParamConverter found as part of the SensioFrameworkExtraBundle.
The ParamConverter has a lot of options to be able to convert parameters inside of the #Route into an Entity. Using your example above we see that Symfony will internally call ArticleRepository->findOneById($id) and return the result to your controller.
EDIT: Removed all mentions of Doctrine configurations. The errors that are displayed when Doctrine is not auto-wiring are different.
Same problem here (with attributs instead of annotations) on Symfony 5
I have even tried to explicite ParamConverter and Entity:
#[Route('/article/{id}/editer', name: 'edit_article', requirements: ["id" => "\d+"], methods: ['GET','POST'])]
#[ParamConverter('id', options: ['mapping' => ['id' => 'id']])]
#[Entity('article', expr: 'repository.findOneBySlug(id)')]
public function editArticle(Article $article, Request $request,
CategoryRepository $categoryRepository, EntityManagerInterface $manager): Response
{
dump($article); die;
}
but i have got the error message:
Cannot autowire argument $id of "App\Controller\DefaultController::editArticle()":
it references class "App\Entity\Article" but no such service exists.
Although there is:
use App\Entity\Article;
And the solution like #nico-haase said is to install this bundle
composer require sensio/framework-extra-bundle
I have an action in the controller for mass instert in the database...
So this uses a lot of resources and the profiler is caching everything and server goes down.
How can i disable the profiler (and all the debug services) in one action on the controller?
The controller looks like :
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\HttpFoundation\Request;
use App\Sync\Incomming\Syncronize;
/**
* #Route("/sync")
*/
class SyncController extends AbstractController
{
private $syncronize;
public function __construct(Syncronize $syncronize)
{
$this->syncronize = $syncronize;
}
/**
* #Route("/",name="sync_index")
*/
public function index(Request $request, Profiler $profiler)
{
$message = "Hello";
return $this->render( 'sync/output.html.twig', ['message' => $message ]);
}
}
if I try to autowire the profiler in the constructor method then I get the error public function __construct(Syncronize $syncronize, Profiler $profiler):
Cannot autowire service "App\Controller\SyncController": argument
"$profiler" of method "__construct()" references class
"Symfony\Component\HttpKernel\Profiler\Profiler" but no such service
exists. You should maybe alias this class to the existing "profiler"
service.
if I try to autowire the profiler in the index method then I get the error public function index(Request $request, Profiler $profiler):
Controller "App\Controller\SyncController::index()" requires that you
provide a value for the "$profiler" argument. Either the argument is
nullable and no null value has been provided, no default value has
been provided or because there is a non optional argument after this
one.
EDIT
For big queries disabling the profiler was not the solution... Actually you need to disable the setSQLLogger:
$em->getConnection()->getConfiguration()->setSQLLogger(null);
Symfony 3.4 / 4
https://symfony.com/doc/4.0/profiler/matchers.html
use Symfony\Component\HttpKernel\Profiler\Profiler;
class DefaultController
{
// ...
public function someMethod(Profiler $profiler)
{
// for this particular controller action, the profiler is disabled
$profiler->disable();
// ...
}
}
If you have an error with autowiring
# config/services.yaml
services:
Symfony\Component\HttpKernel\Profiler\Profiler: '#profiler'
Old:
If you want to disable the profiler from a controller, you can like this:
use Symfony\Component\HttpKernel\Profiler\Profiler;
// ...
class DefaultController
{
// ...
public function someMethod(Profiler $profiler)
{
// for this particular controller action, the profiler is disabled
$profiler->disable();
// ...
}
}
Source: https://symfony.com/doc/current/profiler/matchers.html
Another way would be to use: $this->get('profiler')->disable();
Older:
Simply switch the app to prod mode and disable debug mode.
To do this, open the .env file on the server in your favourite editor (Note: You should never commit this file to Git, as you store secrets in there!).
In that file, you should see a section starting with: ###> symfony/framework-bundle ###
Just below that there is a APP_ENV=dev and APP_DEBUG=1, change these two lines to APP_ENV=prod and APP_DEBUG=0. Then save the file.
Next you should clear the cache for prod mode and install the assets. To do this, run the following commands:
php bin/console cache:clear --env=prod --no-debug
php bin/console cache:warmup --env=prod --no-debug
php bin/console assets:install --env=prod --no-debug --symlink
If you now load the application, it is in prod mode, which includes more caching and is faster as debug is disabled.
Note:
There will still be a timelimit for PHP. If you still hit that limit, you can either change your PHP setting or alternatively you could run the import from CLI, as CLI usually has no timelimit. If users need to be able to upload on their own, I'd suggest having them upload the file, enter a "note" about the file to a db and have a cronjob reading that db for not imported files and import them.
so I've been testing Doctrine queries and other Symfony code and I have to run several commands just to clear Doctrine/Symfony caches. I was searching for the net and came across another command to clear Assetic assets/etc.
From what I've read
php app/console cache:clear
will only clear Symfony cache. it won't include Doctrine and perhaps more.
I know I can create a bash script to clear all my caches but this obviously means I know all the "clear cache" commands. I only found out about the Assetic clear cache/assets by accident. What about those I don't know?
So is there 1 "clear cache" command that can do it for me? This will have to include Symfony/Doctrine/Assetic/Twig and whatever plugins I have installed.
Thanks a lot
What you are looking for is highly dependent on the developer of the bundle that uses the cache. Not even doctrine, that comes with the standard version of symfony has its cache clear command integrated. But what you can do is extend the default symfony command with a listener that runs all the cache clear command you want like this:
<?php
namespace DefaultBundle\Event\Listener;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\HttpKernel\CacheClearer\CacheClearerInterface;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\ConsoleOutput;
use Symfony\Component\HttpKernel\Kernel;
use Symfony\Component\Process\Process;
class CacheClearListener implements CacheClearerInterface
{
private $environment;
/**
* #return array
*/
private static function getCommands()
{
return array(
'php ./app/console doctrine:cache:clear-metadata --no-debug --flush',
'php ./app/console doctrine:cache:clear-query --no-debug --flush',
'php ./app/console doctrine:cache:clear-result --no-debug --flush'
);
}
public function clear($cacheDir)
{
$output = new ConsoleOutput();
$output->writeln('');
$output->writeln('<info>Clearing Doctrine cache</info>');
foreach (self::getCommands() as $command) {
$command .= ' --env='.$this->environment;
$success = $this->executeCommand($command, $output);
if (!$success) {
$output->writeln(sprintf('<info>An error occurs when running: %s!</info>', $command));
exit(1);
}
}
}
/**
* #param string $command
* #param ConsoleOutput $output
*
* #return bool
*/
private function executeCommand($command, ConsoleOutput $output)
{
$p = new Process($command);
$p->setTimeout(null);
$p->run(
function ($type, $data) use ($output) {
$output->write($data, false, OutputInterface::OUTPUT_RAW);
}
);
if (!$p->isSuccessful()) {
return false;
}
$output->writeln('');
return true;
}
/**
* #param Kernel $kernel
*/
public function setKernel(Kernel $kernel)
{
$this->environment = $kernel->getEnvironment();
}
}
Register the listener like this:
<service id="cache_clear_listener" class="DefaultBundle\Event\Listener\CacheClearListener">
<call method="setKernel">
<argument type="service" id="kernel"/>
</call>
<tag name="kernel.cache_clearer" priority="254" />
</service>
And that is all. Now all you need to do is keep adding your new cache clear command to the getCommands() method. In order to find this commands you can run something like
php app/console | grep cache
to see all available commands that contain the word "cache" in them
After your listener is set, every time you run php app/console cache:clear it will trigger all the command that you listed in the getCommands() method of your listener.
Hope this helps,
Alexandru
I'm working on a Symfony2 Command, and I have an error when I try to run the command in prod environment, but it work perfectly in dev :
Everything is fine if I run :
php app/console mycommand:start
When I run
php app/console mycommand:start --env=prod
I get this error :
[LogicException]
The command defined in "NameSpace\Of\MyClassCommand" cannot have an empty name.
Command definition :
services:
my_service.command:
class: NameSpace\Of\MyClassCommand
arguments:
name: mycommand:start
tags:
- { name: console.command }
Command :
class MyClassCommand extends Command
{
/**
* #param InputInterface $input
* #param OutputInterface $output
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
// logic
}
...
}
As you may notice, I don't overload the __construct or the configure methods. I tried but it didn't change anything. Same thing if I clean the cache.
Does anyone have an idea of what could be the difference between the prod and the dev environment, to cause this problem ?
Thank you
Clearing cache is not working for me. I need to declare base class as abstract class to hint Symfony not to register it as command.
abstract class BaseCommand {
...
}
I finally found the solution, Ruslan you were right : clear the cache.
But I had to manually nuke the cache folder, the cache:clear command was not enough.
When I try to reload my fixtures using
php app/console doctrine:fixtures:load
I'm getting this error:
SQLSTATE[23000]: Integrity constraint violation: 1451 Cannot delete or
update a parent row: a foreign key constraint fails (foo_db.Book, CONSTRAINT FK_C29271DD816C6140 FOREIGN KEY (author_id) REFERENCES Author (id))
The error is showed when the status "> purging database" is showed.
This is my code:
class Book{
...
/**
* #ORM\ManyToOne(targetEntity="Author", inversedBy="books")
*/
private $author;
...
}
class Author{
...
/**
* #ORM\OneToMany(targetEntity="Book", mappedBy="author")
*/
private $books;
}
More: my boss has the same code and it doesn't have that error.
Any idea?
sf 2.0.1 (just updated)/ubuntu 10.10.
If I'm guessing correctly, you are using a MySQL database. If yes, then you are facing a bug/problem with the current version of the doctrine-fixtures library for Doctrine2. The problem is that they are using the TRUNCATE command to purge the current database values but this command has problem deleting foreign associations in MySQL.
See this issue and this one on the GitHub repository of the library for more information and workarounds.
In my particular case, I run this command from a script, so to make the command work correctly, I do:
php app/console doctrine:database:drop --force
php app/console doctrine:database:create
php app/console doctrine:schema:update --force
php app/console doctrine:fixtures:load --append
This way, the purging is done by the drop command and appending has the same effect as not appending since the database is empty when the fixtures are loaded.
I must admit I don't know why your boss doesn't have the problem, maybe there is no book associated with an author in his database.
Hope this help.
Regards,
Matt
I've created a simple Event Subscriber class for Symfony 4. All you need to fix the self-referencing foreign keys issue is to add the below class somewhere to your Symfony 4 project.
This subscriber fires before each Symfony CLI command. In case if the command's name is doctrine:fixtures:load, it performs database purge, but doing SET FOREIGN_KEY_CHECKS = 0 first.
This solves the issue without any other modification.
use Doctrine\Common\DataFixtures\Purger\ORMPurger;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Console\ConsoleEvents;
use Symfony\Component\Console\Event\ConsoleCommandEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class ConsoleCommandEventSubscriber implements EventSubscriberInterface
{
/**
* #var EntityManagerInterface
*/
private $entityManager;
public function __construct(EntityManagerInterface $entityManager)
{
$this->entityManager = $entityManager;
}
public static function getSubscribedEvents()
{
return [
ConsoleEvents::COMMAND => 'onCommand',
];
}
public function onCommand(ConsoleCommandEvent $event)
{
if ($event->getCommand()->getName() === 'doctrine:fixtures:load') {
$this->runCustomTruncate();
}
}
private function runCustomTruncate()
{
$connection = $this->entityManager->getConnection();
$connection->exec('SET FOREIGN_KEY_CHECKS = 0');
$purger = new ORMPurger($this->entityManager);
$purger->setPurgeMode(ORMPurger::PURGE_MODE_DELETE);
$purger->purge();
$connection->exec('SET FOREIGN_KEY_CHECKS = 1');
}
}
Add to your composer.json new section script
"scripts": {
"load-fixtures": [
"bin/console doctrine:database:drop --if-exists --force",
"bin/console doctrine:database:create",
"bin/console doctrine:mi:m",
"bin/console doctrine:fixtures:load"
]
}
Then you can run composer install && composer load-fixtures