DQL in config.yml not overwritten in config_test.yml - php

EDIT: Original title" Text environment: "Function "year" does not supported for platform "sqlite""
Incorporating beberlei\DoctrineExtensions in the test environment results in
Uncaught PHP Exception Doctrine\ORM\Query\QueryException: "[Syntax
Error] Function "year" does not supported for platform "sqlite""...
composer show -i includes
beberlei/DoctrineExtensions v1.0.5
The extensions are installed: they exist at "...vendor\beberlei\DoctrineExtensions".
The month() function does NOT throw an error.
config_test.yml
doctrine:
dbal:
default_connection: test
connections:
test:
driver: pdo_sqlite
path: %kernel.cache_dir%/test.sqlite
orm:
dql:
string_functions:
Soundex: Truckee\VolunteerBundle\DQL\Soundex
month: DoctrineExtensions\Query\Sqlite\Month
datetime_functions:
year: DoctrineExtensions\Query\Sqlite\Year
config.yml DQL
dql:
string_functions:
Soundex: Truckee\VolunteerBundle\DQL\Soundex
numeric_functions:
month: Oro\ORM\Query\AST\Functions\SimpleFunction
year: Oro\ORM\Query\AST\Functions\SimpleFunction
function call
public function expiringOppsNotSent()
{
$nextMonth = date_add(new \DateTime(), new \DateInterval('P1M'));
$expiryMonth = date_format($nextMonth, 'm');
$expiryYear = date_format($nextMonth, 'Y');
$qb = $this->getEntityManager()->createQueryBuilder();
$qb->select('o')
->from('TruckeeVolunteerBundle:Opportunity', 'o')
->leftJoin('TruckeeVolunteerBundle:AdminOutbox', 'a', 'WITH', $qb->expr()->eq('a.oppId', 'o'))
->andWhere($qb->expr()->eq('month(o.expireDate)', ':month'))
->andWhere($qb->expr()->eq('year(o.expireDate)', ':year'))
->andWhere('a.id is NULL')
->setParameter(':month', $expiryMonth)
->setParameter(':year', $expiryYear)
;
$notSent = $qb->getQuery()->getResult();
return $notSent;
}
Edit:
The error does not occur if the dql in config.yml (as shown above) are commented out!
Edit #2:
Error persists in functional test with app_dev.php created.
Functional test uses Liip\FunctionalTestBundle\Test\WebTestCase

The correct namespace for the Sqlite Plugin is:
DoctrineExtensions\Query\Sqlite\Year
Update your config.yml to include:
doctrine:
orm:
dql:
datetime_functions:
year: DoctrineExtensions\Query\Sqlite\Year

I wish I had a rational explanation for why the error(s) have disappeared. I experimented with the order and labeling DQL to no effect. I deleted and re-entered the entries and now no errors. Best guess is there was at least one non-display character in an entry. For now all tests pass in SQLite!

Related

Symfony SQLSTATE[42S22]: Column not found

