Recently I am upgrading my application from Symfony 3.4 to Symfony 4.2. I am encountering error telling that read error on connection .
Here is the stack trace:
at var/cache/dev/ContainerRUEbk9e/Redis_ca5fc0f.php:312
at Redis->get('DoctrineNamespaceCacheKey[]')
(var/cache/dev/ContainerRUEbk9e/Redis_ca5fc0f.php:312)
at Redis_ca5fc0f->get('DoctrineNamespaceCacheKey[]')
(vendor/doctrine/cache/lib/Doctrine/Common/Cache/RedisCache.php:47)
at Doctrine\Common\Cache\RedisCache->doFetch('DoctrineNamespaceCacheKey[]')
(vendor/doctrine/cache/lib/Doctrine/Common/Cache/CacheProvider.php:200)
at Doctrine\Common\Cache\CacheProvider->getNamespaceVersion()
(vendor/doctrine/cache/lib/Doctrine/Common/Cache/CacheProvider.php:177)
at Doctrine\Common\Cache\CacheProvider->getNamespacedId('9f7b27184e58ac025013b8c22fbdfa8a')
(vendor/doctrine/cache/lib/Doctrine/Common/Cache/CacheProvider.php:60)
at Doctrine\Common\Cache\CacheProvider->fetch('9f7b27184e58ac025013b8c22fbdfa8a')
(vendor/doctrine/orm/lib/Doctrine/ORM/Query.php:271)
at Doctrine\ORM\Query->_parse()
(vendor/doctrine/orm/lib/Doctrine/ORM/Query.php:295)
at Doctrine\ORM\Query->_doExecute()
(vendor/doctrine/orm/lib/Doctrine/ORM/AbstractQuery.php:967)
at Doctrine\ORM\AbstractQuery->executeIgnoreQueryCache(null, 1)
(vendor/doctrine/orm/lib/Doctrine/ORM/AbstractQuery.php:922)
at Doctrine\ORM\AbstractQuery->execute(null, 1)
(vendor/doctrine/orm/lib/Doctrine/ORM/AbstractQuery.php:726)
at Doctrine\ORM\AbstractQuery->getResult()
(src/Acme/AcmeBundle/Controller/AcmeController.php:1461)
at Acme\AcmeBundle\Controller\AcmeController->acmeAction(object(Request))
(vendor/symfony/symfony/src/Symfony/Component/HttpKernel/HttpKernel.php:150)
at Symfony\Component\HttpKernel\HttpKernel->handleRaw(object(Request), 1)
(vendor/symfony/symfony/src/Symfony/Component/HttpKernel/HttpKernel.php:67)
at Symfony\Component\HttpKernel\HttpKernel->handle(object(Request), 1, true)
(vendor/symfony/symfony/src/Symfony/Component/HttpKernel/Kernel.php:198)
at Symfony\Component\HttpKernel\Kernel->handle(object(Request))
(public/app_dev.php:35)
at runSymfony()
(public/app_dev.php:39)
at require('/var/www/html/project/Website/public/app_dev.php')
(vendor/symfony/symfony/src/Symfony/Bundle/WebServerBundle/Resources/router.php:42)
Please look into the problem
this might be helpful. Earlier my configurations used to be this:
snc_redis:
clients:
default:
type: predis
alias: default
dsn: "%redis_dsn%"
options:
read_write_timeout: "%redis_read_write_timeout%"
session:
type: phpredis
alias: session
dsn: "%redis_dsn%"
options:
read_write_timeout: "%redis_read_write_timeout%"
doctrine:
type: phpredis
alias: doctrine
dsn: "%redis_dsn%"
options:
read_write_timeout: "%redis_read_write_timeout%"
session:
client: session
prefix: session:main
doctrine:
metadata_cache:
client: doctrine
entity_manager: default # the name of your entity_manager connection
document_manager: default # the name of your document_manager connection
namespace: "%kernel.root_dir%"
result_cache:
client: doctrine
entity_manager: [default, read] # you may specify multiple entity_managers
query_cache:
client: doctrine
entity_manager: default
changed to the following
snc_redis:
clients:
default:
type: predis
alias: default
dsn: "%redis_dsn%"
options:
read_write_timeout: "%redis_read_write_timeout%"
session:
type: predis
alias: session
dsn: "%redis_dsn%"
options:
read_write_timeout: "%redis_read_write_timeout%"
doctrine:
type: predis
alias: doctrine
dsn: "%redis_dsn%"
options:
read_write_timeout: "%redis_read_write_timeout%"
session:
client: session
prefix: session:main
doctrine:
metadata_cache:
client: doctrine
entity_manager: default # the name of your entity_manager connection
document_manager: default # the name of your document_manager connection
namespace: "%kernel.root_dir%"
result_cache:
client: doctrine
entity_manager: [default, read] # you may specify multiple entity_managers
query_cache:
client: doctrine
entity_manager: default
Might help others.
Related
In my bundle i create a separate database connection and an EntityManager for it. Everything works fine, except those two things don't show up in the development profiler. There is only the default EntityManager and the default connection.
So basically i created 3 new service definitions for an Doctrine\Common\EventManager, an Doctrine\DBAL\Connection and an Doctrine\ORM\EntityManager. I've already tried to add these new service definition to the ContainerBuilder with the same naming convention which is used by the doctrine bridge, but they still won't show up in the profiler. The connection works fine, but i want debug it with and integrate it in the Symfony lifecycle.
The question is:
What is the best practice to create a separate database connection via Doctrine inside of a Symfony Bundle if the Symfony application is only configured to support one connection?
I believe you should take a look at this doc. They described there how to add another EntityManager, which mean another connection. First step is to create configuration.
Especialy take a look at doctrine.yaml configuration:
# config/packages/doctrine.yaml
doctrine:
doctrine:
dbal:
default_connection: default
connections:
default:
# configure these for your database server
url: '%env(DATABASE_URL)%'
driver: 'pdo_mysql'
server_version: '5.7'
charset: utf8mb4
customer:
# configure these for your database server
url: '%env(DATABASE_CUSTOMER_URL)%'
driver: 'pdo_mysql'
server_version: '5.7'
charset: utf8mb4
orm:
default_entity_manager: default
entity_managers:
default:
connection: default
mappings:
Main:
is_bundle: false
type: annotation
dir: '%kernel.project_dir%/src/Entity/Main'
prefix: 'App\Entity\Main'
alias: Main
customer:
connection: customer
mappings:
Customer:
is_bundle: false
type: annotation
dir: '%kernel.project_dir%/src/Entity/Customer'
prefix: 'App\Entity\Customer'
alias: Customer
Above are two entity managers, 'default' and 'customer'. There are also two cennections, one for each manager.
If configuration is valid you will have access to those managers by passing its names to 'getManager' method.
$entityManager = $this->getDoctrine()->getManager('default');
$customerEntityManager = $this->getDoctrine()->getManager('customer');
If you cant edit configuration:
What what about creating custom class (Manager or something) in which you will manually create connection. Take a look at this, it should help you.
getting-a-connection
I'm about to embark on using RDS with a master read/write and slave read-only setup.
I've read about the Doctrine MasterSlaveConnection type.
However, there will be some endpoints I create that I would like to use the read-only replica (most of my GET endpoints) and some will need to write data (PUT, PATCH, DELETE endpoints).
I'm also using API Platform.
What is the best way of achieving this in Symfony 4 and Doctrine 2?
What I have done in the past is to just use different connections.
Something like:
doctrine:
dbal:
default_connection: default
connections:
default:
# This is your Master
url: '%env(DATABASE_URL)%'
driver: 'pdo_mysql'
server_version: '5.7'
charset: utf8mb4
slave:
# This would be the slave
url: '%env(DATABASE_SLAVE_URL)%'
driver: 'pdo_mysql'
server_version: '5.7'
charset: utf8mb4
orm:
default_entity_manager: default
entity_managers:
default:
connection: default
mappings:
Main:
is_bundle: false
type: annotation
dir: '%kernel.project_dir%/src/Entity'
prefix: 'App\Entity'
alias: Main
slave:
connection: slave
mappings:
Main:
is_bundle: false
type: annotation
dir: '%kernel.project_dir%/src/Entity'
prefix: 'App\Entity'
alias: Main
https://symfony.com/doc/current/doctrine/multiple_entity_managers.html
Then in your controllers or business logic you can either choose to use the default entity manager:
// Controller
$this->getDoctrine()->getEntityManager();
Or you can get the slave connection:
// Controller
$this->getDoctrine()->getEntityManager('slave');
If you need this to work just on all requests without having to create special actions for everything then your best bet is to decorate the Collection and Item DataProviders for doctrine.
https://symfony.com/doc/current/service_container/service_decoration.html
https://github.com/api-platform/core/blob/master/src/Bridge/Doctrine/Orm/CollectionDataProvider.php
https://github.com/api-platform/core/blob/master/src/Bridge/Doctrine/Orm/ItemDataProvider.php
So basically you need to change what manager is chosen based on the $opperationName something like:
if($opperationName === 'GET'){
$manager = $this->managerRegistry->getManager('slave');
} else {
$manager = $this->managerRegistry->getManager();
}
You actually don't need to setup multiple entity managers, nor is it preferable as handling one entity with multiple entity managers is hard.
Using Doctrine 2.2, you can setup slaves/replicas directly from configuration without needing an extra entity manager:
See the config reference here:
https://www.doctrine-project.org/projects/doctrine-bundle/en/2.2/configuration.html#configuration-overview
Example:
doctrine:
dbal:
default_connection: default
connections:
default:
dbname: '%env(DATABASE_DBNAME)%'
user: '%env(DATABASE_USER)%'
password: '%env(DATABASE_PASSWORD)%'
host: '%env(DATABASE_HOST)%'
driver: 'pdo_mysql'
server_version: '5.7'
charset: utf8mb4
default_table_options:
charset: utf8mb4
collate: utf8mb4_unicode_ci
slaves:
ro_replica:
dbname: '%env(REPLICA_DBNAME)%'
user: '%env(REPLICA_USER)%'
password: '%env(REPLICA_PASSWORD)%'
host: '%env(REPLICA_HOST)%'
charset: utf8mb4
Thank you #Chase for the solution. You have made my day. Although it works for me in 'dev' environment I had a problem when switched to 'prod'. I was getting an error that an Entity can not be found. The solution came from this post - thanks #xabbuh. Basically I had to add default_entity_manager: name_of_default_em to doctrine.yml. Here is the copy of the code:
# config/packages/prod/doctrine.yaml
doctrine:
orm:
default_entity_manager: BOE <- add this line to let know prod about default em
auto_generate_proxy_classes: false
metadata_cache_driver:
type: service
id: doctrine.system_cache_provider
query_cache_driver:
type: service
id: doctrine.system_cache_provider
result_cache_driver:
type: service
id: doctrine.result_cache_provider
# ...
A symfony noob here. Been trying since morning to map entity/s of the database using Doctrine via console throws up no primary key error. The mysql server is a remote one which I unfortunately only have read access and I am not able to create a primary key. I did see a few questions on SO with the exact same issue but they were unanswered and old.
I tried https://medium.com/#joaoneto/solves-doctrine-orm-error-with-tables-without-primary-key-on-mysql-when-mapping-the-database-1ce740610b51
but again it throws up error regarding empty columns.
Call to a member function getColumns() on null
My doctrine.yaml. Obviously I altered the connection details.
doctrine:
dbal:
default_connection: default
connections:
# configure these for your database server
default:
driver: 'pdo_mysql'
host: 'localhost'
port: '3306'
dbname: 'symfony_test_db'
user: 'root'
password: ''
charset: utf8mb4
customer:
driver: 'pdo_mysql'
host: 'xxx.xxx.xx.xxx'
port: '3306'
dbname: 'sg3_symfony_db'
user: 'sguser'
password: 'password'
charset: UTF8
backoffice:
driver: 'pdo_mysql'
host: 'localhost'
port: '3306'
dbname: 'back_office'
user: 'backoffice_user'
password: 'password'
charset: UTF8
one:
driver: 'pdo_mysql'
host: 'xxx.xxx.xx.xxx'
port: '3306'
dbname: 'one_db'
user: 'one_user'
password: 'password'
charset: UTF8
staging:
driver: 'pdo_mysql'
host: 'xxx.xxx.xx.xxx'
port: '3306'
dbname: 'staging'
user: 'staginguser'
password: 'password'
charset: UTF8
# With Symfony 3.3, remove the `resolve:` prefix
#url: '%env(resolve:DATABASE_URL)%'
orm:
default_entity_manager: default
entity_managers:
default:
connection: default
#auto_mapping: true
mappings:
Main:
is_bundle: false
type: annotation
dir: '%kernel.project_dir%/src/Entity/Main'
prefix: 'App\Entity\Main'
alias: Main
customer:
connection: customer
mappings:
Customer:
is_bundle: false
type: annotation
dir: '%kernel.project_dir%/src/Entity/Customer'
prefix: 'App\Entity\Customer'
alias: Customer
backoffice:
connection: backoffice
mappings:
Backoffice:
is_bundle: false
type: annotation
dir: '%kernel.project_dir%/src/Entity/Backoffice'
prefix: 'App\Entity\Backoffice'
alias: Backoffice
one:
connection: mt4
mappings:
One:
is_bundle: false
type: annotation
dir: '%kernel.project_dir%/src/Entity/One'
prefix: 'App\Entity\One'
alias: One
staging:
connection: staging
mappings:
staging:
is_bundle: false
type: annotation
dir: '%kernel.project_dir%/src/Entity/Staging'
prefix: 'App\Entity\Staging'
alias: Staging
CLI command I use to map but fails.
php bin/console doctrine:mapping:convert --from-database annotation --force --em=one ./src/Entity/One/ --verbose
In this case, sometimes you need to walk around.
This error:
Table ____ has no primary key. Doctrine does not support reverse
engineering from tables that don’t have a primary key.
So.
Doctrine can not work on tables that have no primary key.
In MySQL, create tables without PK will always be a bad idea, but, in some cases (or legacy systems) that not have PKs on some tables, you still can use Doctrine as ORM.
However, by default (and I believe this will not change) if your database has tables without primary key Mapping simply will not work.
The more fast way to solve this is override the vendor class DatabaseDriver, in the namespace:
namespace Doctrine\ORM\Mapping\Driver;
On line 289, change:
if ( ! $table->hasPrimaryKey()) {
continue;
// throw new MappingException(
// "Table " . $table->getName() . " has no primary key. Doctrine does not ".
// "support reverse engineering from tables that don't have a primary key."
// );
}
To avoid any future problems, after mapping your database, return the settings to avoid any problems later.
Good luck!
Reference: Solves Doctrine ORM Error with tables without Primary Key on MySQL when mapping the database.
Not a very clean solution but for the moment I managed to do it by, exporting the schema of tables I need and recreating them on my local server. Forcing Pk's on the tables that did not have PK defined. This created entity class files instantly and worked like a charm.
I'm using SncRedisBundle with success locally but can't have it work using heroku.
Here is my config :
#config.yml
imports:
- { resource: heroku/parameters_heroku.php } #heroku cloud provider configuration's
snc_redis:
clients:
default:
type: predis
alias: default
dsn: "%redis_url%"
cache:
type: predis
alias: cache
dsn: "%redis_url%&database=1"
logging: false
session:
type: predis
alias: session
dsn: "%redis_url%&database=2"
task:
type: predis
alias: task
dsn: "%redis_url%&database=3"
doctrine:
type: predis
alias: doctrine
dsn: "%redis_url%&database=4"
session:
client: session
ttl: 10800 #le session expirera apres 3 heures
doctrine:
metadata_cache:
client: doctrine
entity_manager: default # the name of your entity_manager connection
document_manager: default # the name of your document_manager connection
result_cache:
client: doctrine
entity_manager: [default] # you may specify multiple entity_managers
query_cache:
client: doctrine
entity_manager: default
second_level_cache:
client: doctrine
entity_manager: default
monolog:
client: cache
key: monolog
swiftmailer:
client: default
key: swiftmailer
#heroku/parameters_heroku.php
<?php
$is_heroku = getenv("IS_HEROKU");//manually added : heroku config:set IS_HEROKU=1
if (!$is_heroku) {
return;
}
if ($redisUrl = getenv('REDIS_URL')) {
$aParsedRedisUrl = parse_url($redisUrl);
$redisConstructedDsn = 'redis://'.$aParsedRedisUrl['host'].':'.$aParsedRedisUrl['port'].$aParsedRedisUrl['path'].'?'.'password='.$aParsedRedisUrl['pass'].($aParsedRedisUrl['query'] ? '&'.$aParsedRedisUrl['query'] : ''); // le user ne sert pas : .'&user='.$aParsedRedisUrl['user']
$container->setParameter('redis_url', $redisConstructedDsn);
}
if I dump $redisConstructedDsn during the heroku build process, I've got something like that : redis://xxxxxx.compute-1.amazonaws.com:18839?password=foobar, so, it seem pretty compatible with predis doc
but the composer construction fails with a
remote: [Predis\Response\ServerException] remote:
NOAUTH Authentication required.
I can't find what I did wrong
problem solved :
initially I used this kind of syntax : dsn: "%redis_url%/3" wich is incompatible with heroku.
When I changed it to an acceptable format : "%redis_url%?database=3", I added bug elsewhere, so here is the simple correction in heroku/parameters_heroku.php
if ($redisUrl = getenv('REDIS_URL')) {
$container->setParameter('redis_url', $redisUrl);
}
some resources on the internet will say that predis isn't compatible with heroku's format, but they are old&wrong ;)
I start using Redis on me project (php-redis). Is a Symfony2 project and i found the:
https://github.com/snc/SncRedisBundle
I follow the installation process and i configured:
Some clients to store no-sql data and cache
Sessions storage
Doctrine metada, result and query cache
I create a new entity in a bundle and i fail because i create it at yml and i have all others with annotation system, so i delete yml format and create the annotation.
Every change i make on the annotation class (change the table name for example), is not affecting the schema or the database, even i recreate the database or try to execute cache:clear with all the options.
If i just comment the redis doctrine configuration lines, it works and i can see the changes on the schema.
Im maybe forgetting something, or i cant really find how to clean that doctrine redis cache.
¿I have to manually clean any position on the redis client use for caching?
Here is the configuration:
#Snc Redis Bundle
snc_redis:
clients:
d2a:
type: phpredis
alias: d2a
dsn: redis://localhost/1
cache:
type: phpredis
alias: cache
dsn: redis://localhost
logging: true
session:
client: d2a
prefix: redis_session
doctrine:
metadata_cache:
client: cache
entity_manager: default # the name of your entity_manager connection
document_manager: default # the name of your document_manager connection
result_cache:
client: cache
entity_manager: [default, read] # you may specify multiple entity_managers
query_cache:
client: cache
entity_manager: default
The easiest way but not the best one is to flush redis db with doctrine cache. Run
php app/console redis:flushdb --client=cache
(Not tested!) Another way is to setup doctrine metadata cache in doctrine config http://symfony.com/doc/current/reference/configuration/doctrine.html#caching-drivers
orm:
entity_managers:
# A collection of different named entity managers (e.g. some_em, another_em)
some_em:
metadata_cache_driver:
type: array # Required
host: ~
port: ~
instance_class: ~
class: ~