cakephp see the compiled SQL Query before execution - sql

My query gets the timeout error on each run. Its a pagination with joins.
I want to debug the SQL, but since I get a timeout, I can't see it.
How can I see the compiled SQL Query before execution?
Some cake code:
$this -> paginate = array(
'limit' => '16',
'joins' => array( array(
'table' => 'products',
'alias' => 'Product',
'type' => 'LEFT',
'conditions' => array('ProductModel.id = Product.product_model_id')
)),
'fields' => array(
'COUNT(Product.product_model_id) as Counter',
'ProductModel.name'
),
'conditions' => array(
'ProductModel.category_id' => $category_id,
),
'group' => array('ProductModel.id')
);

First off, set the debug variable to 2 in app/config/config.php.
Then add:
<?php echo $this->element('sql_dump');?>
at the end of your layout. This should actually be commented out in your default cake layout.
You will now be able see all SQL queries that go to the database.
Now copy the query and use the SQL EXPLAIN command (link is for MySQL) over the database to see what the query does in the DBMS. For more on CakePHP debugging check here.
Since your script doesn't even render you can try to get the latest log directly from the datasource with:
function getLastQuery()
{
$dbo = $this->getDatasource();
$logs = $dbo->getLog();
$lastLog = end($logs['log']);
return $lastLog['query'];
}
This needs to be in a model since the getDatasource() function is defined in a model.
Inspect the whole $logs variable and see what's in there.

One more thing you can do is ....
Go to Cake/Model/DataSource/DboSource.php and locate function execute() and print $sql variable.
That should print the sql.
This certainly is not be the cleanest way (as you are changing Cake directory) .. but certainly would be quickest just to debug if something is not working with sql.

Try...
function getLastQuery($model) {
$dbo = $model->getDatasource();
$logData = $dbo->getLog();
$getLog = end($logData['log']);
echo $getLog['query'];
}

Simple way to show all executed query of your given model:
$sqllog = $this->ModelName->getDataSource()->getLog(false, false);
debug($sqllog);

class YourController extends AppController {
function testfunc(){
$this->Model->find('all', $options);
echo 'SQL: '.$this->getLastQuery();
}
function getLastQuery()
{
$dbo = ConnectionManager::getDataSource('default');
$logs = $dbo->getLog();
$lastLog = end($logs['log']);
return $lastLog['query'];
}
}
or you can get all the query by adding following line in to the function execute() in lib/Cake/Model/DataSource.php
Debugger::dump($sql);

set the debug variable to 2 in app/config/config.php.
echo $this->Payment->save();
Out put like =>SQL Query: INSERT INTO photoora_photoorange.payments VALUES (*******)
[insert query][2]

set the debug variable to 2 in app/config/config.php.
And

Related

Native query instead of createQueryBuilder in entity field type Symfony

Maybe someone faced such a problem then please help. I want to add a dropdown field in formbuilder that would feed from native sql query. I made this in my form:
->add('extensionId', 'entity', [
'required' => false,
'label' => 'Insurance Company',
'class' => 'Bundle:Product',
'query_builder' => function (ProductRepository $repo) {
return $repo->getPGOperPG();
}
])
It works fine if i use createQueryBuilder, like this:
public function getPGOperPG()
{
return $this->createQueryBuilder('pgo')
->select('pgo')
->join('pgo.productGroups', 'pg')
->where('pg.id IN (677, 655, 625) AND pgo.isActive = true');
}
But i get error if use this:
public function getPGOperPG()
{
$sql = <<<SQL
SELECT product_group_option_id
FROM product_groups_product_group_options
WHERE product_group_id in (677, 655, 625)
SQL;
$rsm = new ResultSetMappingBuilder($this->getEntityManager());
$rsm->addRootEntityFromClassMetadata('Bundle\Entity\Product', 'pgo');
return $this->_em->createNativeQuery($sql, $rsm)
;
}
This is the error:
enter image description here.
I understand that only CreateQueryBuilder object is expected.
Question: is there a way how i could pass native query to a dropdown field? maybe some other form type or smth?
Thank you in advance!!!

YII: How do you log slow SQL queries?

