How to handle query errors in Zend? - php

I have a simple question.
I am working on Zend framework 2.
I am trying to make an AJAX call to fetch all booking data from table booking by passing the booking_id. Trouble is, the query is failing for reasons unknown. The actual query is complex and its working when I replace $booking_id with an actual booking_id like '22432'. Hence, I believe that the query is fine, there is some other issue.
But I don't know how to fetch the query errors/exceptions in an Ajax call. Can someone help me with this?
Javascript:
$.post("dashboard/getBookingDataByBookingId", {
booking_id: bookingId,
},
function(data){
if(data.response == true) {
alert(data);
} else {
alert('failed');
}
}, 'json');
Controller
public function getBookingDataByBookingIdAction()
{
$request = $this->getRequest();
$response = $this->getResponse();
if ($request->isPost())
{
$post_data = $request->getPost();
$booking_id = $post_data['booking_id'];
$booking_data = array();
$booking_data = $this->getBookingTable()->getBookingByUserIdAndBookingId($booking_id);
if (!$booking_data)
$response->setContent(\Zend\Json\Json::encode(array('response' => false, 'booking_data' => $booking_data)));
else {
$response->setContent(\Zend\Json\Json::encode(array('response' => true, 'booking_data' => $booking_data)));
}
}
return $response;
}
The bookingTable model has a public function:
public function getBookingByUserIdAndBookingId($booking_id)
{
$sql = "Select * from booking where id='".$booking_id."';
try {
$statement = $this->adapter->query($sql);
$res = $statement->execute();
return $res->current();
} catch (Exception $ex) {
return $ex;
}
}

You are posting a variable named 'id':
{
id: bookingId,
}
So you should access it as:
$post_data = $request->getPost();
$booking_id = $post_data['id'];
or more concisely:
$booking_id = $request->getPost('id');
You should also be using parameterised queries to avoid SQL injection.

For Getting errors/exceptions in an Ajax call use:
In Google Chrome use: POSTMAN Extension
In FireFox user: FIREBUG Plugin

Related

Call to undefined method CI_DB_mysqli_driver::groupBy()

I've created a web app using code igniter 3 to get data from 3 tables and display them in the view (quiz_table,question_table and answers_table).
Below is the code in my controller,
public function loadSingleQuizData_get()
{
$quizId = $this->uri->segment(3);
$this->load->model('QuizModel');
$singleQuizQuestionData = $this->QuizModel->getSingleQuizQuestionDataFromDB($quizId);
$data = array('singleQuizQuestionData' => $singleQuizQuestionData);
print json_encode($data);
}
and below is the code in the model
function getSingleQuizQuestionDataFromDB($quizId)
{ //insert query
try {
$this->db->select('quiz_table.quizName');
$this->db->select('quiz_table.creatorName');
$this->db->select('quiz_table.rating');
$this->db->select('question_table.questionId');
$this->db->select('question_table.questionTitle');
$this->db->select('question_table.correctAnswer');
$this->db->select('answer_table.answer');
$this->db->from('quiz_table');
$this->db->where('quiz_table.quizId',$quizId);
$this->db->join('question_table','question_table.quizId = quiz_table.quizId','INNER');
$this->db->join('answer_table','answer_table.questionId= question_table.questionId','INNER');
$this->db->from('quiz_table');
$this->db->groupBy(['quiz_table.quizId', 'question_table.questionId']);
$result = $this->db->get();
$singleQuizQuestionData= $result->result_array();
return $singleQuizQuestionData;
} catch (Exception $e) {
// log_message('error: ',$e->getMessage());
return;
}
}
When I try to load the results in the view I get the below error message
Please help!
https://codeigniter.com/userguide3/database/query_builder.html
The syntax for group by in codeigniter is group_by not groupBy (that would be laravel)

Slim Framework - How to query db in normal function