I have an error that i don't understand, few days ago i create a new project for trying resolving this error in a project with fewer files and i solve it, but the solution didn't work in my Real project.
( This error is related to an other question i asked few day ago : The class was not found in the chain configured namespaces, but like i said i solve it so maybe i need to ask a new question ).
I tried to implement two EntityManager in my project for multple database connexion,
and that is the problem, oneof my entityManager searched tables in the wrong place, and don't find theme ... IDK why and most crazy thing it's some function work and other didn't, you'll see that :
In first my doctrine.yaml file :
doctrine:
dbal:
default_connection: default
connections:
default:
# configure these for your database server
url: '%env(resolve:DATABASE_URL)%'
driver: 'pdo_mysql'
server_version: '5.7'
charset: utf8mb4
customer:
# configure these for your database server
url: '%env(resolve:DATABASE_CUSTOMER_URL)%'
driver: 'pdo_mysql'
server_version: '5.7'
charset: utf8mb4
orm:
default_entity_manager: default
entity_managers:
default:
mappings:
Tdsmo:
is_bundle: false
type: annotation
dir: '%kernel.project_dir%/src/Entity/Tdsmo'
prefix: 'App\Entity\Tdsmo'
alias: Tdsmo
customer:
connection: customer
mappings:
Customer:
is_bundle: false
type: annotation
dir: '%kernel.project_dir%/src/Entity/Customer'
prefix: 'App\Entity\Customer'
alias: Customer
And know an exemple of some function that i can use in my controller :
// this one work, but his not the default connexion ..
// return all agent in agentCustomer that is in the second database.
$agentCustomers = $this->getDoctrine()
->getRepository(AgentCustomer::class, "customer")
->findAll()
;
// And this one, that is the default connexion, didn't work like this same for 'AgentRepository $agentRepository' that can be implemented in the method and called after for ->findAll()
// return an error
$agents = $this->getDoctrine()
->getRepository(Agent::class, "default")
->findAll()
;
BUT This shit work and return a array with all column and values :
$connexion = $this->getDoctrine()->getConnection('default')
$agentsFetch = $connexion->fetchAll("SELECT * from agent");
But i can't use the fetch method 'cause if i do in my template i need to replace all agent.firstName by agent.first_name for example, Furthermore i need to understand why one method work but not the other ...
Finally, the full error is :
An exception occurred while executing 'SELECT t0.id AS id_1, t0.email AS email_2, t0.roles AS roles_3, t0.password AS password_4, t0.firstName AS firstName_5, t0.lastName AS lastName_6, t0.registeredAt AS registeredAt_7, t0.telephone AS telephone_8, t0.fonction_id AS fonction_id_9, t0.subdivision_id AS subdivision_id_10, t0.section_id AS section_id_11 FROM Agent t0':
SQLSTATE[42S22]: Column not found: 1054 Champ 't0.firstName' inconnu dans field list
Thank you for your help !
OKAY
Thanks to Nicolai, he help me found the real problem, it was because of the naming strategy !
I don't know why but if it is not explicitly defined in the context of the use of several entityManager doctrine will generate the tables in the database in camelCase, instead of the snake_case (underscore).In any case that's what was causing me problem
So it must be specified with this line :
naming_strategy: doctrine.orm.naming_strategy.underscore
For where i found to specify 'underscore' :
How to configure naming strategy in Doctrine 2
And the doc For thoses who want :
https://symfony.com/doc/current/bundles/DoctrineBundle/configuration.html#configuration-overview

Symfony4 SQLite in memory for testing can't get it to work

I'm trying to use SQLite in memory db to run tests in Symfony 4, but I cant get it to work.
My config looks like this:
doctrine:
dbal:
default_connection: default
connections:
default:
driver: 'pdo_sqlite'
url: ':memory:'
memory: true
#charset: utf8mb4
#default_table_options:
# charset: utf8mb4
# collate: utf8mb4_unicode_ci
[EDITED on 2019-01-27]
In my case,
config/packages/test/doctrine.yaml :
doctrine:
dbal:
driver: pdo_sqlite
memory: true
charset: UTF8
But, for the fonctionnal testing, you need to create dB ( db in memory= not created and not persisted !)
Exemple :
<?php
// tests/Repository/MyRepositoryTest.php
namespace App\Tests\Controller;
use App\Repository\MyController;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
class MyRepositoryTest extend WebTestCase {
public function testSearch()
{
$container = self::$kernel->getContainer();
$entityManager = $container->get('doctrine')->getManager();
// Runs the schema update tool using our entity metadata
$metadatas = $entityManager->getMetadataFactory()->getAllMetadata();
$schemaTool = new SchemaTool($entityManager);
$schemaTool->updateSchema($metadatas);
// #TODO : now you can test !
}
}

How can I output the date with ConsoleLogger?

