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: ~
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 have two MongoDB instances - one slave and one master. There is an Arbiter too.
Basically the setup is the following:
(Image Source: https://docs.mongodb.com/manual/replication/)
In my Symfony application, in config.yml I have this for MongoDB:
# Mongo DB
doctrine_mongodb:
connections:
default:
server: %database_mongodb_access%
options: {}
default_database: %database_mongodb_name%
document_managers:
default:
auto_mapping: true
where %database_mongodb_access% is 'mongodb://mongo:27017'.
How to configure my Symfony/Doctrine application to automatically failover to the slave MongoDB instance if the primary fails, so the application continues working?
It is not clear to me from the docs:
http://symfony.com/doc/master/bundles/DoctrineMongoDBBundle/config.html
It is possible to connect to several mongodb servers on one connection if you are using a replica set by listing all of the servers within the connection string as a comma separated list.
doctrine_mongodb:
# ...
connections:
default:
server: "mongodb://mongodb-01:27017,mongodb-02:27017,mongodb-03:27017"
http://symfony.com/doc/master/bundles/DoctrineMongoDBBundle/config.html#connecting-to-a-pool-of-mongodb-servers-on-1-connection
And check the retry mechanism for failover :
http://symfony.com/doc/master/bundles/DoctrineMongoDBBundle/config.html#retrying-connections-and-queries
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 ;)
tl;dr How does the getManagerForClass() method find out which entity manager is the right one for a specific class?
I've made a generic controller that should be able to handle basic actions for different entities.
I also have connections to two different databases, so I'm using two entity managers.
In my controller, I'm trying to use Doctrine's getManagerForClass() method to find which manager to use for each class, as explained on this blog and this SO answer.
But the method does not seem to differentiate my two entity managers and simply returns the first one in the configuration.
My controller action starts like this:
public function indexAction($namespace, $entityName)
{
$classFullName = "AppBundle:$namespace\\$entityName";
$em = $this->getDoctrine()->getManagerForClass($classFullName);
This is my Doctrine configuration:
dbal:
default_connection: postgres
connections:
postgres:
driver: pdo_pgsql
host: "%database_host%"
port: "%database_port%"
dbname: "%database_name%"
user: "%database_user%"
password: "%database_password%"
charset: UTF8
oracle:
driver: oci8
host: "%oracle_host%"
port: "%oracle_port%"
dbname: "%oracle_name%"
user: "%oracle_user%"
password: "%oracle_password%"
charset: UTF8
orm:
auto_generate_proxy_classes: true
entity_managers:
postgres:
connection: postgres
mappings:
AppBundle:
type: annotation
dir: Entity\Postgres
oracle:
connection: oracle
mappings:
AppBundle:
type: annotation
dir: Entity\Oracle
And my folder structure is as follows:
AppBundle
|___Controller
| |___EntityController.php
|
|___Entity
|___Postgres
| |___SomePostgresBasedEntity.php
|
|___Oracle
|___SomeOracleBasedEntity.php
Now I don't know exactly how the method works, and how it it supposed to know about the mapping if not through the configuration.
But if I call it this way, for example:
$em = $this->getDoctrine()->getManagerForClass("AppBundle:Oracle\\SomeOracleBasedEntity");
...I get the entity manager for Postgres.
But if I simply switch the entity manager configuration, putting the one for oracle first, the previous call works, but the following doesn't:
$em = $this->getDoctrine()->getManagerForClass("AppBundle:Postgres\\SomePostgresBasedEntity");
Update 1
getManagerForClass() cycles through every manager and for each one, checks if the class is "non-transient":
foreach ($this->managers as $id) {
$manager = $this->getService($id);
if (!$manager->getMetadataFactory()->isTransient($class)) {
return $manager;
}
}
This goes all the way down to AnnotationDriver->isTransient(). Here the doc says the following:
A class is non-transient if it is annotated with an annotation from the AnnotationDriver::entityAnnotationClasses.
#Entity seems to be one of those annotations that makes a class non-transient.
But then, how could any of my entities be transient at all? How could the driver distinguish an entity that belongs to a specific manager based solely on its annotations?
I must have missed something in the higher level classes.
Update 2
The method works when using yml mappings.
I kind of expected this behaviour. The difference comes from the implementations of the isTransient() method in the different drivers. The FileDriver implementation of isTransient returns true if the metadata file exists in the dir: directory of the mapping configuration.
I would have expected the AnnotationDriver to search for annotations only in the entities contained in the specified dir: directory, but it seems to ignore that parameter.
Or should I use another one?
At long last, I solved it.
The solution was using the prefix parameter.
entity_managers:
postgres:
connection: postgres
mappings:
AppBundle:
type: annotation
dir: Entity\Postgres
prefix: AppBundle\Entity\Postgres
alias: Postgres
oracle:
connection: oracle
mappings:
AppBundle:
type: annotation
dir: Entity\Oracle
prefix: AppBundle\Entity\Oracle
alias: Oracle
Explanation
The prefix parameter gets passed to the corresponding Entity Manager service, and is added to the entityNamespaces property, which otherwise defaults to AppBundle/Entity.
The Annotation Driver will then check for annotations in that specific namespace, whereas the File Driver checks for existing mapping files in the directory specified through the dir parameter.
(The alias parameter is not mandatory.)
At least, that's how I understand it.
We are using symfony 1.4 on our development machine
traditional way to cache partial in symfony is by editing cache.yml
something:
enabled: true
lifetime: true
this will store cache on the disk
but we want to store cache on memcache instead on disk.
so, the question is how to cache symfony partial in memcache
Symfony partial cache work like all other cache in symfony: it refers to view_cache part of apps/frontend/config/factories.yml.
For example, if you want to store your cache in SQLite database:
all:
view_cache:
class: sfSQLiteCache
param:
database: %SF_TEMPLATE_CACHE_DIR%/cache.db
So if you want to store these information into Memcached, you should use the sfMemcacheCache.class.php class:
all:
view_cache:
class: sfMemcacheCache
param:
servers:
server1:
host: localhost
port: 11211
persistent: true
OR
all:
view_cache:
class: sfMemcacheCache
param:
host: localhost
port: 11211
persistent: true