Execute stored procedure in directus headless cms - mysql

I just find directus headless cms
Looks awesome. It resolve many uses cases for me.
But I am concerned about how to achieve transactions, aggregate functions or complex queries. I understand that maybe is out scope.
If a custom endpoint or graphql allow me execute a stored procedure i will have all my needs achieved.
Is it possible?

Hi finally I find how to use custom endpoints to do plain querys, including stored procedures.
Maybe is possible implement a module for add admin gui option for that, I try work in that, for the moment this is the example for a select:
use Directus\Application\Http\Request;
use Directus\Application\Http\Response;
return [
'' => [
'method' => 'GET',
'handler' => function (Request $request, Response $response) {
$container = \Directus\Application\Application::getInstance()->getContainer();
$dbConnection = $container->get('database');
$tableGateway = new \Zend\Db\TableGateway\TableGateway('directus_users', $dbConnection);
$query = $tableGateway->getAdapter()->query("select * from productos where 1=1");
$result = $query->execute();
if ($result->count() > 0) {
$returnArr = array();
while ($result->valid()) {
$returnArr[] = $result->current();
$result->next();
}
if (count($returnArr) > 0) {
return $response->withJson([
'data' => [
$returnArr,
],
]);
}
}
return "{}";
},
],
];
Sorry for my bad English.

Related

Does Laravel clone query reduce query time?

When I have to get paid and pending orders, I searched and found a way to clone the query.
$paid = $products->clone()->where('paid', 1)->count();
$pending = $products->clone()->where('paid', 0)->count();
I wonder if this approach saves query time or if we still send two requests to the database server.
Thanks
laravel added the Illuminate\Support\Benchmark utility class in version 9.32. If you have it available, you can test for yourself.
use Illuminate\Support\Benchmark;
public function yourControllerMethod()
{
$products = Product::query();
$iterations = 100;
Benchmark::dd(
[
'cloning' => function () use ($products) {
$products->clone()->where('paid', 1)->count();
$products->clone()->where('paid', 0)->count();
},
'not cloning' => function () {
Product::query()->where('paid', 1)->count();
Product::query()->where('paid', 0)->count();
},
],
$iterations
);
}
Both approaches will execute the same amount of SQL queries though. I think the time saved (if any) will be minimal.

Retrieve specific data using JSON decode Laravel

I'm new to Laravel. I need to retrieve specific data from the database using the JSON decode. I am currently using $casts to my model to handle the JSON encode and decode.
This is my insert query with json encode:
$request->validate([
'subject' => 'required|max:255',
'concern' => 'required'
]);
$issue = new Issue;
$issue->subject = $request->subject;
$issue->url = $request->url;
$issue->details = $request->concern;
$issue->created_by = $request->userid;
$issue->user_data = $request->user_data; //field that use json encode
$issue->status = 2; // 1 means draft
$issue->email = $request->email;
$issue->data = '';
$issue->save();
The user_data contains {"id":37,"first_name":"Brian","middle_name":"","last_name":"Belen","email":"arcega52#gmail.com","username":"BLB-Student1","avatar":"avatars\/20170623133042-49.png"}
This is my output:
{{$issue->user_data}}
What I need to retrieve is only the first_name, middle_name, and last_name. How am I supposed to achieve that? Thank you in ADVANCE!!!!!
As per the above code shown by you it will only insert data into the database.For retrieving data you can make use of Query Builder as i have written below and also you can check the docs
$users = DB::table('name of table')->select('first_name', 'middle_name', 'last_name')->get();
I will recommend using Resources. It really very helpful laravel feature. Check it out. It is a reusable class. You call anywhere and anytime.
php artisan make:resource UserResource
Go to your the newly created class App/Http/Resources/UserResource.php and drfine the column you want to have in your response.
public function toArray($request) {
return [
"first_name" => $this->first_name,
"middle_name" => $this->middle_name,
"last_name" => $this->last_name
]
}
Now is your controller you can use the UserResource like folow:
public function index()
{
return UserResource::collection(User::all());
}
Or after inserting data you can return the newly added data(f_name, l_name...)
$user = new User;
$user->first_name= $request->first_name;
$user->middle_name= $request->middle_name;
$user->last_name= $request->last_name;
$user->save();
$user_data= new UserResource($user);
return $user_data;