I have a console command and I'm initializing ConsoleLogger in the initialize method:
$this->logger = new ConsoleLogger($output);
But the date is not outputted in the console. Is it possible to prefix the output with the datetime?
I know this is an old topic, but it's the first result when you google for "symfony console log date", that's why I'd like to share what I found when trying to solve this.
According to the Symfony docs, you can specify a custom formatter (found in old Symfony 2.6 docs)
https://symfony.com/doc/2.6//cookbook/logging/monolog_console.html
# app/config/services.yml
services:
my_formatter:
class: Symfony\Bridge\Monolog\Formatter\ConsoleFormatter
arguments:
# NOTE
# The placeholder to use in the `format` is enclosed in single `%` (ex.: `%datetime%`)
# However, here we escape `%` characters so Symfony will not interpret them as service parameters.
# https://symfony.com/doc/current/configuration.html#configuration-parameters
- "[%%datetime%%] %%start_tag%%%%message%%%%end_tag%% (%%level_name%%) %%context%% %%extra%%\n"
But that's not doing the trick already.
Taking a look at the source of ConsoleFormatter, I found this:
const SIMPLE_FORMAT = "%datetime% %start_tag%%level_name%%end_tag% <comment>[%channel%]</> %message%%context%%extra%\n";
const SIMPLE_DATE = 'H:i:s';
So there date is set as H:i:s here.
Luckily this date can be overwritten with the date_format option.
This is how I solved it now:
In my monolog.yaml I added the formatter
console:
type: console
process_psr_3_messages: false
channels: ["!event", "!doctrine", "!console"]
verbosity_levels:
VERBOSITY_NORMAL: DEBUG
formatter: console_log_formatter
And in services.yml I added the custom formatter with my date_format set
console_log_formatter:
class: Symfony\Bridge\Monolog\Formatter\ConsoleFormatter
arguments:
- date_format: 'Y-m-d H:i:s'
maybe you need to define the verbosity level
$this->consoleLogger = new ConsoleLogger($output, [LogLevel::INFO => OutputInterface::VERBOSITY_NORMAL]);
Hope this is what you are looking for

Is it possible to use two diffrent document managers with different databases for the same bundle in Symfony?

