ZF2 - TableGateway with Mysqli driver - php

I am trying to use a TableGateway class in ZF2 with the Mysqli driver but am having loads of problems.
For some reason, any Where clause I add with a variable never gets quoted in and when the query is executed it throws the error:
Statement couldn't be produced with sql: ...
The code that is giving me problems is this:
<?php
class MyTable extends Zend\Db\TableGateway\TableGateway
{
public function get_count($id)
{
$count = $this->select(function (Zend\Db\Sql\Select $select) use ($id) {
$select->columns([
'count' => 'COUNT(field)',
]);
$select->join(['alias1' => 'other_table'], 'thing = alias1.thing', []);
$select->where([
'main_table.id' => $id,
'alias1.active' => 1,
]);
})->current();
return $count;
}
}
When I look at the error, it just shows ? where the actual values supplied should be.
If though, I select straight from the adapter like this:
// build select object similar to above example
$selectString = $sql->getSqlStringForSqlObject($select);
$results = $this->dbAdapter->query($selectString, Zend\Db\Adapter\Adapter::QUERY_MODE_EXECUTE);
Then it works perfectly. But I have to use this getSqlStringForSqlObject which I find odd. In my other projects I am using the PDO driver and I never had such an issue but for this project the mysqli driver is required.
How can I make the values supplied to where get quoted in properly?

Try using prepareStatementForSqlObject. Also, if it's possible, please show us your db config.
prepareStatementForSqlObject() will return a StatementInterface object.
getSqlStringForSqlObject() will get you you a plain sql string.

Related

Laravel 5.5 Query Builder whereRaw returns no results but raw SQL does

When I perform the scoped query below I get no results, yet when I execute the resulting SQL (with bindings transcribed) on the database I get the expected results. I can query the model without the scope and the results are as expected.
It's a straightforward query checking whether a point exists within a polygon. I see no signs of errors or exceptions. I'm at a loss. Am I missing something?
Area Class (w/ Query Scope):
namespace App;
use Illuminate\Database\Eloquent\Model;
use Grimzy\LaravelMysqlSpatial\Eloquent\SpatialTrait;
use Grimzy\LaravelMysqlSpatial\Types\Point;
use Grimzy\LaravelMysqlSpatial\Types\Polygon;
use Grimzy\LaravelMysqlSpatial\Types\Linestring;
class Area extends Model
{
use SpatialTrait;
protected $table = "areas";
protected $spatialFields = [
'point', // MySQL POINT type
'area' // MySQL POLYGON type
];
public function scopeContainsPoint($query, $lat, $lng) {
return $query->whereRaw("ST_Contains(area, GeomFromText('POINT(? ?)'))", [$lng, $lat]);
}
}
Query Scope Usage and Results:
$s = Area::containsPoint(43.80, -79.48)->get();
=> Illuminate\Database\Eloquent\Collection {#3192
all: [],
}
Eloquent Query Log:
DB::getQueryLog();
=> [
[
"query" => "select * from `areas` where ST_Contains(area, GeomFromText('POINT(? ?)'))",
"bindings" => [
-79.48,
43.8,
],
"time" => 311.05,
],
]
Resuting SQL (returns correct result):
select * from `areas` where ST_Contains(area, GeomFromText('POINT(-79.48 43.8)'));
The problem boiled down to an issue escaping the 'POINT(-79.48 43.8)' portion of the raw DB statement that for some reason didn't reveal itself on the DB::getQueryLog().
Changing from:
$query->whereRaw("ST_Contains(area, GeomFromText('POINT(? ?)'))", [$lng, $lat]);
to this:
$query->whereRaw("ST_Contains(area, GeomFromText(?))", ["POINT($lng $lat)"]);
resolved the problem and returns the expected rows.
Edit:
Also, for anyone wondering - I discovered that the Grimzy/laravel-mysql-spatial library contains the scope I was looking for (among many others). Still learned something about prepared statements though. Always read the manual.

PHP7/PDO: Returning PDOStatement Object and fetch data later

