I have been working on an e-commerce website in PHP Lithium framework, actually this one is upgraded from CakePHP, we have to use transaction operation on db in mysql. Just don't know how to do db transaction in PHP Lithium framework.
Since Lithium uses PDO, you can just get the PDO object and call the beginTransaction() method.
$foo = app\models\Foo::create();
$pdo = Connections::get('default')->connection;
$pdo->beginTransaction();
$foo->bar = 'Hello';
$foo->save();
$pdo->commit();
https://github.com/UnionOfRAD/lithium/issues/1004#issuecomment-23690165
http://www.php.net/manual/en/pdo.begintransaction.php
It doesn't seem like it is supported, unfortunately. See source of lithium/data/source/database/adapter/MySql.php.
An alternative may be to manually execute your queries.
Within your model, you can do:
static::connection->read($sql, $placeholders);
Where $sql is your raw SQL like:
$sql = 'SELECT * FROM users WHERE id = {:id}';
and $placeholders (optional) are your placeholders:
$placeholders = [
'id' => 5
];
Using that knowledge, you should be able to set up a transaction.
Related
Atm I am building a very specific solution for an existing application written in Laravel. The solution executes queries in c++ modifies data, does sorting and returns the results. This c++ program is loaded in via a PHP extension and serves a single method to handle this logic.
The method provided by the extension should be implemented in Laravel using Eloquent, I've been looking at the source code for ages to find the specific method(s) that execute the queries build with Eloquensts Builder.
Where can I find the methods that actually perform the queries?
Why c++? I hear you think. The queries should be executed on multiple schemas (and/or databases) over multiple threads for improved performance. Atm 100+ schemas are being used with each containing thousands of records per table.
After a lot of troubleshooting and testing I have found a solution to my problem. In the class Illuminate\Database\Query\Builder you can find a method called runSelect(). This method runs a select statement against the given connection and returns the selected rows as an array.
/**
* Run the query as a "select" statement against the connection.
*
* #return array
*/
protected function runSelect()
{
return $this->connection->select(
$this->toSql(), $this->getBindings(), ! $this->useWritePdo
);
}
What I did to test my implementation in c++ to run the selects, I mapped the return values of $this->getBindings() to a new array to do some necessary modifications to some strings and did a simple str_replace_array on the prepared statement to get the full query. Eventually the c++ program will execute the prepared statemend and not the parsed query.
The modified method to suit my case looks like this. This has been done quick and dirty for now to test if it is possible, but you get the idea. Works as a charm except for the count() method in eloquent.
/**
* Run the query as a "select" statement against the connection.
*
* #return array
*/
protected function runSelect()
{
$bindings = [];
foreach ($this->getBindings() as $key => $value) {
$bindings[] = $value; // Some other logic to manipulate strings will be added.
}
$query = str_replace_array('?', $bindings, $this->toSql());
$schemas = ['schema1', 'schema2', 'schema3', 'schema4']; // Will be fetched from master DB.
return runSelectCpp($schemas, $query);
}
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
I'm trying to do some SQL queries using Zend adapter. The code that I'm trying to use is something like this:
$result = $this->$db->getConnection()->exec('CREATE TABLE TEST');
and I know that $db is set and works properly, because I can run other commands such as
$this->$db->listTables(); or
$result = $this->$db->fetchAssoc("SHOW COLUMNS FROM " .$schema);
As I was reading through Zend documentation, it was mentioned that some database transactions that are not prepared should be used through the first example (e.g. exec("...") ), but apparently I have problems running those.
Any thoughts?
This should work ...
$db = Zend_Db_Table::getDefaultAdapter();
$db->query('CREATE TABLE wolf (tag VARCHAR(9))');
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);
...
I am creating a web site using php, mysql and zend framework.
When I try to run any sql query, page generation jumps to around 0.5 seconds. That's too high. If i turn of sql, page generation is 0.001.
The amount of queries I run, doesn't really affect the page generation time (1-10 queries tested). Stays at 0.5 seconds
I can't figure out, what I am doing wrong.
I connect to sql in bootstrap:
protected function _initDatabase ()
{
try
{
$config = new Zend_Config_Ini( APPLICATION_PATH . '/configs/application.ini', APPLICATION_ENV );
$db = Zend_Db::factory( $config -> database);
Zend_DB_Table_Abstract::setDefaultAdapter( $db );
}
catch ( Zend_Db_Exception $e )
{
}
}
Then I have a simple model
class StandardAccessory extends Zend_DB_Table_Abstract
{
/**
* The default table name
*/
protected $_name = 'standard_accessory';
protected $_primary = 'model';
protected $_sequence = false;
}
And finally, inside my index controller, I just run the find method.
require_once APPLICATION_PATH . '/models/StandardAccessory.php';
$sa = new StandardAccessory( );
$stndacc = $sa->find( 'abc' );
All this takes ~0.5 seconds, which is way too long. Any suggestions?
Thanks!
Tips:
Cache the table metadata. By default, Zend_Db_Table tries to discover metadata about the table each time your table object is instantiated. Use a cache to reduce the number of times it has to do this. Or else hard-code it in your Table class (note: db tables are not models).
Use EXPLAIN to analyze MySQL's optimization plan. Is it using an index effectively?
mysql> EXPLAIN SELECT * FROM standard_accessory WHERE model = 'abc';
Use BENCHMARK() to measure the speed of the query, not using PHP. The subquery must return a single column, so be sure to return a non-indexed column so the query has to touch the data instead of just returning an index entry.
mysql> SELECT BENCHMARK(1000,
(SELECT nonindexed_column FROM standard_accessory WHERE model = 'abc'));
Note that Zend_Db_Adapter lazy-loads its db connection when you make the first query. So if there's any slowness in connecting to the MySQL server, it'll happen as you instantiate the Table object (when it queries metadata). Any reason this could take a long time? DNS lookups, perhaps?
The easiest way to debug this, is to profile your sql queries. you can use Firephp (plugin for firebug) see http://framework.zend.com/manual/en/zend.db.profiler.html#zend.db.profiler.profilers.firebug
another way to speed up things a little is to cache the metadata of your tables.
see: http://framework.zend.com/manual/en/zend.db.table.html#zend.db.table.metadata.caching
Along with the above suggestions I did a very unscientific test and found that the PDO adapter was faster for me in my application (I know mysqli is supposed to be faster but maybe it's the ZF abstraction). I show the results here (the times shown are only good for comparison)