I would like to retrieve all the tables of my database as a list.
i tried to do a "Show databases" on a query but as i'm not using a class I defined (entity) in symfony it's not working.
And with DQL :
$em = $this->getDoctrine()->getEntityManager();
$query = $em->createQuery(
'show databases');
$result = $query->getResult();
This error :
[Syntax Error] line 0, col 0: Error: Expected SELECT, UPDATE or DELETE, got 'show'
Any idea to help me ?
As mentioned in a different answer, you can use Doctrine\DBAL for that:
/** #type \Doctrine\DBAL\Connection $connection */
$connection = ...;
/** #type \Doctrine\DBAL\Schema\MySqlSchemaManager $sm */
$sm = $connection->getSchemaManager();
And then just list the tables as Array:
var_dump( $sm->listDatabases() );
My 2 cents:
getContainer()->get('doctrine.dbal.default_connection')->getSchemaManager()->listTableNames()
This will give you an array of table names.
i have a couple cases where I need to use complex sql statements/functions that I just couldn't do in DQL. Luckily, Symfony2/doctrine provide a method to grab the current database connection and bypass doctrine entirely.
//get connection
$conn = $this->get('database_connection');
//run a query
$users= $conn->fetchAll('select * from users');
Be very careful when using this method, however. Since you are bypassing doctrine, you need to handle any security concerns like SQL injection yourself.
You can add Doctrine DBAL to your project and it will give you the tools you need. You can list databases, tables from a database, columns from a table etc etc
More in Doctrine DBAL documentation: http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/schema-manager.html
Doctrine is a ORM, it is not intended to list all the databases. Beside that, usually for the current user you don't have the right to show all databases in the server, this can prove to be a big security breach.
Basicly, doctrine does not know how to interpret your query, you have to use a native query for this: Doctrine Native Query
Related
I can connect the databases in my project created by Laravel 5, but I use this code.
Is there any way to add User::all() before that ->select("select * from users");?
public function index(){
$user = \DB::connection('nombrebd')->select("select * from users");
$user2 = \DB::connection('nombrebd2')->select("select * from users");
return $user+$user2;
}
UPDATE
Sorry for my bad explanation , I need to receive all information about user in two differents databases.
If your intention is to use Eloquent as the base of your query to avoid writing actual SQL statements, you can do the following to get all users from each database:
$user = App::make('App\User')->setConnection('nombrebd')->get();
$user2 = App::make('App\User')->setConnection('nombrebd2')->get();
You can't use User::all() as you'd like, because that initialises a query builder instance and fetches the results all in one go, so there is no way to specify which connection it should use.
You could have two models, and in one of them you can specify an alternate connection:
protected $connection = 'mysql-alt';
Once you query both models, you can even merge them as such:
$users = $user_list_a->merge($user_list_b);
I use this approach when dealing with legacy databases.
I feel like I'm having a moment where I'm missing something small here; I've been having issues using the insert() method on the QueryBuilder component on Dotrine DBAL 2.2.x / 2.3.x.
I did some investigation and here's the snippet from the QueryBuilder page from the DBAL Documantation
The \Doctrine\DBAL\Query\QueryBuilder supports building SELECT, INSERT, UPDATE and DELETE queries. Which sort of query you are building depends on the methods you are using.
It goes on further to explain code examples, such that I can simply do:
$builder = $connection->createQueryBuilder();
$result = $builder
->insert('table_name')
// ...
To use the query builder in Insert Mode. Except when I do I get a complaint here from PHP:
Fatal error: Call to undefined method Doctrine\DBAL\Query\QueryBuilder::insert()
On further inspection of The QueryBuilder.php Source Code
I see no reference to any method insert(...), no class to inherit this from, no traits added to the QueryBuilder that could expose the insert mechanism. In addition I see this right at the top:
/* The query types. */
const SELECT = 0;
const DELETE = 1;
const UPDATE = 2;
There's no insert query type; there is however this interesting method comment for execute():
/**
* Execute this query using the bound parameters and their types.
*
* Uses {#see Connection::executeQuery} for select statements and {#see Connection::executeUpdate}
* for insert, update and delete statements.
*
* #return mixed
*/
Bottom Line:
This is a massive project with 100's of maintainers, I'm more likely to find my interpretation suspect here than a screwup on something so fundamental over numerous versions, but I cannot for the life of me figure out what I'm missing. Please help me see the obvious.
It depends on your version. Insert has been added since v2.5.0-BETA3.
Viz https://github.com/doctrine/dbal/blob/master/lib/Doctrine/DBAL/Query/QueryBuilder.php#L563
and commit
You can decide to update package version or check this alternative solution
I have a simple entity with many-to-many and one-to-many associations. I'm aware of 'Joins' for fetching related associations which is a manual solution for my problem.
How can I fetch an entity with all of its associations using EntityManager in Doctrine2? e.g.:
$this->em
->getRepository('Entities\Patientprofile')
->findOneByuserid('555555557')
->fetchAllAssociations();
from http://doctrine-orm.readthedocs.org/en/latest/reference/dql-doctrine-query-language.html#temporarily-change-fetch-mode-in-dql
you can set eager fetch mode temporarily:
$query = $em->createQuery("SELECT u FROM MyProject\User u");
$query->setFetchMode("MyProject\User", "address", "EAGER");
$query->execute();
If you want do load dynamically all associations with this fetch mode, you can use the getAssociationMappings() method of the Doctrine\ORM\Mapping\ClassMetadataInfo, passing your entity name as parameter to the constructor of ClassMetadataInfo and then iterate over the returned array as $assoc and call:
$query->setFetchMode("MyProject\User", $assoc, "EAGER");
Doc: ClassMetadataInfo#getAssociationMappings()
Doctrine2 setFetchMode not working with "EAGER"
I tried also to fetch the associating entities "eagerly" using setFetchMode in my query, but the following didn't seem to work:
$query->setFetchMode("MyProject\User", "address", "EAGER");
When I jumped into the files I found out that the third parameter $fetchMode should be an integer. The constants are defined in Doctrine\ORM\Mapping:ClassMetadataInfo. When passing a string it will default to Mapping\ClassMetadata::FETCH_LAZY because of this if clause.
/**
* Specifies that an association is to be fetched when it is first accessed.
*/
const FETCH_LAZY = 2;
/**
* Specifies that an association is to be fetched when the owner of the
* association is fetched.
*/
const FETCH_EAGER = 3;
/**
* Specifies that an association is to be fetched lazy (on first access) and that
* commands such as Collection#count, Collection#slice are issued directly against
* the database if the collection is not yet initialized.
*/
const FETCH_EXTRA_LAZY = 4;
So setting the corresponding integer solved the problem:
$query->setFetchMode("MyProject\User", "address", 3);
Or declare the class use Doctrine\ORM\Mapping\ClassMetadata at the top and then use the constant:
$query->setFetchMode("MyProject\User", "address", ClassMetadata::FETCH_EAGER);
EDIT:
Since there seems to be a lot of confusion here on how to fetch associations the right way I will edit my answer and add some additional information on how you can fetch join using your repository.
According to the Doctrine documentation there are 2 types of joins:
Regular Joins: Used to limit the results and/or compute aggregate values.
Fetch Joins: In addition to the uses of regular joins: Used to fetch related entities and include them in the hydrated result of a
query.
So to get an entity including its associations you will need to "fetch-join" all these associations to make sure they are loaded eagerly.
I usually don't use DQL queries for getting entities and solving my fetch joins, instead I add a custom method to a repository where I use a query builder. This is more flexible and much more readable then using DQL. The correct DQL query will be created by the query builder when we call the createQuery method. You can check the created DQL query of course for debug purposes.
An example for such a custom method inside the Patientprofile entity repository from the question above:
public function findPatientByIdWithAssociations($id)(
// create a query builder for patient with alias 'p'
$qb = $this->createQueryBuilder('p')
->where('p.id = :patient_id')
->addSelect('pd')
->leftJoin('p.documentation', 'pd')
->addSelect('pa')
->leftJoin('p.address', 'pa')
->setParameter('patient_id', $id);
$query = $queryBuilder->getQuery();
return $query->getSingleResult();
}
And now you can use your custom repository method to get the patient by id (for example '555555557') including associations to the patient documentation and address:
$repository = $this->em->getRepository('Entities\Patientprofile');
$patient = $repository->findPatientByIdWithAssociations('555555557');
Make sure you use both addSelect and leftJoin to do eager loading.
Doctrine 2 uses Proxy classes for lazy loading, so you don't actually need to have the associations' data fetched until you use the objects. Since the Proxy classes inherit from your association classes, you're able to use the proxies exactly as you would use the fretch association classes.
but, if you really need to fetch the actual association classes, you need to tell the query to set the fetch mode to Doctrine\ORM\Mapping\ClassMetadata::FETCH_EAGER. If you're using the annotations, you can achieve this with:
e.g.
/**
* #ManyToMany(targetEntity="Item", fetch="EAGER")
*/
private $items;
You can use a DQL query:
$query = $em->createQuery("SELECT p, f FROM Entities\\Patientprofile p JOIN p.Foo f WHERE p.id = ?1");
$query->setParameter(1, 321);
$patient = $query->getSingleResult();
Faced the same problem.
It was necessary to pull out all chain of parents of an element.
$query->setFetchMode(EntityClass, "alias_in_entity", 3) gets only 1 lvl deep, other parents are just proxy.
This can be fixed by changed in entity class fetch mode to eager. But if it`s not if this is not possible for some reason (performance etc), this can be made as #wormhit mentioned by changing entity metadata "on fly"
Example:
$query = $this->entityManager->createQueryBuilder()->select('fields')
->from(FormField::class, 'fields');
$metadata = $this->entityManager->getClassMetadata(FormField::class);
$metadata->setAssociationOverride('parent', ['fetch' => \Doctrine\ORM\Mapping\ClassMetadata::FETCH_EAGER]);
return $query->getOneOrNullResult();
could some one please explain this snippet of magento code found in loadByCustomerId() in the class Mage_Sales_Model_Mysql4_Quote.
$read = $this->_getReadAdapter();
$select = $this->_getLoadSelect('customer_id', $customerId, $quote)
->where('is_active=1')
->order('updated_at desc')
->limit(1);
$data = $read->fetchRow($select);
When i var_dump($data) i see that its an array of customer data. What is model associated with this $data array? Thanks.
Magento "Models" (meaning the entities that allow you to interact with the database, not general purpose server/domain models) have two layers. The first is the "Model" layer. This contains methods for logical interactive with an model. (get me a customer's address, place the order, etc). The second layer is the "Resource Model" layer. Resource Models handle any interactive with the database (or,more generally, the data-store,or the persistance layer, or etc.).
The way a Resource Model interacts with the database is via adapter objects. One for reading information, another for writing information.
So, you're in the class Mage_Sales_Model_Mysql4_Quote. This is a Resource Model. It's the backend for the Mage_Sales_Model_Quote object, instantiated with
$model = Mage::getModel('sales/quote');
With this line
$read = $this->_getReadAdapter();
you're getting a reference to the model's read adapter. This will let you make queries to the database.
With this line
$select = $this->_getLoadSelect('customer_id', $customerId, $quote)
->where('is_active=1')
->order('updated_at desc')
->limit(1);
You're getting a reference to the SQL statement (also an object) that this Resource Model will use to load a sales/quote object.
//gets a reference
$this->_getLoadSelect('customer_id', $customerId, $quote)
Then, you're calling methods on that object to alter it with additional logic
->where('is_active=1')
->order('updated_at desc')
->limit(1);
In pseudo sql, a query might look like this normally
SELECT * FROM quote_table;
But after you call those methods, the query will look something like
SELECT * FROM quote_table
WHERE is_active = 1
ORDER BY updated_at desc
LIMIT 1;
Finally,
$data = $read->fetchRow($select);
here you're using the read adapter you fetched earlier to make a query into the database for the specific quote item row that your query will fetch.
_getReadAdapter() gets the read-only database connection. _getLoadSelect creates a select query on the model's (Mage_Sales_Model_Mysql4_Quote) main table. The data returned is just raw data from the SQL query not associated with any particular backend model.
How to do a native sql query in Doctrine 2, executing an update statement?
The createNativeQuery method on EntityManager, requires a second parameter (ResultSetMapping) to be able to map the resultsets to Objects.
But when updating (or inserting, or set, or...) there is no resulset to map.
Passing null or just new ResultSetMapping(), gives an error.
Are only select queries supported for native sql?
Essentially ditto w/ faken,
this from the docs:
If you want to execute DELETE, UPDATE or INSERT statements the Native
SQL API cannot be used and will probably throw errors. Use
EntityManager#getConnection() to access the native database connection
and call the executeUpdate() method for these queries.
one note of use is the connection object can be retrieved from the EntityManager:
$conn = $entityManager->getConnection();
$rowsAffected = $conn->executeUpdate($sql, $params, $types);
Update statements are usually pretty simple, so you might as well use the normal Doctrine2 way (i.e. programmatically updating entities and calling EntityManager::flush() OR using DQL Updates).
Having said this, if you really want to use normal SQL, you could always do it like this:
Keep the db connection object you get when creating a connection with Doctrine2:
$connection = \Doctrine\DBAL\DriverManager::getConnection($dbConfig->toArray(),null,$evm);
Execute whatever SQL you want, using the available methods in the connection object, e.g.:
$connection->executeUpdate($sql, $params, $types);
$connection->exec($sql);
...