Code igniter - running two queries collide - php

As part of a very large active records query in CI, I need to get something from a different model - something like:
$sql = $this->events_model->events_to_sql($val); //returns an sql
$this->db->where($sql, NULL, false);
Now "events_to_sql" run a different query to get some data it needs for it to operate, but it fails because it uses an Active Records "where" from before, where the first query is not closed.
$this->db->where("clients.email !=", '');
How can I tell CI: This is a separate query. You shall run it and only it?
*No, I can not run the other query first, because there are multiple of the same idea, and I don't want each case t be handled separately, but all to be handled in the same manner.
*I know I can use another DB connection, but I'd rather work with a single connection.
EDIT:
This is what runs: (in order)
//main model
$this->db->where("clients.email !=", '');
//Events to sql function
//run seperate function
$this->db->from('events');
return $this->db->get();
return (string)$sql_built_from_the_event_stuff.
Instead of getting: "SELECT * FROM events" I get "SELECT * FROM events WHERE clients.email != ''"

Use arguments to separate query,
Example:
$separate = 1;
$sql = $this->events_model->events_to_sql($val,$separate); //returns an sql
$this->db->where($sql, NULL, false);
Model events_to_sql,
public function events_to_sql($val, $queryselector = false){
.....
.....
if($queryselector != 1){
$this->db->where("clients.email !=", '');
}
//Events to sql function
//run seperate function
$this->db->from('events');
return $this->db->get();
return (string)$sql_built_from_the_event_stuff.
}

Related

Generate The Raw MySQL Query From Laravel Query Builder