I only want to log SQL queries that are slow, where slow is determined by any query that takes longer than a value specified by me. Is this possible? And how do I enable it?
DBProfiler works quite nicely, but it seems to always output to the screen and not the file:
array( //db profiler
'class'=>'ext.db_profiler.DbProfileLogRoute',
'countLimit' => 1, // How many times the same query should be executed to be considered inefficient
'slowQueryMin' => 0.1, // Minimum time for the query to be slow
),
How can I plug into DBProfiler or perhaps in another way so that I can get something written to application.log every time a query is slow?
In your config/main.php in the db component configuration set enableParamLogging and enableProfiling params to true and make sure that:
'log'=>array(
'class'=>'CLogRouter',
'routes'=>array(
array(
'class'=>'CFileLogRoute',
'levels'=>'error, warning',
),
// uncomment the following to show log messages on web pages
array(
'class'=>'CWebLogRoute',
),
),
),
is like this. for more infos CDbConnection and CLogRouter
try dbprofiler extension. my be it will help you...
dbprfiler
I ended up writing my own logging function:
private function slowQueryEvaluator($startTime, $endTime, $identifier) {
$MAX_TIME = 0.1;
$IP = Controller::getRealIpAddress();
$userID = -1;
if (isset(YII::app()->user->id)) {
$userID = YII::app()->user->id;
}
$seconds = $endTime - $startTime;
if ($seconds > $MAX_TIME ) {
YII::log($IP.' - '.$userID.' - '.$seconds.' seconds - '.$identifier);
}
}

zend framework 2 autentification using DbTable failure

I have followed the zend instructions for implement my web Authentication using a database table.
It's exactly the same code, but when render the page, the following exceptions appears:
Zend\Authentication\Adapter\Exception\RuntimeException
File:
C:\xampp\htdocs\pfc\vendor\ZF2\library\Zend\Authentication\Adapter\DbTable.php
Mensaje:
The supplied parameters to DbTable failed to produce a valid sql statement, please
check table and column names for validity.
produced by this other:
Zend\Db\Adapter\Exception\InvalidQueryException
File:
C:\xampp\htdocs\pfc\vendor\ZF2\library\Zend\Db\Adapter\Driver\Mysqli\Statement.php
Mensaje:
Statement couldn't be produced with sql: SELECT `users`.*, (CASE WHEN `password` = ?
THEN 1 ELSE 0 END) AS `zend_auth_credential_match` FROM `users` WHERE `mail` = ?
Seems to be that Statement.php can not execute the sql of above, but I send the sql by phpmyadmin replacing the ? for strings and work ok.
I am sure that $dbAdapter works ok also because I have tested it and the columns name are
"mail" and "password".
This in my code, also I put the $dbAdapter test code.
$dbAdapter = new DbAdapter(array( //This DbAdapter Work ok sure!!
'driver' => 'Mysqli',
'database' => 'securedraw',
'username' => 'root',
'password' => ''
));
$fp = function($name) use ($dbAdapter) { return $dbAdapter->driver->formatParameterName($name);};
$sql = 'SELECT * FROM ' . $qi('users') . ' WHERE id = ' . $fp('id');
$statement = $dbAdapter->query($sql);
$parameters = array('id' => 1);
$sqlResult = $statement->execute($parameters);
$row = $sqlResult->current();
$mail = $row['mail'];
$password = $row['password']; //until here test $dbAdapter exitly!!
//Start the auth proccess!!
$authAdapter = new AuthDbTableAdapter($dbAdapter);
$authAdapter->setTableName('users')
->setIdentityColumn('mail')
->setCredentialColumn('password');
$authAdapter->setIdentity('josep')
->setCredential('josep');
$authResult = $authAdapter->authenticate(); //This is the fail method!!!
After more research on the subject, I discovered that if changed the driver of the dbAdapter to pdo_mysql, authenticate method works ok.
The problem is I don't want use PDO because the SGBD won't change in the future.
Somebody know because happen this?
This may seems old but I was able to solve this error. This error is caused from you MySQL version.
This one works for me. All you need to do is to remove the driver_options from your db setup, this code is usually located at your global.php or .local.php from your Config file.
Change FROM:
'db' => array(
'driver' => 'Pdo_Mysql',
'dsn' => 'mysql:dbname=dbName;host=localhost',
'username' => 'dbUser',
'password' => 'dbPass',
'driver_options' => array(
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
),
),
TO
'db' => array(
'driver' => 'Pdo_Mysql',
'dsn' => 'mysql:dbname=dbName;host=localhost',
'username' => 'dbUser',
'password' => 'dbPass',
),
Thank you. This solution solved my problem.

limit number of results using magento API V2

