I tried to log my each SQL query for laravel 5.2 so for that I found many solutions and I tried below code , but somehow it's not gone a work and not generate the log.
In my routes.php - Code not working
Event::listen('illuminate.query', function($query, $bindings, $time, $name) {
dd("here");
$data = compact('bindings', 'time', 'name');
// Format binding data for sql insertion
foreach ($bindings as $i => $binding) {
if ($binding instanceof \DateTime) {
$bindings[$i] = $binding->format('\'Y-m-d H:i:s\'');
} else if (is_string($binding)) {
$bindings[$i] = "'$binding'";
}
}
// Insert bindings into query
$query = str_replace(array('%', '?'), array('%%', '%s'), $query);
$query = vsprintf($query, $bindings);
echo $query;
Log::info('illuminate.query:'. $query);
});
But I tried with the another code sample and it's working fine
code in my routes.php - working fine
DB::enableQueryLog();
DB::listen(
function ($sql) {
// $sql is an object with the properties:
// sql: The query
// bindings: the sql query variables
// time: The execution time for the query
// connectionName: The name of the connection
// To save the executed queries to file:
// Process the sql and the bindings:
foreach ($sql->bindings as $i => $binding) {
if ($binding instanceof \DateTime) {
$sql->bindings[$i] = $binding->format('\'Y-m-d H:i:s\'');
} else {
if (is_string($binding)) {
$sql->bindings[$i] = "'$binding'";
}
}
}
// Insert bindings into query
$query = str_replace(array('%', '?'), array('%%', '%s'), $sql->sql);
$query = vsprintf($query, $sql->bindings);
// Save the query to file
$logFile = fopen(
storage_path('logs' . DIRECTORY_SEPARATOR . date('Y-m-d') . '_query.log'),
'a+'
);
fwrite($logFile, date('Y-m-d H:i:s') . ': ' . $query . PHP_EOL);
fclose($logFile);
}
);
My Question : why Event::listen('illuminate.query' is not working? is there anything i am doing wrong?
Laravel are not firing events as illuminate.query anymore. It was changed to classes. https://github.com/laravel/framework/commit/41599959d45016f0280d986f758d414fbee81863
Now You have to caught Illuminate\Database\Events\QueryExecuted event if You want to log sql queries.
You should define your listeners in EventServiceProvider.php like so:
protected $listen = [
'Illuminate\Database\Events\QueryExecuted' =>[
'App\Listeners\YourListener'
],
]
Adding this as an answer for #Hardy Mathew instead of a comment, since comments can't have code formatting:
Example Listener as requested:
<?php
namespace App\Listeners;
use Illuminate\Database\Events\QueryExecuted;
class QueryExecutedListener
{
public function handle(QueryExecuted $event)
{
dd($event);
}
}
Be sure to add the listener in the EventServiceProvider as told by #Giedrius Kiršys
Related
I am trying to use Tinybutstrong to merge a template with an sql query result. Below is the PHP code being run, the custom database reader plugin I am attempting to use, the template file and the error message.... The code is being run from within a wordpress site, hence the use of the wpdb object and the custom database reader plugin.
The code being run:
include_once('wp-content/themes/mine/tbs_plugins/tbsdb_wpdb.php');
$link = new wpdb($username, $password, $dbname, $servername);
$sql_query = 'select year from mytable limit 10';
$TBS = new clsTinyButStrong;
$TBS->LoadTemplate('wp-content/themes/mine/templates/mytemplate.htm');
$TBS->MergeBlock('blk1', $link, $sql_query);
$TBS->Show();
Custom database reader plugin tbsdb_wpdb.php:
<?php
function tbsdb_wpdb_open(&$source,&$query) {
$source->get_results($source->prepare($query),ARRAY_A);
return $source;
}
function tbsdb_wpdb_fetch(&$Rs,$num) {
if ($num<=$Rs->num_rows) {
return $Rs->get_row(null,ARRAY_A,$num-1) ;
}
else {
return False ;
}
}
function tbsdb_wpdb_close(&$source) {
// not needed
}
?>
Part of Template mytemplate.htm:
.
.
.
[blk1;block=begin]
<table><tr><td align="center">[blk1.year]</td></tr></table>
[blk1;block=end]
.
.
.
Error message:
TinyButStrong Error in field [blk1.year...]: item before 'year' is neither an object nor an array. Its type is NULL. This message can be cancelled using parameter 'noerr'.
I have listed out the results from the query in a for loop as follows:
$rows = $link->get_results($sql_query);
echo "<table>";
foreach ($rows as $obj) :
echo "<tr><td>" . $obj->Year . "</td></tr>";
endforeach;
echo "</table>";
this gives me a correct result but when using TBS class/Loadtemplate/Mergeblock/Show... no joy, I get the error message... Any ideas would be appreciated.
Solved it myself by modifying the tbsdb_wpdb.php to:
function tbsdb_wpdb_open(&$source,&$query) {
global $link;
global $sql_query;
return $link->get_results($sql_query,ARRAY_A);
}
function tbsdb_wpdb_fetch(&$Rs,$num) {
global $link;
global $sql_query;
if ($num<=$link->num_rows) {
return $link->get_row($sql_query,ARRAY_A,$num-1) ;
}
else {
return False ;
}
}
So essentially my global declarations were missing (or rather, in the wrong place).
I'm trying to build a script where I need to read a txt file and execute some process with the lines on the file. For example, I need to check if the ID exists, if the information has updated, if yes, then update the current table, if no, then insert a new row on another temporary table to be manually checked later.
These files may contain more than 20,30 thousand lines.
When I just read the file and print some dummie content from the lines, it takes up to 40-50ms. However, when I need to connect to the database to do all those verifications, it stops before the end due to the timeout.
This is what I'm doing so far:
$handle = fopen($path, "r") or die("Couldn't get handle");
if ($handle) {
while (!feof($handle)) {
$buffer = fgets($handle, 4096);
$segment = explode('|', $buffer);
if ( strlen($segment[0]) > 6 ) {
$param = [':code' => intval($segment[0])];
$codeObj = Sql::exec("SELECT value FROM product WHERE code = :code", $param);
if ( !$codeObj ) {
$param = [
':code' => $segment[0],
':name' => $segment[1],
':value' => $segment[2],
];
Sql::exec("INSERT INTO product_tmp (code, name, value) VALUES (:code, :name, :value)", $param);
} else {
if ( $codeObj->value !== $segment[2] ) {
$param = [
':code' => $segment[0],
':value' => $segment[2],
];
Sql::exec("UPDATE product SET value = :value WHERE code = :code", $param);
}
}
}
}
fclose($handle);
}
And this is my Sql Class to connect with PDO and execute the query:
public static function exec($sql, $param = null) {
try {
$conn = new PDO('mysql:charset=utf8mb4;host= '....'); // I've just deleted the information to connect to the database (password, user, etc.)
$q = $conn->prepare($sql);
if ( isset($param) ) {
foreach ($param as $key => $value) {
$$key = $value;
$q->bindParam($key, $$key);
}
}
$q->execute();
$response = $q->fetchAll();
if ( count($response) ) return $response;
return false;
} catch(PDOException $e) {
return 'ERROR: ' . $e->getMessage();
}
}
As you can see, each query I do through Sql::exec(), is openning a new connection. I don't know if this may be the cause of such a delay on the process, because when I don't do any Sql query, the script run within ms.
Or what other part of the code may be causing this problem?
First of all, make your function like this,
to avoid multiple connects and also o get rid of useless code.
public static function getPDO() {
if (!static::$conn) {
static::$conn = new PDO('mysql:charset=utf8mb4;host= ....');
}
return static::$conn;
}
public static function exec($sql, $param = null) {
$q = static::getPDO()->prepare($sql);
$q->execute($param);
return $q;
}
then create unique index for the code field
then use a single INSERT ... ON DUPLICATE KEY UPDATE query instead of your thrree queries
you may also want to wrap your inserts in a transaction, it may speed up the inserts up to 70 times.
Here's the code in controller
public function actionIndex()
{
$result = new RestResult();
try {
$query = TaskMgr::find()
->join('INNER JOIN', EqpInfo::tableName(), EqpInfo::tableName() . '.EQP_COD =' . TaskMgr::tableName() . '.EQP_COD')
->select([TaskMgr::tableName() . '.EQP_COD', TaskMgr::tableName() . '.TASK_STA', TaskMgr::tableName() . '.TASK_DATE', TaskMgr::tableName() . '.BUSINESS_NATURE', EqpInfo::tableName() . '.EQP_SORT_NAME', EqpInfo::tableName() . '.EQP_VART_NAME', EqpInfo::tableName() . '.USE_UNT_NAME', EqpInfo::tableName() . '.USE_UNT_ADDR', EqpInfo::tableName() . '.INST_AREA_NAME', EqpInfo::tableName() . '.MAKE_UNT_NAME']);
$result->content = $query->asArray(true)->all();
} catch (Exception $e) {
$result->error = $e->getMessage();
$result->content = [];
$result->message = ["error" => Yii::t('rest', "Server error.")];
} finally {
return $result;
}
}
and I got empty array.as pic 1, I thought it might be the problem of QueryBuilder, so I simply excute the sql script in index action:
public function actionIndex()
{
$y = Yii::$app->get('db2')->createCommand('SELECT * FROM "TB_TASK_MGR" INNER JOIN "V_EQPINFO" ON "V_EQPINFO".EQP_COD ="TB_TASK_MGR".EQP_COD')
->queryAll();
return var_dump($y);
}
and I got a empty array again.
but when I ran the sql script in Navicat, I got some rows.as pic 2, that means the sql result is not empty. I thought it might some problems with my DBConnection, so I tried change the action as :
public function actionIndex()
{
$y = Yii::$app->get('db2')->createCommand('SELECT * FROM "TB_TASK_MGR"')
->queryAll();
return var_dump($y);
}
and I got some rows, that means there's no problem in DBConnection, the only difference is the 'join' expression.
I use xampp to deploy site, php version is 5.6.23. oracle client installed and remote oracle version is 11g. php.ini config oci as
extension=php_pdo_oci.dll
Please help me find out why is this, is it because some bugs in php_pdo_oci.dll? and how to excute sql with 'join' in yii2 to oracle.
In my Codeigniter project ,table value is not retrieving from database.Am using MySQL (WAMP) as database.Using Select Query i have checked the data in database and its fine there.When updating the same also its retrieving the old value in db.But when retrieving the value in later stage (ie,taking old bill) its not retrieving the value.The problem is happening only on the single field(ie,actual_price).How to solve this error.Here am attaching the screenshot and controller code for the same.
Controller Code
function bill_view($billid)
{
if(!$billid) {
redirect('report/bill_report');
}
$salecode =str_replace("_","/",$billid);
$filter ="gm_sale.saleCode ='$salecode'";
$billArray =$this->sale_model->getBillinfo($filter);
$exshowroom='';
$bank ='';
$scheme='';
$wcoNo ='';
$saleId =0;
foreach($billArray as $key=>$val) {
$exshowroom = $val['actual_price'];
$date =$val['saledate'];
$sale_to=$val['saleCustomer'];
$saleUserId=$val['saleUserId'];
$wcoNo = $val['wcoNo'];
$saleId= $val['saleId'];
if(!is_null($val['bank']) && !empty($val['bank'])){
$bank =$val['bank'];
}
if(!is_null($val['scheme_id']) && !empty($val['scheme_id'])){
$array_scheme = unserialize($val['scheme_id']);
///////////////////////////////////////////
foreach ($array_scheme as $val_scheme_id) {
$res_scheme = $this->db->get_where("gm_scheme",array('id'=>(int)$val_scheme_id));
if($res_scheme->num_rows >0){
$arrscheme = $res_scheme->row_array();
if(!empty($scheme)) {
$scheme .= ",";
}
$scheme .= $arrscheme['schemeName'];
}
}
/////////////////////////////////////////////
}
break;
}
$query = $this->db->get_where('gm_users',array('userId'=>(int)$saleUserId));
if($query->num_rows >0) {
$arrUser =$query->row_array();
}else{
$arrUser =array();
}
$data['list_product'] = $billArray;
$data['exshowroom']=$exshowroom;
$data['userinfo'] =$arrUser;
$data['saleCode'] =$salecode;
$data['sale_to'] =$sale_to;
$data['added_date'] =$date;
$data['bank'] =$bank;
$data['scheme'] =$scheme;
$data['wcoNo'] =$wcoNo;
$data['saleId'] =$saleId;
$this->load->view('header_login');
$this->load->view('report/bill_view',$data);
//print_r($billArray);
$this->load->view('footer_login');
}
Model Code
function getBillinfo($filter=''){
$this->db->select('*,gm_sale.added_date as saledate');
$this->db->from('gm_sale',FALSE);
$this->db->join('gm_products',"gm_sale.productId=gm_products.productId",FALSE);
$this->db->join('gm_model',"gm_products.model_id=gm_model.id",FALSE);
$this->db->join('gm_banks',"gm_sale.bank_id=gm_banks.bank_id","LEFT");
if($filter<>"")
$this->db->where($filter,'',FALSE);
$this->db->order_by('gm_sale.saleId',"desc");
$query = $this->db->get();
print_r($query);
if($query->num_rows>0) {
$arrRow =$query->result_array();
print_r($arrRow);
return($arrRow);
}
return(array());
}
Your code that you have in the controller doing DB stuff should be in the model.
The controller does not have context to
$this->db
modify your joins (3rd param) to retrieve values in actual_price
Softdelete behavior works fine on execute delete statement via the entity manager as the following code:
$entity = $this->em->getRepository('Users')->find(7);
$this->em->remove($entity);
$this->em->flush();
but when execute the same functionality via QueryBuilder hard delete will execute on database
$qb = $this->em->createQueryBuilder();
$qb->delete('Users', 'p');
$qb->where($qb->expr()->eq('p.id', ':id'));
$qb->setParameters(array("id" => 7));
$result = $qb->getQuery()->getResult();
How can I allow softdelete in all cases either via entity manager or query builder
If you use DQL then you have to use a Query Hint. This should do the trick:
$query = $qb->getQuery()
$query->setHint(
\Doctrine\ORM\Query::HINT_CUSTOM_OUTPUT_WALKER,
'Gedmo\SoftDeleteable\Query\TreeWalker\SoftDeleteableWalker'
);
$result = $query->getResult();
Update:
The docs mention that you have to use a Query Hint but don't provide an example so I pulled the usage from their tests.
Docs: https://github.com/l3pp4rd/DoctrineExtensions/blob/master/doc/softdeleteable.md
Test Usage: https://github.com/l3pp4rd/DoctrineExtensions/blob/master/tests/Gedmo/SoftDeleteable/SoftDeleteableEntityTest.php
my old solution after previous answer by #Ken Hannel is:
Edit:
/vendor/doctrine/orm/lib/Doctrine/ORM/Query/SqlWalker.php
Replace walkDeleteClause function as the following:
public function walkDeleteClause(AST\DeleteClause $deleteClause)
{
$class = $this->em->getClassMetadata($deleteClause->abstractSchemaName);
$tableName = $class->getTableName();
$sql = 'DELETE FROM ' . $this->quoteStrategy->getTableName($class, $this->platform);
$this->setSQLTableAlias($tableName, $tableName, $deleteClause->aliasIdentificationVariable);
$this->rootAliases[] = $deleteClause->aliasIdentificationVariable;
//check if SoftDeleteableListener is attached
foreach ($this->em->getEventManager()->getListeners() as $eventName => $listeners) {
foreach ($listeners as $listener) {
if ($listener instanceof \Gedmo\SoftDeleteable\SoftDeleteableListener) {
$date = date('Y-m-d H:i:s');
$sql = 'UPDATE ' . $this->quoteStrategy->getTableName($class, $this->platform) . " SET deletedAt = ' " . $date . " ' ";
}
}
}
return $sql;
}
but really but I think Ken Hannel way is more professional and up to standard.