How can i get mysql query of a laravel query
Convert:
App\User::where('balance','>',0)->where(...)->get();
To:
SELECT * FROM users WHERE `balance`>0 and ...
use toSql() method of laravel to get the query to be executed like
App\User::where('balance','>',0)->where(...)->toSql();
But Laravel will not show you parameters in your query, because they are bound after preparation of the query. To get the bind parameters, use this
$query=App\User::where('balance','>',0)->where(...);
print_r($query->getBindings() );
enable the query log as DB::enableQueryLog() and then output to the screen the last queries ran you can use this,
dd(DB::getQueryLog());
you can add this function to your helpers
function getRealQuery($query, $dumpIt = false)
{
$params = array_map(function ($item) {
return "'{$item}'";
}, $query->getBindings());
$result = str_replace_array('\?', $params, $query->toSql());
if ($dumpIt) {
dd($result);
}
return $result;
}
and use like this:
getRealQuery(App\User::where('balance','>',0)->where(...),true)
Method 1
To print a single query, use toSql() method of laravel to get the query to be executed like
App\User::where('balance','>',0)->where(...)->toSql();
Method 2
Laravel can optionally log in memory all queries that have been run for the current request. But in some cases, such as when inserting a large number of rows, this can cause the application to use excess memory, so you should avoid this.
To enable the log, you may use the enableQueryLog method as
DB::connection()->enableQueryLog();
To get an array of the executed queries, you may use the getQueryLog method as
$queries = DB::getQueryLog();
you can get more details here Laravel Enable Query Log
Method 3
Another approach to display all queries used in Laravel without enabling the query log install the LaravelDebugBar from here Laravel Debug Bar.
It is a package that allows you to quickly and easily keep tabs on your application during development.
To print the raw sql query, try:
DB::enableQueryLog();
// Your query here
$queries = DB::getQueryLog();
print_r($queries);
Reference
Here is a helper function who tells you the last SQL executed.
use DB;
public static function getLastSQL()
{
$queries = DB::getQueryLog();
$last_query = end($queries);
// last_query is the SQL with with data binding like
// {
// select ? from sometable where field = ? and field2 = ? ;
// param1,
// param2,
// param3,
// }
// which is hard to read.
$last_query = bindDataToQuery($last_query);
// here, last_query is the last SQL you have executed as normal SQL
// select param1 from sometable where field=param2 and field2 = param3;
return $last_query
}
Here is the bindDataToQuery function, who fill the '?' blanks with real params.
protected static function bindDataToQuery($queryItem){
$query = $queryItem['query'];
$bindings = $queryItem['bindings'];
$arr = explode('?',$query);
$res = '';
foreach($arr as $idx => $ele){
if($idx < count($arr) - 1){
$res = $res.$ele."'".$bindings[$idx]."'";
}
}
$res = $res.$arr[count($arr) -1];
return $res;
}
It is so strange that the laravel haven't support any way to get the raw sql easily, it is now version 6 after all...
Here's a workaround I used by myself to quickly get the raw sql with parameters without installing any extension...
Just deliberately make your original sql WRONG
Like change
DB::table('user')
to
DB::table('user1')
where the table "user1" does not exist at all!
Then run it again.
Sure there will be an exception reported by laravel.
SQLSTATE[42S02]: Base table or view not found: 1146 Table 'user1' doesn't exist (SQL: ...)
And now you can see the raw sql with parameters is right after the string "(SQL:"
Change back from the wrong table name to the right one and there you go!
In Laravel 5.4 (I didn't check this in other versions), add this function into the
"App"=>"Providers"=>"AppServiceProvider.php" .
public function boot()
{
if (App::isLocal()) {
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+'
);*/
Log::notice("[USER] $query");
}
);
}
}
After that install,
https://github.com/ARCANEDEV/LogViewer
and then you can see every executed SQL queries without editing the code.
To get mysql query in laravel you need to log your query as
DB::enableQueryLog();
App\User::where('balance','>',0)->where(...)->get();
print_r(DB::getQueryLog());
Check reference : https://laravel.com/docs/5.0/database#query-logging
Instead of interfering with the application with print statements or "dds", I do the following when I want to see the generated SQL:
DB::listen(function ($query) {
Log::info($query->sql, $query->bindings);
});
// (DB and Log are the facades in Illuminate\Support\Facades namespace)
This will output the sql to the Laravel log (located at storage/logs/laravel.log). A useful command for following writes to this file is
tail -n0 -f storage/logs/laravel.log
A simple way to display all queries used in Laravel without any code changes at all is to install the LaravelDebugBar (https://laravel-news.com/laravel-debugbar).
As part of the functionality you get a tab which will show you all of the queries that a page has used.
Try this:
$results = App\User::where('balance','>',0)->where(...)->toSql();
dd($results);
Note: get() has been replaced with toSql() to display the raw SQL query.
A very simple and shortcut way is below
Write the name of column wrong like write 'balancedd' in spite of 'balance' and the query will be displayed on error screen when you execute code with all the parameters and error that column not found.
DB::enableQueryLog();
(Query)
$d= DB::getQueryLog(); print"<pre>"; print_r ($d); print"</pre>";
you will get the mysql query that is just run.
There is actually no such thing in Laravel and even PHP, since PHP internally sends the parameters with query string to the database where it (possibly) become parsed into raw query string.
The accepted answer is actually optimistic solution, kind of "optionally works".

phpunit testing ???? how shall i compare to xml files before and after api function call(the function contains the stored procedure)

after searching for a long time got this great article its really very nice
but i am facing a bit problem here in my stuff as u have used direct mysql query in api i have used stored procedure in here and every time i have to compare two XML before and after even for a single short and sweet query so is there any alternative for this process but which is this secure
please chk this out u will get i more clearly
database testing in php using phpunit,simpletest on api haveing stored procedure
or how shall i compare to xml files before and after api function call(the function contains the stored procedure)
means i am able to get the before state with mysql-dump but the after but not getting the instant after xml state
sorry for the English but tried my best
thanks for the help friend
have to write an unit test test for the api function
public function delete($userId)
{
// this function calls a stored procedure
$sql = "CALL Delete_User_Details(:userId)";
try {
$db = parent::getConnection();
$stmt = $db->prepare($sql);
$stmt->bindParam("userId", $userId);
$stmt->execute();
$id = $stmt->fetchObject();
if ($id == null) {
$delete_response->createJSONArray("DATABASE_ERROR",0);
} else {
$delete_response->createJSONArray("SUCCESS",1);
}
} catch (PDOException $e) {
$delete_response->createJSONArray("DATABASE_ERROR",0);
}
return $delete_response->toJSON();
}
i have writen this unit test for it now want to write an dbunit for it
public function testDeleteUser()
{
$decodedResponse = $response->json();
$this->assertEquals($response->getStatusCode(), 200);
$this->assertEquals($decodedResponse['status']['StatusMSG'], 'SUCCESS');
$this->assertEquals($decodedResponse['status']['Code'], '1');
}
help guyss
u can just simply test it before by calling the query like
$sql = "select * from user";
and compare it with BeforeDeleteUser.xml
And the Call Ur stored procedure
$sql = "CALL Delete_User_Details(:userId)";
And for the after case just repeat the before one again
$sql = "select * from user";
and compare it with AfterDeleteUser.xml
see the logic is very simple if u have 5 Users in BeforeDeleteUser.xml and it results true and after the call of CALL Delete_User_Details(:userId) stored procedure , the AfterDeleteUser.xml should contain only 4 user (or maybe idDelete field to 0 that depends on ur implementation)

Echo query before execution and without execution in codeigniter Active Record

I am looking for a way to see generated string of the query but without executing it.
Note that the query hasn't been executed before. (I do not want $this->db->last_query();)
I hope there be a method with a name like $this->db->echo_query_string($table_name = ''); to be used exactly like $this->db->get($table_name = ''); BUT THE ONLY DIFFERENCE BE THAT get() executes the code, but echo_query_string() just echoes the string of query without execution.
You can see the compiled query by either of these functions
/* SELECT */ $this->db->_compile_select();
/* INSERT */ $this->db->_insert();
/* UPDATE */ $this->db->_update();
You don't need to change any file in codeigniter because it already provides a method to do that.
Using
echo $this->db->last_query();
will produce
select * from some_table...
And this is it.
I added this little method in DB_active_rec.php
function return_query()
{
return $this->_compile_select();
}
Usage
$this->db->select('id,user_name')->from('user')->where('id',1);
$string = $this->db->return_query();
echo $string;
Result
SELECT `id`, `user_name` FROM (`user`) WHERE `id` = 1
In this way you are bound to use
$this->db->from()
Instead of
$this->db->get()
Which runs the query
You can use some public methods to get SQL queries
Get a SELECT query
$sql = $this->db->get_compiled_select();
Get a INSERT query
$sql = $this->db->get_compiled_insert();
Get a UPDATE query
$sql = $this->db->get_compiled_update();
Get a DELETE query
$sql = $this->db->get_compiled_delete();
As of version 3 of Codeigniter, please refer to this url and also to this.
echo $this->db->update_string(); OR echo $this->db->get_compiled_update();
echo $this->db->insert_string(); OR $this->db->get_compiled_insert();
echo $this->db->get_compiled_delete();
echo $this->db->get_compiled_select();
From CI 3.1.11 The below code will help you
$this->db->get_compiled_select()
Form more details visit https://codeigniter.com/userguide3/database/query_builder.html#selecting-data

Trying to write a PHP function for mysql, SELECT SUM()

I am trying to write a PHP function which gets the sum of values in 1 column of a table. MY SQL statement works just fine. However, when I write my function and attempt to echo the variable into my HTML code, it returns '0'.
Here is my function:
function get_asset_value($org_ID) {
global $db;
$query = "SELECT SUM(asset_value) FROM assets
WHERE org_ID = '$org_ID'";
$asset_sum = $db->query($query);
$asset_sum = $asset_sum->fetch();
return $asset_sum;
In my HTML, I have the following:
<?php echo $asset_sum; ?>
I'm not sure if this has to do with the "fetch" portion of my function. I really don't know what fetch does but I tried copying/modifying this piece of code from a working function (which doesn't return the sum, but it is a select statement).
Thank you!
In addition to
SELECT SUM(asset_value) AS the_sum FROM assets WHERE ord_ID = '$ord_ID';
...
return $asset_sum['the_sum']
by Brad,
you better do
$safer = mysql_real_escape_string($org_ID);
then do,
SELECT SUM(asset_value) AS the_sum FROM assets WHERE ord_ID = '$safer';
...
return $asset_sum['the_sum']
SELECT SUM(asset_value) AS the_sum FROM assets WHERE ord_ID = '$ord_ID';
...
return $asset_sum['the_sum'];
The issue is, you are returning an entire record, rather than just the field you want.
Also, judging by the way you are inserting that ID in your query, I suspect you are open to SQL injection. You should really learn to do prepared queries with PDO.

Is it best to make fewer calls to the database and output the results in an array?

I'm trying to create a more succinct way to make hundreds of db calls. Instead of writing the whole query out every time I wanted to output a single field, I tried to port the code into a class that did all the query work. This is the class I have so far:
class Listing {
/* Connect to the database */
private $mysql;
function __construct() {
$this->mysql = new mysqli(DB_LOC, DB_USER, DB_PASS, DB) or die('Could not connect');
}
function getListingInfo($l_id = "", $category = "", $subcategory = "", $username = "", $status = "active") {
$condition = "`status` = '$status'";
if (!empty($l_id)) $condition .= "AND `L_ID` = '$l_id'";
if (!empty($category)) $condition .= "AND `category` = '$category'";
if (!empty($subcategory)) $condition .= "AND `subcategory` = '$subcategory'";
if (!empty($username)) $condition .= "AND `username` = '$username'";
$result = $this->mysql->query("SELECT * FROM listing WHERE $condition") or die('Error fetching values');
$info = $result->fetch_object() or die('Could not create object');
return $info;
}
}
This makes it easy to access any info I want from a single row.
$listing = new Listing;
echo $listing->getListingInfo('','Books')->title;
This outputs the title of the first listing in the category "Books". But if I want to output the price of that listing, I have to make another call to getListingInfo(). This makes another query on the db and again returns only the first row.
This is much more succinct than writing the entire query each time, but I feel like I may be calling the db too often. Is there a better way to output the data from my class and still be succinct in accessing it (maybe outputting all the rows to an array and returning the array)? If yes, How?
Do you actually have a performance issue?
If your current setup works and doesn't suffer from performance issues, I wouldn't touch it.
This sort of DB access abstraction will likely become a maintenance issue and probably won't help performance.
Also, you're susceptible to SQL injection.
You should be able to store the whole object from the query into a variable and then access the single values from that object:
$object = $listing->getListingInfo('','Books');
$title = $object->title;
$price= $object->price;
But you can also use fetch_assoc() and return the whole assiciative array:
$array = $listing->getListingInfo('','Books');
$title = $object['title'];
$price= $object['price'];
This will give you the same results and also with only one query to the DB.
EDIT: If the getListingInfo() is the only function you should think of the following:
rename the function to prepareListingInfo() and within the function only prepare the query and store it in a class variable.
add a getNextListingInfo() function, which will return an object or associative array with the next row.
Using this new function, you can get every row that matches your query.
Either cache the result in an internal var
Or Comment it with a warning and explain to function users to copy the result in an var instead of calling it again and again with the same params
Yes, that would be calling the db too often.
A couple of solutions
1) put the listing info in a variable
2) cache the results in a hashmap or dictionary (be careful for memory leaks)

Categories