I'm using Doctrine 2 and I want to generate an ORM of my database but I don't want select all tables of the db.
For example, in this db :
Table 1 has no primary key
Table 2 is normal
I want to choose ONLY Table 2 with this command:
doctrine:mapping:convert --from-database yml ./src/Application/TestBundle/Resources/config/doctrine/metadata/orm --filter="Table2"
I have an error :
Table Table_1 has no primary key. Doctrine does not support reverse engineering from tables that don't have a primary key.
Ok I know , but I don't want my table 1 in my ORM. When my table 1 has primary key i can filter the tables. I've seen
Generating a single Entity from existing database using symfony2 and doctrine, but it doesn't work.
Ignoring the table was the solution:
doctrine:
dbal:
schema_filter: ~^(?!Table1)~
If you use Doctrine2 without Symfony then you should add this line to your bootstrap:
// With this expression all tables prefixed with Table1 will ignored by the schema tool.
$entityManager->getConnection()->getConfiguration()->setFilterSchemaAssetsExpression("~^(?!Table1)~");
the whole bootstrap looks like
<?php
// bootstrap.php
use Doctrine\ORM\Tools\Setup;
use Doctrine\ORM\EntityManager;
// Include Composer Autoload (relative to project root).
require_once "vendor/autoload.php";
// Create a simple "default" Doctrine ORM configuration for Annotations
$isDevMode = true;
$paths = array(__DIR__."/doctrine/entities");
$config = Setup::createAnnotationMetadataConfiguration($paths, $isDevMode);
//$config = Setup::createYAMLMetadataConfiguration(array(__DIR__."/doctrine/yaml"), $isDevMode);
// the connection configuration
$dbParams = array(
'driver' => 'pdo_mysql',
'user' => 'username',
'password' => 'password',
'dbname' => 'database',
);
/** #var $entityManager \Doctrine\ORM\EntityManager */
$entityManager = EntityManager::create($dbParams, $config);
// Set the other connections parameters
$conn = $entityManager->getConnection();
$platform = $conn->getDatabasePlatform();
$platform->registerDoctrineTypeMapping('enum', 'string');
// With this expression all tables prefixed with t_ will ignored by the schema tool.
$conn->getConfiguration()->setFilterSchemaAssetsExpression("~^(?!t__)~");
In recent versions of the Doctrine bundle one has to configure schema filter on the connection level, so:
doctrine:
dbal:
default_connection: default
connections:
default: # <- your connection name
url: '%env(DATABASE_URL)%'
schema_filter: '#^(?!table_to_exclude)#'
Doctrine first validates your tables and only then executes the command.
So you should always have valid DB schema in order to make any operations with it.
Related
I'm working on a Symfony 4 Web Project, and I have a database for every Client, so, in every request I have to connect to a database based on client id.
How to use doctrine to connect to a database manually ?
MyController:
/**
* #Route("/api/log", name="log", methods={"GET"})
*/
public function log(Request $request)
{
$this->denyAccessUnlessGranted(['ROLE_CLIENT','ROLE_ADMIN']);
$clientId = $request->query->get('client_id');
$dbName = 'project_'.$clientId;
//I have database credentials: $host,$port,$username,$password & $dbName:
$this->getDoctrine()->........
You can work with multiple connections and managers. Here the official symfony documentation.
So, if you could change manually config/packages/doctrine.yaml, you will solve your problem.
Another way, is to work with entity manager directly:
use Doctrine\ORM\Tools\Setup;
use Doctrine\ORM\EntityManager;
$paths = array('/path/to/entity/mapping/files');
$config = Setup::createAnnotationMetadataConfiguration($paths);
$dbParams = array('driver' => 'pdo_sqlite', 'memory' => true);
$entityManager = EntityManager::create($dbParams, $config);
Entity Manager API documenation
If I want to translate content in symfony, I will use the translator as it is described in the book:
$translated = $this->get('translator')->trans('Symfony2 is great');
But, if this translations are already existing in a database, how can I access this?
The db looks like
ID | locale | type | field | content
1 | en | message| staff.delete | delete this user?
I wil have to tell the translator where he can get the translation information. Cann you help me with a good tutorial or tipps an tricks?
According to docs you need to register a service in order to load translations from other source like from database
You can also store translations in a database, or any other storage by
providing a custom class implementing the LoaderInterface interface.
See the translation.loader tag for more information.Reference
What i have done,i have a translation bundle where my translation entity resides so i have registered a service in config.yml and passed doctrine manager #doctrine.orm.entity_manager in order to get data from entity
services:
translation.loader.db:
class: Namespace\TranslationBundle\Loader\DBLoader
arguments: [#doctrine.orm.entity_manager]
tags:
- { name: translation.loader, alias: db}
In DBLoader class i have fetched translations from database and sets as mentioned in docs translation.loader
My Loader class
namespace YourNamespace\TranslationBundle\Loader;
use Symfony\Component\Translation\Loader\LoaderInterface;
use Symfony\Component\Translation\MessageCatalogue;
use Doctrine\ORM\EntityManager;
class DBLoader implements LoaderInterface{
private $transaltionRepository;
private $languageRepository;
/**
* #param EntityManager $entityManager
*/
public function __construct(EntityManager $entityManager){
$this->transaltionRepository = $entityManager->getRepository("YourNamespaceTranslationBundle:LanguageTranslation");
$this->languageRepository = $entityManager->getRepository("YourNamespaceTranslationBundle:Language");
}
function load($resource, $locale, $domain = 'messages'){
//Load on the db for the specified local
$language = $this->languageRepository->findOneBy( array('locale' => $locale));
$translations = $this->transaltionRepository->getTranslations($language, $domain);
$catalogue = new MessageCatalogue($locale);
/**#var $translation YourNamespace\TranslationBundle\Entity\LanguageTranslation */
foreach($translations as $translation){
$catalogue->set($translation->getLanguageToken(), $translation->getTranslation(), $domain);
}
return $catalogue;
}
}
Note: Each time you create a new translation resource (or install a bundle
that includes a translation resource), be sure to clear your cache so
that Symfony can discover the new translation resources:
php app/console cache:clear
I am looking for a good solution to on-the-fly connection of databases within Symfony utilizing Doctrine for entity management.
The scenario I have is that all inbound users to our service will be visiting *.website.com addresses, like client1.website.com.
We would like to use one Doctrine entity for the Client table to then look up their database credentials based on the URL of their account on the fly.
So far I have found the following topics here on stackoverflow that discuss dynamically changing the database credentials--but no clear workable solutions.
I'd like to propose collaborating to put together a working solution, and I'll put together a blog/tutorial post for other folks looking to modify database connection parameters within Symfony.
Here are some related posts:
Dynamic database connection symfony2
Symfony2, Dynamic DB Connection/Early override of Doctrine Service
Thanks!
If $em is existing entity manager and you want to reuse it's configuration, you can use this:
$conn = array(
'driver' => 'pdo_mysql',
'user' => 'root',
'password' => '',
'dbname' => 'foo'
);
$new = \Doctrine\ORM\EntityManager::create(
$conn,
$em->getConfiguration(),
$em->getEventManager()
);
I needed to do something similar - runtime discovery of an available database server. I did it by overriding the doctrine.dbal.connection_factory.class parameter and substituting my own derivation of the Doctrine bundle's ConnectionFactory class
My services.yml provides the parameter, pointing at my custom class
parameters:
doctrine.dbal.connection_factory.class: Path\To\Class\CustomConnectionFactory
Then fill in your discovery logic in Path\To\Class\CustomConnectionFactory.php
<?php
namespace Path\To\Class;
use Doctrine\Bundle\DoctrineBundle\ConnectionFactory;
use Doctrine\Common\EventManager;
use Doctrine\DBAL\Configuration;
class CustomConnectionFactory extends ConnectionFactory
{
public function createConnection(array $params, Configuration $config = null, EventManager $eventManager = null, array $mappingTypes = array())
{
// Discover and override $params array here.
// A real-world example might obtain them from zookeeper,
// consul or etcd for example. You'll probably want to cache
// anything you obtain from such a service too.
$params['driver'] = 'pdo_mysql';
$params['host'] = '10.1.2.3';
$params['port'] = 3306;
$params['dbname'] = 'foo';
$params['user'] = 'myuser';
$params['password'] = 'mypass';
//continue with regular connection creation using new params
return parent::createConnection($params, $config, $eventManager,$mappingTypes);
}
}
Note also that Symfony 3.2 features the ability to use environment variables in container configurations, and to use their values on-demand (rather than fixing them when the container is compiled). See the blog announcement for more details.
I know that using the Doctrinebundle in Symfony2 it is possible to instantiate multiple DB connections under Doctrine...
$connectionFactory = $this->container->get('doctrine.dbal.connection_factory');
$connection = $connectionFactory->createConnection(array(
'driver' => 'pdo_mysql',
'user' => 'foo_user',
'password' => 'foo_pass',
'host' => 'foo_host',
'dbname' => 'foo_db',
));
I'm curious if this is the case if you are using PURELY Doctrine though?, I've set up Doctrine via Composer like so...
{
"config": {
"vendor-dir": "lib/"
},
"require": {
"doctrine/orm": "2.3.4",
"doctrine/dbal": "2.3.4"
}
}
And have been looking for my ConnectionFactory class but am not seeing it anywhere? Am I required to use Symfony2 to do this?
Should I just download ConnectionFactory.php from the DoctrineBundle and include it in my DBAL folder?? idk?
A bundle is only in the context of symfony needed, it wraps the orm into symfony infrastructure (services, etc.). For pure use of the orm you should read the ORM: Installation and Configuration. As you see you must create an entity manager by yourself with EntityManager::create($dbParams, $config), so simply create different entity managers for your different databases.
For DBAL use you should read DBAL: Configuration and see, a connection can simply obtained trough DriverManager::getConnection($connectionParams, $config); But if you are sure the ConnectionFactory has no dependency to symfony stuff and you really need it, you can try copy it to your code and construct a new factory to obtain a DBAL connection.
$connectionFactory = new ConnectionFactory(array());
$connection = $connectionFactory->createConnection(array(
'driver' => 'pdo_mysql',
'user' => 'foo_user',
'password' => 'foo_pass',
'host' => 'foo_host',
'dbname' => 'foo_db',
));
But take care, this is a DBAL connection, i.e. it's a abstraction layer which sits on top of PDO and only for pure SQL queries. If you need a entity manager you have to initialize it as mentioned in the docs above, or maybe you find another entity manager factory class, which you can "copy".
I am trying to generate entities from database using standard console commands as described in Symfony2 documentation here: http://symfony.com/doc/current/cookbook/doctrine/reverse_engineering.html.
php app/console doctrine:mapping:convert --from-database --force yml "src/My/HomeBundle/Resources/config/doctrine/metadata/orm"
php app/console doctrine:mapping:import MyHomeBundle yml
php app/console doctrine:generate:entities MyHomeBundle
After this, all tables are generated correctly. The problem is that this won't generate entities for database views. When I add yml files myself into src/My/HomeBundle/Resources/config/doctrine/metadata/orm for example:
UserInGroup:
type: entity
table: user_in_group_view
fields:
id:
id: true
type: integer
unsigned: false
nullable: false
generator:
strategy: IDENTITY
userId:
type: integer
unsigned: false
nullable: false
column: user_id
userGroupId:
type: integer
unsigned: false
nullable: false
column: user_group_id
lifecycleCallbacks: { }
I get this exception when running php app/console doctrine:generate:entities MyHomeBundle:
Notice: Undefined index: My\HomeBundle\Entity\UserInGroup in C:\Users\ThisIsMe\Projects\SymfonyTestProject\vendor\doctrine\lib\Doctrine\ORM\Mapping\Driver\AbstractFileDriver.php line 121
Similar question was posted here: How to set up entity (doctrine) for database view in Symfony 2
I know I can create Entity class, but I was hoping that I could get this generated so if I change my view, I could just regenerate entity classes. Any suggestions?
Now you create your orm files only. You need to follow 2 more steps. I will give you the complete steps from begining.
Before doing this delete all yml files in your orm directory that you had created early.
I hope MyHomeBundle is your bundle name
1).php app/console doctrine:mapping:convert yml ./src/My/HomeBundle/Resources/config/doctrine --from-database --force
Symfony2 generate entity from Database
2).php app/console doctrine:mapping:import MyHomeBundle yml
3).php app/console doctrine:generate:entities MyHomeBundle
Hope this helps you.
Got the same issue, i use xml instead of yml but must be the same.
Check in your orm entity if the name include the correct route, exemple:
<entity name="Myapp\MyrBundle\Entity\MyEntity" table="myentity">
Because when i generate my orm from database the name was like that:
<entity name="MyEntity" table="myentity">
So doctrine didn't understand the right path.
Hope i'm clear and this will help you!
I know it's an old question but I found the trick (Symfony 6) to generate entities from SQL view (I use a SQL server database).
So I modified two methods of the SQLServerPlatform.php file of the doctrine bundle.
public function getListTablesSQL()
{
// "sysdiagrams" table must be ignored as it's internal SQL Server table for Database Diagrams
// Category 2 must be ignored as it is "MS SQL Server 'pseudo-system' object[s]" for replication
return 'SELECT name, SCHEMA_NAME (uid) AS schema_name FROM sysobjects'
. " WHERE type = 'V' AND name != 'sysdiagrams' AND category != 2 ORDER BY name";
}
I changed the where condition parameter 'U' by 'V' for view.
Same operation for the method getListTableColumnsSQL(), we change here the 'U' parameter of the where condition by 'V'.
public function getListTableColumnsSQL($table, $database = null)
{
return "SELECT col.name,
type.name AS type,
col.max_length AS length,
~col.is_nullable AS notnull,
def.definition AS [default],
col.scale,
col.precision,
col.is_identity AS autoincrement,
col.collation_name AS collation,
CAST(prop.value AS NVARCHAR(MAX)) AS comment -- CAST avoids driver error for sql_variant type
FROM sys.columns AS col
JOIN sys.types AS type
ON col.user_type_id = type.user_type_id
JOIN sys.objects AS obj
ON col.object_id = obj.object_id
JOIN sys.schemas AS scm
ON obj.schema_id = scm.schema_id
LEFT JOIN sys.default_constraints def
ON col.default_object_id = def.object_id
AND col.object_id = def.parent_object_id
LEFT JOIN sys.extended_properties AS prop
ON obj.object_id = prop.major_id
AND col.column_id = prop.minor_id
AND prop.name = 'MS_Description'
WHERE obj.type = 'V'
AND " . $this->getTableWhereClause($table, 'scm.name', 'obj.name');
}
Maybe this will help someone.
As you can see here:
http://symfony.com/doc/current/cookbook/doctrine/reverse_engineering.html
the reverse engineering process from db to entity is not fully implemented yet:
"As the Doctrine tools documentation says, reverse engineering is a one-time process to get started on a project. Doctrine is able to convert approximately 70-80% of the necessary mapping information based on fields, indexes and foreign key constraints. Doctrine can't discover inverse associations, inheritance types, entities with foreign keys as primary keys or semantical operations on associations such as cascade or lifecycle events. Some additional work on the generated entities will be necessary afterwards to design each to fit your domain model specificities."