I am currently in the process of updating my web application from PHP 5.6 to PHP 7, therefore I need to alter the database abstraction class that has been using the old MySQL-Extension.
The class has a method "Query()" where SQL statements are being prepared and executed and a method "Fetch()" which fetches a single row and returns it. See the simplified versions:
function Query($query='')
{
$result = $this->connection->Prepare($query);
$result->Execute();
return $result;
}
function Fetch($resource=null)
{
return $resource->Fetch(PDO::FETCH_ASSOC);
}
So basically what I am trying to do is this:
$statement = Query('SELECT * FROM Test');
$firstRow = Fetch($statement);
print_r($statement) shows me this:
PDOStatement Object
(
[queryString] => SELECT * FROM Test
)
But when I call "Fetch", there is no row returned. Can someone tell if it's possible to return PDOStatement objects and pass them into other functions/methods for "later use"?
PS: Of course I know that this is not best practice but I am trying to avoid having to alter thousands of lines of code in the application.

How to create a query in Drupal 8

I am used to using db_select in drupal 7 but now it's deprecated in drupal 8
So, If I need to create a query to list all users from users_field_data table, What should I do?
Do I still use db_select or db_query even though they are deprecated functions? Or create a new controller to extend from "Select class" and make my query?
Depends on what you are trying to achieve.
Using the storage object
If you want to make a simple query about the users then you should use the loadByProperties of the storage object
$users = \Drupal::entityTypeManager()->getStorage('user')->loadByProperties([
'name' => 'bar'
]);
Using entity query & loadMultiple
If you need a more complex query with sorts, range, pager and OR/AND condition groups you should use entity query
$ids = \Drupal::entityQuery('user')->condition('name', 'foo')->execute();
$users = User::loadMultiple($ids);
As mentioned in the documentation you can query data by injecting Drupal's database connection class. For example:
use Drupal\Core\Database\Connection;
class DatabaseQueryExample {
protected $connection;
public function __construct(Connection $connection) {
$this->connection = $connection;
}
public function queryExamples() {
// db_query()
$this->connection->query(" ... ");
// db_select()
$this->connection->select(" ... ");
}
}
db_select, db_insert, db_update, etc... were deprecated in Drupal 8.0.x and will be removed in Drupal 9.0.0.
Instead get a database connection injected into your service from the container and call select() on it. For example, $injected_database->select($table, $alias, $options);.
eg:
$db = \Drupal::database();
$data = $db->select('table_name','t')->fields('t')->execute();
$db->insert();
$db->update();

Is there a way to prepare a sql statement in prestashop using Db instance?

I want to find something like PDO methods, that works with Prestashop DB Object, or a module, or new class that uses PDO class and prepare the statements before execution.
If I can change the following by something with PDO class
$result = Db::getIntance()->executeS('SELECT * FROM customer WHERE id = '.$id_customer);
I didn't see anything like that and I want to know if exists before make more code without prepare statements
In prestashop you can use ORM like this
Db::getInstance()->insert('target_table', array(
'id_target' => (int)$target,
'name' => pSQL($name),
));
You can use the DbQuery class for a cleaner code
$sql = new DbQuery();
//this line is optional
$sql->select('*');
//PrestaShop will add the prefix to the table
$sql->from('customer');
//or if you want to select specific columns
$sql->select('id_customer, name, etc..');
//each where line is considered as an AND
$sql->where('id = '.(int)$id_customer);
$sql->where('name = '.pSQL('name of customer'));
$result = Db::getIntance()->executeS($sql);

CodeIgniter and PostgreSQL - Retrieving data from Function returning refcursor

I have a PostgreSQL function that selects data and returns it via a refcursor, similar to the following declaration:
CREATE OR REPLACE FUNCTION my_function()
RETURNS refcursor AS
...
How do I retrieve data from this function via a CodeIgniter model? I can't just SELECT directly from the function as it does not return the data directly.
In case anyone is interested, a post on php.net gave the following solution:
protected function dbquery($query){
pg_query("BEGIN;");
$tr=pg_query($query);
$r=pg_fetch_row($tr);
$name=$r[0];
$rs=pg_query("FETCH ALL IN \"" . $name . "\";");
pg_query("END;");
return $rs;
}
Which can be wired up in the model as follows:
$query = $this->dbquery("SELECT * FROM my_function()");
while ($row = pg_fetch_assoc($query))
{
array_push($result, array('my_column' => $row['my_column'] ));
}
Not an ideal solution as it does not use the CI Postgres driver's functions (although it probably could be refactored to), but it works.
The answer above does not take advantage of the CI active record class. To do this in CI just run a custom query.
For example:
$sql = "CREATE OR REPLACE FUNCTION... "
$this->db->query($sql);

Categories