Laravel 5: How to dump SQL query?

Laravel 5's built-in solution
In Laravel 5+, we can use \DB::getQueryLog() to retrieve all executed queries. Since, query logging is an extensive operation and cause performance issues so it's disabled by default in L5 and only recommend for development environments only. We can enable the query logging by using the method \DB::enableQueryLog(), as mentioned in [Laravel's documentation][1].
Problem in built-in solution
The DB::getQueryLog() function is great but sometimes we wish that it would be great if we get dump in flat SQL format, so we can copy/past it in our favorite MySQL application like phpMyAdmin or Sqlyog to execute it and debug or optimize it.
So, I need a helper function that helps me to produce dump with following additional info:
On which file and line number the dump has called.
Remove back-ticks from the query.
Flat query, so don't need to update binding parameters manually and I can copy/past SQL in phpMyAdmin etc to debug/optimize the query.
Custom Solution
Step 1: Enable Query Logging
Copy/past following block of code on top of route file:
# File: app/Http/routes.php
if (\App::environment( 'local' )) {
\DB::enableQueryLog();
}
Step 2: Add helper function
if (!function_exists( 'dump_query' )) {
function dump_query( $last_query_only=true, $remove_back_ticks=true ) {
// location and line
$caller = debug_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS, 1 );
$info = count( $caller ) ? sprintf( "%s (%d)", $caller[0]['file'], $caller[0]['line'] ) : "*** Unable to parse location info. ***";
// log of executed queries
$logs = DB::getQueryLog();
if ( empty($logs) || !is_array($logs) ) {
$logs = "No SQL query found. *** Make sure you have enabled DB::enableQueryLog() ***";
} else {
$logs = $last_query_only ? array_pop($logs) : $logs;
}
// flatten bindings
if (isset( $logs['query'] ) ) {
$logs['query'] = $remove_back_ticks ? preg_replace( "/`/", "", $logs['query'] ) : $logs['query'];
// updating bindings
$bindings = $logs['bindings'];
if ( !empty($bindings) ) {
$logs['query'] = preg_replace_callback('/\?/', function ( $match ) use (&$bindings) {
return "'". array_shift($bindings) . "'";
}, $logs['query']);
}
}
else foreach($logs as &$log) {
$log['query'] = $remove_back_ticks ? preg_replace( "/`/", "", $log['query'] ) : $log['query'];
// updating bindings
$bindings = $log['bindings'];
if (!empty( $bindings )) {
$log['query'] = preg_replace_callback(
'/\?/', function ( $match ) use ( &$bindings ) {
return "'" . array_shift( $bindings ) . "'";
}, $log['query']
);
}
}
// output
$output = ["*FILE*" => $info,
'*SQL*' => $logs
];
dump( $output );
}
}
How to use?
Take dump of last executed query, use just after the query execution:
dump_query();
Take dump of all executed queries use:
dump_query( false );
On which file and line number the dump has
called.
I don't understand why you need this because you always know where you called the dump function but never mind you have your solution for that.
Remove back-ticks from the query.
You don't need to remove back-ticks as the query will work in MySQL along with them also.
Flat query, so don't need to update binding parameters manually and I can copy/past SQL in phpMyAdmin etc to debug/optimize the query.
You can use vsprintf for binding parameters as:
$queries = DB::getQueryLog();
foreach ($queries as $key => $query) {
$queries[$key]['query'] = vsprintf(str_replace('?', '\'%s\'', $query['query']), $query['bindings']);
}
return $queries;
And I would suggest you to checkout this github repo squareboat/sql-doctor
I was looking for simple solution and the one below worked for me.
DB::enableQueryLog();
User::find(1); //Any Eloquent query
// and then you can get query log
dd(DB::getQueryLog());
Reference Links:
How to Get the Query Executed in Laravel 5? DB::getQueryLog() Returning Empty Array
https://www.codegrepper.com/code-examples/php/dump+sql+query+laravel
Add this code in the top of your routes file.
Laravel 5.2 routes.php
Laravel 5.3+ web.php
<?php
// Display all SQL executed in Eloquent
Event::listen('Illuminate\Database\Events\QueryExecuted', function ($query) {
var_dump($query->sql);
var_dump($query->bindings);
var_dump($query->time);
echo "<br><br><br>";
});
For a Laravel 8 application it could be useful to put the following in the AppServiceProvider.php file:
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
// [...]
// Dump SQL queries on demand **ONLY IN DEV**
if (env('APP_ENV') === 'local') {
DB::enableQueryLog();
Event::listen(RequestHandled::class, function ($event) {
if ( $event->request->has('sql-debug') ) {
$queries = DB::getQueryLog();
Log::debug($queries);
dump($queries);
}
});
}
// [...]
}
Then appending &sql-debug=1 to the url will dump the queries.