I'm very new to PHP and Slim Framework which helps creating APIs.
Everything is ok If i query db inside $app->post or get. But I want to separate it to normal function. It will help when I need to use it later in other APIs.
I tried to call this
$app->get('/search/[{phone}]', function($request, $response, $args) use ($app){
$token = $response->getHeader('token');
// $phone = $args['phone'];
if (isTokenValid($token)){
return $this->response->withJson("valid");
}
return $this->response->withJson("invalid");
});
My isTokenValid() function
function isTokenValid($token){
$sql = 'SELECT id FROM users WHERE token = :token';
$s = $app->db->prepare($sql); //<< this line 25
$s->bindParam(':token', $token);
if ($s->execute()){
if($sth->rowCount() > 0){
return true;
}
}
return false;
}
But I get 500 Internal Server Error
Type: Error
Message: Call to a member function prepare() on null
File: /Applications/MAMP/htdocs/aigoido/src/functions.php
Line: 25
How to call it outside $app? Thanks.
You want to create a dependency injection container for your database connection and pass that object in as the function parameter rather than app object. This makes the db connection reusable throughout your app.
https://www.slimframework.com/docs/concepts/di.html
Also, you can return $response rather than $this->response.
$c = $app->getContainer();
$c['db'] = function() {
return new DB($host,$user,$pass,$name);
};
$app->post('/search/[{phone}]', function($request, $response, $args) use ($c) {
$token = $response->getHeader('token');
// $phone = $args['phone'];
if (isTokenValid($c->db,$token)){
return $response->withJson("valid");
}
return $response->withJson("invalid");
});
function isTokenValid($db, $token){
$sql = 'SELECT id FROM users WHERE token = :token';
$s = $db->prepare($sql);
$s->bindParam(':token', $token);
if ($s->execute()){
if($sth->rowCount() > 0){
return true;
}
}
return false;
}
Pass $app to your function as parameter. The function has it own context so $app is not available without that.
function isTokenValid($token, $app){
$sql = 'SELECT id FROM users WHERE token = :token';
$s = $app->db->prepare($sql); //<< this line 25
$s->bindParam(':token', $token);
if ($s->execute()){
if($sth->rowCount() > 0){
return true;
}
}
return false;
}

How to replace Slim::getInstance() in Slim 3

I am currently trying to follow a Slim tutorial that is utilizing $app = Slim::getInstance(); I don't know much about Slim, so the solutions to use a container do not make sense to me. What can I do to make my function provided below actually run?
function jsonResponse($data, $code = 200)
{
$app = Slim::getInstance();
$app->response->setStatus($code);
$app->response->headers->set(
'Content-type',
'application/json; charset=utf-8'
);
return $app->response->setBody(json_encode($data));
}
I am calling this inside another function for logging in that looks like this:
function login($request) {
$user = json_decode($request->getBody());
$username = $user->username;
$password = $user->password;
if (empty($username) || empty($password)) {
$error = 'Username and password are required';
// Bad request
return jsonResponse($error, 400);
}
$sql = "SELECT first_name, username FROM users "
. "WHERE username = '$username' AND password = '$password'";
$db = getConnection();
$row = array();
try {
$result = $db->query($sql);
if (!$result) {
$error = 'Invalid query: ' . mysql_error();
// Internal server error
return jsonResponse($error, 500);
}
$user = $result->fetchAll(PDO::FETCH_OBJ);
if (empty($user)) {
// Unauthorized
return jsonResponse($error, 401);
}
$row["user"] = $user;
$db = null;
} catch(PDOException $e) {
error_log('{"error":{"text":'. $e->getMessage() .'}}');
// $error = array( 'error' => array ( 'text' => $e->getMessage() ) );
// Internal server error
return jsonResponse($error, 500);
}
// OK, default is 200
return jsonResponse($row);
}
My route for the login function is $app->post('/login_user', 'login');
tl;dr I would like an explanation on how to convert older Slim code that uses getInstance().
Thank you!
It's actually pretty straightforward. In this particular case you don't need jsonResponse() function at all. Your login controller will need these changes:
function login($request, $response, $args) {
// ... some code ...
if ($isError) {
return $response->withStatus(500)->withJson($error);
}
return $response->withJson($row); // Status=200 is default.
}
In general, as was said in the comments, Slim3 has no static method to get a Singleton instance. If you wanted to hook on the response object in Slim3, the best way would be to create a middleware.
Or, if you really wanted to access $response from external function, you pass it as a function parameter (respecting dependency injection pattern and keeping code testable): jsonResponse($response, $error, 500);.
Technically, $app is a global variable, but I would suggest against accessing it through $GLOBALS.