Hi I have searched the site for my question but haven't found an easy solution and I think the issue is so basic.
I'm using Api V2 so maybe there's a solution now. Here I go, this is my code:
$api_soap_url = 'http://localhost/magento/api/v2_soap?wsdl=1';
$client = new SoapClient($api_soap_url);
$session_id = $client->__soapCall('login',array($user, $pw));
$data = array($session_id);
$result = $client->__soapCall('customerCustomerList', $data);
This returns all results, I need to limit number of result so I have tried using filters and other solutions found here but no luck.
The only one I haven't tried is this one:
Control the number of results from a Magento API call
But filtering by date doesn't solve my problem and rewriting classes is a ver complex solution for such a simple need.
Thanks in advance
I'm not sure the filter can limit number of result but you can try this:
$complexFilter = array(
'complex_filter' => array(
array(
'key' => 'created_at',
'value' => array('key' => 'gt', 'value' => '2012-05-13 06:11:00')
// where created_at is greater than 2012-05-13 06:11:00
// For example: eq (equals), neq (not equals), gt (greater than), lt (less than), etc.
)
)
);
$result = $client->customerCustomerList($session, $complexFilter);
I ended up overriding app/code/core/Mage/Sales/Model/Order/Api.php, adding a "special magic" field called "collection.limit". Your mileage may vary; I have tight controls on both the Magento installation and the programs (in this case, a set of C# programs) accessing the Magento installation.
My caller simply uses the "magic field" as a key/ value pair, something like this (please test, again, I was calling from C#, so this php should be considered suspect):
$collectionLimitClause = array (
'key' => 'collection.limit',
'value' => array('key' => 'eq', 'value' => '10')
);
In my Magento installation (this part is tested, live and running), I created a Sales/Model/Order/Api.php in my local namespace and over-rode the items function. Around the 32nd or so line of that function, you'll see this:
$apiHelper = Mage::helper('api');
$filters = $apiHelper->parseFilters($filters, $this->_attributesMap['order']);
try {
foreach ($filters as $field => $value) {
$orderCollection->addFieldToFilter($field, $value);
}
} catch (Mage_Core_Exception $e) {
$this->_fault('filters_invalid', $e->getMessage());
}
Instead, I "catch" my own magic limiter with the strncmp here, with an if-else inside the foreach:
$apiHelper = Mage::helper('api');
$filters = $apiHelper->parseFilters($filters, $this->_attributesMap['order']);
try {
foreach ($filters as $field => $value) {
if( !strncmp($field,"collection.limit",16) ) {
$orderCollection->getSelect()->limit($value['eq']);
}
else {
$orderCollection->addFieldToFilter($field, $value);
}
}
} catch (Mage_Core_Exception $e) {
$this->_fault('filters_invalid', $e->getMessage());
}
I'm not overly excited by this, but, I think it's pretty safe and it works.

Symfony file upload - "Array" stored in database instead of the actual filename

I'm using Symfony 1.4.4 and Doctrine and I need to upload an image on the server.
I've done that hundreds of times without any problem but this time something weird happens : instead of the filename being stored in the database, I find the string "Array".
Here's what I'm doing:
In my Form:
$this->useFields(array('filename'));
$this->embedI18n(sfConfig::get('app_cultures'));
$this->widgetSchema['filename'] = new sfWidgetFormInputFileEditable(array(
'file_src' => '/uploads/flash/'.$this->getObject()->getFilename(),
'is_image' => true,
'edit_mode' => !$this->isNew(),
'template' => '<div id="">%file%</div><div id=""><h3 class="">change picture</h3>%input%</div>',
));
$this->setValidator['filename'] = new sfValidatorFile(array(
'mime_types' => 'web_images',
'path' => sfConfig::get('sf_upload_dir').'/flash',
));
In my action:
public function executeIndex( sfWebRequest $request )
{
$this->flashContents = $this->page->getFlashContents();
$flash = new FlashContent();
$this->flashForm = new FlashContentForm($flash);
$this->processFlashContentForm($request, $this->flashForm);
}
protected function processFlashContentForm($request, $form)
{
if ( $form->isSubmitted( $request ) ) {
$form->bind( $request->getParameter( $form->getName() ), $request->getFiles( $form->getName() ) );
if ( $form->isValid() ) {
$form->save();
$this->getUser()->setFlash( 'notice', $form->isNew() ? 'Added.' : 'Updated.' );
$this->redirect( '#home' );
}
}
}
Before binding my parameters, everything's fine, $request->getFiles($form->getName()) returns my files.
But afterwards, $form->getValue('filename') returns the string "Array".
Did it happen to any of you guys or do you see anything wrong with my code?
Edit: I added the fact that I'm embedding another form, which may be the problem (see Form code above).
Alright, I got it. I wasn't properly declaring my validator.
What i should've done is:
$this->setValidator('filename', new sfValidatorFile(array(
'mime_types' => 'web_images',
'path' => sfConfig::get('sf_upload_dir').'/flash',
)));
Silly mistake, I hope that will help those who have the same problem.
Alternatively you can use;
$this->validatorSchema['filename']
in place of;
$this->setValidator['filename']