CakePHP 3 - Can't return proper json when debug mode = true

I'm new to stackoverflow, and I've just started to play around with CakePHP 3.
I've run into a weird problem:
I'm sending an ajax-request (form submit) to the controller, and I expect to get a proper json-response back. It works fine when I set debug mode to false in config/app.php, but when it's set to true, I get an error-message in the browsers console, and the responsetext seem to be html. I'm calling the action with the .json extension in the url.
I've linked screenshot of the console where the first response is with debug mode set to false, and the second set to true:
I have enabled the extensions in config/routes.php:
Router::scope('/', function (RouteBuilder $routes) {
$routes->extensions(['json', 'xml']);
(...)
Here's the controller-code:
public function getUserStats() {
$this->log($this->request->data, 'debug');
if (($this->request->is('post'))) {
$this->log('getCategories(): Post-request is received.', 'info');
$usersTable = TableRegistry::get('Users');
$q = $usersTable->find('statsByUsers', $this->request->data);
$users = $q->all();
// Calculating total amount per user.
foreach ($users as $u) {
foreach ($u->purchases as $p) {
$u->total += $p->total;
}
}
$this->log($users, 'debug');
$this->set('users', $users);
$this->set('_serialize', ['users']);
}
}
Here's the model code:
public function findStatsByUsers(Query $query, array $options) {
debug($options);
$options['dates'] = $this->getConvertedDates($options);
$query
->contain([
'Purchases' => function($q) use($options) {
return $q
->select(['id', 'total' => 'amount * count', 'purchase_date', 'user_id'])
->where(['purchase_date BETWEEN :fromDate AND :toDate',])
->bind(':fromDate', $options['dates']['fromDate'], 'datetime') // Binds the dates to the variables in where-conditions
->bind(':toDate', $options['dates']['toDate'], 'datetime');
}
])
->where([
'Users.id IN ' => $options['users'],
'Users.active' => true
]);
return $query;
}
I hope I've given you enough information so that you can help me solve this.
CakePHP version: 3.3.2
Looking at the bit of output that is visible in the screenshot
<div class="cake-debug-output"> ...
that HTML is output generated by the debug() function.
Look closely at your model code, and you should spot the call to the function. Remove it, and you should be good.
btw, the source of the call can be found in the first <span> element in the <div>, so if you experience similar problems in the future make sure to check that.
<?php
use Cake\Core\Configure;
// your class ,...
public function getUserStats() {
$this->log($users, 'debug');
Configure::write('debug',false); // DISABLE
$this->set('users', $users);
$this->set('_serialize', ['users']);
}

Yii framework 2.0 pass parameter to eager loading relational database table

Working with Yii framework 2.0 I tried to retrieve data from my relational database tables following the documentation here http://www.yiiframework.com/doc-2.0/guide-db-active-record.html
Below is the code sample under the section Lazy and Eager Loading.
$customers = Customer::find()->limit(100)->with([
'orders' => function($query) {
$query->andWhere('subtotal>100');
},
])->all();
In my case I want to pass a parameter to the andWhere() method as following.
$param = 'something flexible';
$customers = Customer::find()->limit(100)->with([
'orders' => function($query) {
$query->andWhere('subtotal > ' . $param);
},
])->all();
It does not work this way. What do I miss or how can I pass the parameter from the first line to the andWhere() method?
I found the solution as following.
$param = 'something flexible';
$customers = Customer::find()->limit(100)->with([
'orders' => function($query) use($param) {
$query->andWhere('subtotal > ' . $param);
},
])->all();