how to display data from database using $.post

hey iam trying to take data from data base using $.post. Here iam taking db data as json ecoded. But i couldn't display or alert the data. If possible how can i display the json array? how can i check the database values in json format? pls help me. iam using codeigniter
function profile_view(id3)
{
$.post("<? echo base_url();?>Attendance/Prev_leave_record", {id:id3},function(data){
//do something
});
}
controller
function Prev_leave_record()
{
$teacher_id=$this->input->post('id');
$teacher_details=$this->AM->prev_record($teacher_id);
$out=array(
'teacher_details'=>$teacher_details);
// echo '{"teacher_details":'.json_encode($teacher_details).'}';
echo json_encode($out);
}
model
function prev_record($teacher_id)
{
$this->db->select('leave_from_date,leave_to_date');
$this->db->from('leave_data');
$this->db->where('applied_user_id',$teacher_id);
$teacher_details=$this->db->get();
return $teacher_details;
}
Try this
Model:
Your model made a query but didn't return the result of the query.
See Returning Query Results.
function prev_record($teacher_id)
{
//This is opinion, but it will be much more efficient
//not using Query Builder for such a simple query
$sql = "SELECT leave_from_date, leave_to_date FROM leave_data WHERE applied_user_id = ?";
$query = $this->db->query($sql, [$teacher_id]);
//always check that the query produced results
//the next statement returns one row as an array or
//returns NULL if the query produced no results
return $query->num_rows() > 0 ? $query->row_array(): NULL;
}
Controller:
function Prev_leave_record()
{
$teacher_id = $this->input->post('id');
$teacher_details = $this->AM->prev_record($teacher_id);
if(isset($teacher_details))
{
$out['results'] = "Success";
$out['teacher_details'] = $teacher_details;
}
else
{
$out['results'] = "Failed";
}
echo json_encode($out);
}
javascript:
function profile_view(id3)
{
$.post("<? echo base_url();?>attendance/prev_leave_record", {id:id3},
function(data)
{
console.log(data); //so you can see the structure returned
if(data.results === "Success){
alert("Cool, it worked: " + data.teacher_details);
} else {
alert("Opps, we didn't get anything.");
}
}
);
}
Try this,
function profile_view(id3)
{
$.post("<? echo base_url();?>Attendance/Prev_leave_record", {id:id3},function(data){
console.log(data); // or alert(data);
});
}
Then check the console from Inspect element from browser (F12 or ctrl+shift+i)

Laravel 4 - logging SQL queries