My goal is to have two different document managers connected to different databases that share the same database models.
I have heavily changed my database model and I would like to write a custom migration script that retrieves objects from the old model reads its values and then creates a new object on the new schema with the information of the old object.
I have found a related stackoverflow question here:
Working with two entity managers in the same bundle in Symfony2
Howewer, this solution suggests to use different prefixes for each database and it stores the classes for the data model in different folders:
doctrine:
dbal:
default_connection: default
connections:
default:
driver: %database_driver%
host: %database_host%
port: %database_port%
dbname: %database_name%
user: %database_user%
password: %database_password%
charset: UTF8
second:
driver: %database_sqlite_driver%
host: ~
port: ~
dbname: %database_sqlite_shop_name%
path: %database_sqlite_shop_name%
user: ~
password: ~
charset: UTF8
orm:
auto_generate_proxy_classes: %kernel.debug%
default_entity_manager: default
entity_managers:
default:
connection: default
mappings:
YourBundle:
# you must specify the type
type: "annotation"
# The directory for entity (relative to bundle path)
dir: "Entity/FirstDb"
#the prefix
prefix: "Your\Bundle\Entity\FirstDb"
shop:
connection: second
mappings:
YourBundle:
type: "annotation"
#here the second path where entity for the connection stand
dir: "Entity/SecondDb"
#the prefix
prefix: "Your\Bundle\Entity\SecondDb"
I would really just like to have two different document manager objects that share the same models in the same folder but are connected to diffrent databases. Is this possible?
I found out that it is indeed possible to be connected to different databases in the same Symfony Bundle. This answer led me to a possible solution:
https://stackoverflow.com/a/15110867/2174832
#services.yml
acme_app.dynamic_connection:
class: %acme.dynamic_doctrine_connection.class%
calls:
- [setDoctrineConnection, #doctrine.dbal.default_connection]]
<?php
namespace Acme\Bundle\AppBundle;
use Doctrine\DBAL\Connection;
use Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException;
use Exception;
class DynamicDoctrineConnection
{
/**
* #var Connection
*/
private $connection;
/**
* Sets the DB Name prefix to use when selecting the database to connect to
*
* #param Connection $connection
* #return SiteDbConnection $this
*/
public function setDoctrineConnection(Connection $connection)
{
$this->connection = $connection;
return $this;
}
public function setUpAppConnection()
{
if ($this->request->attributes->has('appId')) {
$connection = $this->connection;
$params = $this->connection->getParams();
// we also check if the current connection needs to be closed based on various things
// have left that part in for information here
// $appId changed from that in the connection?
// if ($connection->isConnected()) {
// $connection->close();
// }
// Set default DB connection using appId
//$params['host'] = $someHost;
$params['dbname'] = 'Acme_App'.$this->request->attributes->get('appId');
// Set up the parameters for the parent
$connection->__construct(
$params, $connection->getDriver(), $connection->getConfiguration(),
$connection->getEventManager()
);
try {
$connection->connect();
} catch (Exception $e) {
// log and handle exception
}
}
return $this;
}
}
With the solution above one can write a service that can be called to change the database that the current entity manager is connected to to a different database.
Unfortunately the solution above only works for the PDO driver (Mysql).
Since our technology stack includes mongodb and we use the doctrine-mongodb bundle I had to look for a differnt solution.
The doctrine-mongodb documentation has a section about setting up a custom document manager here:
http://docs.doctrine-project.org/projects/doctrine-mongodb-odm/en/latest/reference/introduction.html
I was unable to get the right doctrine-mongodb odm document mappings to work with the instructions in the doc and therefore the only solution for me was to create a simple PHP mongoclient connection:
$mongo = new \Mongo('mongodb://localhost:27017');
$legacyDbDocumentMangager = $mongo->selectDB('backed_up_prod_db');
$legacyUserCollection = $legacyDbDocumentMangager->selectCollection('User');
$user = $legacyUserCollection->findOne(array('email' => 'matyas#stackoverflow.com'));
The only differnce between this simple php mongodb driver and the doctrine-mongodb odm is that the results of the queries of this driver are associative arrays and the results of the doctrine-mongodb odm diver are objects.
I hope this information is useful to someone.

Symfony2 Doctrine Metadata Cache with Redis Issue

I'm trying to use Redis as a driver for caching doctrine metadata, query and results. Follwing is my configuration.
auto_generate_proxy_classes: "%kernel.debug%"
naming_strategy: doctrine.orm.naming_strategy.underscore
auto_mapping: true
result_cache_driver:
type: redis
host: %redis_host%
instance_class: Redis
query_cache_driver: redis
#metadata_cache_driver: redis
When I remove the comment from line #metadata_cache_driver: redis, I get an error running a test I have with following error.
TypeError: Argument 1 passed to Doctrine\ORM\Mapping\ClassMetadataFactory::wakeupReflection() must implement interface Doctrine\Common\Persistence\Mapping\ClassMetadata, string given, called in vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/AbstractClassMetadataFactory.php on line 214
My Functional Test looks like Following:
public function testX()
{
//The data in prepared in setup..
$param1 = 'test-id';
$param2 = 'test-key';
$result = $this->em->getRepository('MyBundle:Test')
->findOneByXX($param1, $param2);
$this->assertTrue($result instanceof Test);
}
And My Query looks like following:
$qb->select('c')
->from('MyBundle:Test', 'c')
->where('c.id = :id')
->andWhere('c.key = :key')
->setParameter('id', $id)
->setParameter('key', $key);
$query = $qb->getQuery()
->useResultCache(true);
return $query->getOneOrNullResult();
Do I need additional configuration for Redis? Any Help would be appreciated??
I believe to resolve this you need to set the serializer for redis, the default serializer is probably not aware of the the PHP classes and when the object is removed from cache, and unserialized, it is not the same type as it was prior to serialization.
$redis->setOption(\Redis::OPT_SERIALIZER, \Redis::SERIALIZER_PHP);
For you case you will probably need to set the configuration option as a part of the driver configuration.

Categories