There are already several questions in regards to logging the SQL query in Laravel 4. But I've tried almost all of them and it's still not working the way I want.
Here's my situation
in my php view file, I make AJAX request to the server
The AJAX request is received and runs a RAW parameterized Postgres SQL query (e.g.
DB::select('select * from my_table where id=?', array(1))
If I use
Event::listen('illuminate.query', function($sql)
{
Log::error($sql);
});
I just get "select * from my_table where id=?" as the log message without the ID value actually populated.
If I use
$queries = DB::getQueryLog();
$last_query = end($queries);
Log::error(print_r($last_query, true));
I still don't have the final SQL query with the ID populated.
Finally, if I use a logging tool like https://github.com/loic-sharma/profiler - it doesn't display anything since I'm making an AJAX request.
Have I exhausted my options? Is there still another better way?
Here is what I am currently using for logging of sql queries. You should be able to drop this into your main routes file then add 'log' => true into your database config.
if (Config::get('database.log', false))
{
Event::listen('illuminate.query', function($query, $bindings, $time, $name)
{
$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);
Log::info($query, $data);
});
}
Thanks to Jeemusu answer for the bit about inserting the bindings into the prepared statement.
You should be able to find the bindings by passing $bindings as the second parameter of the Event function.
Event::listen('illuminate.query', function($sql, $bindings, $time){
echo $sql; // select * from my_table where id=?
print_r($bindings); // Array ( [0] => 4 )
echo $time; // 0.58
// To get the full sql query with bindings inserted
$sql = str_replace(array('%', '?'), array('%%', '%s'), $sql);
$full_sql = vsprintf($sql, $bindings);
});
In Laravel 3.x I think the event listener was called laravel.query
Continuing on #Collin James answer.
If you want to log to a seperate file only for sql, you can do it with this:
if (Config::get('database.log', false)) {
Event::listen('illuminate.query', function($query, $bindings, $time, $name) {
$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);
$log = new Logger('sql');
$log->pushHandler(new StreamHandler(storage_path().'/logs/sql-' . date('Y-m-d') . '.log', Logger::INFO));
// add records to the log
$log->addInfo($query, $data);
});
}
With this at the top of your file:
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
This will log all your queries to a file named sql-YYYY-mm-dd.log in storage/logs/.
While the accepted answer stands correct, this answer explains how to update loic-sharma profiler when making Ajax requests using jQuery. Using this approach one doesn't need to read file logs.
Step 1
The first problem is to send the updated profiler data to the client on every Ajax-request. This can be solved using the "after" events of the Laravel application.
app/filters.php:
App::after(function($request, $response)
{
// If it's a JsonResponse and the profiler is enabled, include it in the response.
if($response instanceof \Illuminate\Http\JsonResponse && Profiler::isEnabled()) {
$profiler = Profiler::getFacadeRoot();
$profilerJson = json_encode($profiler->render());
$content = substr($response->getContent(), 0, -1) . ',"profiler":' . $profilerJson . '}';
$response->setContent($content);
}
});
The App::after filter will run upon every Laravel request. The first line of the closure above, makes sure that it will only continue if a the response is of type JsonResponse and the profiler is enabled. If that is the case, render the profiler and append the HTML to the JSON object.
Note: this code assumes that the returned JSON is a object. So it will fail for arrays: Response::json(array(1,2,3)).
Step 2
Now that the updated profiler HTML is being sent to the client, we must update the DOM with the new profiler HTML using javascript. This should happen every time the client gets a JSON response. jQuery provides global Ajax event handlers, which is perfect to achive this.
$(document).ajaxSuccess(function(event, request, settings) {
try {
json = jQuery.parseJSON(request.responseText);
if(json.profiler) {
renderProfiler(json.profiler);
}
} catch(error) {
// Its not JSON.
return;
}
});
Here's a method to replace the old profiler with the new one:
renderProfiler = function(data) {
// Remove previous
$anbu = $('.anbu');
$anbu.prev().remove(); // Removes <style> tag of profiler
$anbu.next().next().remove(); // Removes the inline script tag of profiler
$anbu.next().remove(); // Removes jQuery script tag by the profiler
$anbu.remove(); // Removes the <div> tag of profiler
$(document.body).append(data);
};
Using it
Now it is as simple as returning responses as:
return Response::json(array(
'user' => Auth::user()
));
Laravel will append the profiler HTML. The javascript will catch the JSON response and update the DOM. You will have the SQL queries and timings right on the web page.
Note
While the code is tested, there might be a bug or two. This is also not exactly how I do it. Instead of sending the HTML in the json response, I extend the object with the actual data from the profiler. On the client side I render the profiler using a mustache template.
While the question was originally targeted at Laravel 4, I still ended up here through google, but I'm using Laravel 5.
There are new ways to log all queries in Laravel 5 using Middleware, but if you prefer the same approach here is the same code provided by Collin James but working for Laravel 5
if (Config::get('database.log', false))
{
Event::listen('Illuminate\Database\Events\QueryExecuted', function($query)
{
$bindings = $query->bindings;
$time = $query->time;
$name = $query->connection->getName();
$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->sql);
$query = vsprintf($query, $bindings);
Log::info($query, $data);
});
}
That's what I've been using:
DB::listen(function ($query, $bindings, $time, $connection) {
$fullQuery = vsprintf(str_replace(array('%', '?'), array('%%', '%s'), $query), $bindings);
$result = $connection . ' (' . $time . '): ' . $fullQuery;
dump($result);
// You can of course log the $result
});

Categories