where_in codeigniter error if array is empty - mysql

I'm using Codeigniter 2. I'm trying to make a mysql query using Active Record. The problem is I got error when array passed to where_in is empty. I'm asking if there any way to ignore where_in condition if the array is empty
This the condition example :
$this->db->where_in('p.brand_id', $brands);
And this is the error I got :
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ') AND p.brand_id IN ()

Just don't call where_in() if the array is empty.
if(is_array($brands) && count($brands) > 0){
$this->db->where_in('p.brand_id', $brands);
}

I changed in Active Record (DB_active_rec.php class) and I Added this code to Ignore where_in condition if values array's empty. So it's works now for me.
The code I added is between //#begin and //#end
/**
* Where_in
*
* Called by where_in, where_in_or, where_not_in, where_not_in_or
*
* #param string The field to search
* #param array The values searched on
* #param boolean If the statement would be IN or NOT IN
* #param string
* #return object
*/
protected function _where_in($key = NULL, $values = NULL, $not = FALSE, $type = 'AND ')
{
if ($key === NULL OR $values === NULL)
{
return;
}
//#begin
// Ignore where_in condition if values array's empty
if(is_array($values) && empty($values))
{
return $this;
}
//#end
// More method stuff

Related

Laravel AssertJsonCount on a nested array

How can I call assertJsonCount using an indexed, nested array?
In my test, the following JSON is returned:
[[{"sku":"P09250"},{"sku":"P03293"}]]
But attempting to use assertJsonCount returns the following error:
$response->assertJsonCount(2);
// Failed asserting that actual size 1 matches expected size 2.
This may or may not be specific to Laravel. Although a Laravel helper is involved, this issue may occur elsewhere.
assertJsonCount utilises the PHPUnit function PHPUnit::assertCount which uses a laravel helper data_get, which has the following signature:
/**
* Get an item from an array or object using "dot" notation.
*
* #param mixed $target
* #param string|array|int $key
* #param mixed $default
* #return mixed
*/
function data_get($target, $key, $default = null)
{
if (is_null($key)) {
return $target;
}
...
We can see that the JSON returned is a nested array, so logically we should pass in a key of 0.
$response->assertJsonCount($expectedProducts->count(), '0');
However this will be ignored as assertCount function checks if a key has been passed using is_null.
To overcome this, we can count all children of 0:
$response->assertJsonCount($expectedProducts->count(), '0.*');
This will produce the desired result.

Symfony to set a DateTime in MySQL database

Question:
In a DB web app, Date/Time field is very common.
When in Symfony, you tried to do either of the follwings:
$creationDate=new DateTime();
$record->setCreationDate($creattionDate);
This will create a "Object DateTime can't be converted to string" error.
Or:
$creationDate=new DateTime();
$datestr=$creationDate->format('Y-m-d H:i:s');
$record->setCreationDate($datestr);
This will create "Calling method format() on a non-ojbect" error.
In your entity you have to map your field with date or datetime type.
#ORM\Column(name="creationDate", type="date", nullable=true)
Solution:
Hack the DateTimeType.php located at: your symfony root/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/DateTimeType.php for the function named convertToDatabaseValue
Original content:
return ($value !== null)
? $value->format($platform->getDateTimeFormatString()) : null;
It seems Symfony is doing some extra conversion when the parameter is already a string.
Change to:
return ($value !== null)
? $value : null;
will do the trick.

PDO query does not return data when inserting date as variable

Im trying to get a hold of OOP and PDO. Did some tutorials. In the tutorial i got the query method (so thats not mine...)
but im having troubles with a pdo query
I want to select orders from the database matching a date..... de date comes from a datepicker and returns 2012-12-16 for example therefor
$dateInputQuery = date("Y-m-d", strtotime(Input::get('datepick')));
$data = $order->getAllOrders('order', 'WHERE DATE(orderdate) = DATE({$dateInputQuery})', false, false);
the strange thing is that when i replace the WHERE clause to WHERE DATE(orderdate) = \'2013-12-16\' it returns all the data but when inserting my date like above it does not....
in the db class the method looks like this
public function getAll($table, $where = NULL, $orderSort = NULL, $limit = NULL) {
$this->query("SELECT * FROM {$table} {$where} {$orderSort} {$limit}")->error();
return $this;
}
and query method in db class
public function query($sql, $params = array()) {
//reset error
$this->_error = false;
if ($this->_query = $this->_pdo->prepare($sql)) {
$x = 1;
if (count($params)) {
foreach ($params as $param) {
$this->_query->bindValue($x,$param);
$x++;
}
}
if ($this->_query->execute()) {
$this->_results = $this->_query->fetchAll(PDO::FETCH_OBJ);
$this->_count = $this->_query->rowCount();
} else {
$this->_error = true;
}
}
return $this;
}
why is this ?
Your immediate problem is caused the fact that $dateInputQuery is unquoted. Date is a string literal and should be quoted. And even though you can easily add quotes around it you really shouldn't do this. See next point.
order is a reserved word in MySQL, therefore the table name should be put in backticks
$data = $order->getAllOrders('`order`', "WHERE DATE(orderdate) = DATE('$dateInputQuery')", false, false);
^ ^ ^ ^
You're not leveraging parameter binding in query() function. Instead on top of it you're using query string interpolation leaving your code vulnerable to sql injections and diminishing the usage of prepared statements. When you use parameter binding you no longer need to quote parameter values.
Your sql query is not index-friendly. You shouldn't apply any functions (in your case DATE()) to the column you're searching on (orderdate). Instead you can rewrite your condition to apply necessary transformations/calculations to the arguments which are constants.
You should avoid using SELECT *. Read Which is faster/best? SELECT * or SELECT column1, colum2, column3, etc and Why is using '*' to build a view bad?
That being said your query should look something like
$sql = "SELECT order_id, orderdate, ...
FROM `order`
WHERE orderdate >= ?
AND orderdate < ? + INTERVAL 1 DAY";
And you should execute it
$this->query($sql, array($dateInputQuery, $dateInputQuery));
Instead of passing whole clauses (e.g. WHERE) you should pass values

Named query with optional parameter not working in mysql

I have a named query below for optional parameter which is flightNumber, departureAirport and arrivalAirport. But this query is not working when I don't give any value for these parameter.
#Query("from CapacityMonitor
where carrierCode = :carrierCode and
(:flightNumber IS NULL OR flightNumber = :flightNumber) and
(:departureAirport IS NULL OR departureAirport = :departureAirport) and
(:arrivalAirport IS NULL OR arrivalAirport = :arrivalAirport)
I can change a query but i have to use with #Query annotation only
So you want to keep your query the way it is and make it work with or without parameters. Well, you can't do that. If the query is expecting parameters, then you have to set them.
The best approach would be to leave the query the same way it is and set the parameters to NULL so that :param IS NULL returns TRUE in those cases and return all results. That way you will fake a match.
Anyway, the parameter has to be set always.
I would suggest using a Criteria Query to build a statement with custom WHERE clause.
Based on your example, it could look like this (depending on your data types):
public List<CapacityMonitor> getFlights(String carrierCode, String flightNumber, String departureAirport, String arrivalAirport) {
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<CapacityMonitor> query = builder.createQuery(CapacityMonitor.class);
Root<CapacityMonitor> root = query.from(CapacityMonitor.class);
query.select(root);
// Carrier code is mandatory
query.where(builder.equals(root.get("carrierCode"), carrierCode));
// Other properties are optional
if (null != flightNumber && flightNumber.length() > 0) {
query.where(builder.equals(root.get("flightNumber"), flightNumber));
}
// Use LIKE expression to match partially
if (null != departureAirport && departureAirport.length() > 0) {
query.where(builder.like(root.get("departureAirport"), "%" + departureAirport + "%"));
}
if (null != arrivalAirport && arrivalAirport.length() > 0) {
query.where(builder.like(root.get("arrivalAirport"), "%" + arrivalAirport + "%"));
}
return em.createQuery(query).getResultList();
}

Doctrine 2 mysql FIELD function in order by

I'm trying to use the MySQL FIELD function in an order by clause in a query. I'm assuming that Doctrine 2 doesn't support the FIELD function out of the box - is that true? If so, how can I use it? Will I have to turn my whole query into a native query? Is there a Doctrine 2 extension that adds this functionality?
Jeremy Hicks, thanks for your extension.
I didn`t know how to connect your function to doctrine, but finally i find answer.
$doctrineConfig = $this->em->getConfiguration();
$doctrineConfig->addCustomStringFunction('FIELD', 'DoctrineExtensions\Query\Mysql\Field');
I need FIELD function to order my Entities that i select by IN expression. But you can use this function only in SELECT, WHERE, BETWEEN clause, not in ORDER BY.
Solution:
$qb
->select("r, field(r.id, " . implode(", ", $ids) . ") as HIDDEN field")
->from("Entities\Round", "r")
->where($qb->expr()->in("r.id", $ids))
->orderBy("field");
To avoid adding field alias into your result row you need put HIDDEN keyword. So this how to be able order values in IN expression in Doctrine 2.2.
You could add support for the FIELD() DQL function but instead implement it as standard SQL CASE .. WHEN expression. This way your function would work both on MySQL and Sqlite, which is particularly useful if you are like me and like to run your unit tests on in-memory sqlite.
This class is largely based on the work by Jeremy Hicks (I simply changed the getSql() method)
class Field extends FunctionNode
{
private $field = null;
private $values = array();
public function parse(\Doctrine\ORM\Query\Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
// Do the field.
$this->field = $parser->ArithmeticPrimary();
// Add the strings to the values array. FIELD must
// be used with at least 1 string not including the field.
$lexer = $parser->getLexer();
while (count($this->values) < 1 ||
$lexer->lookahead['type'] != Lexer::T_CLOSE_PARENTHESIS) {
$parser->match(Lexer::T_COMMA);
$this->values[] = $parser->ArithmeticPrimary();
}
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
{
$query = '(CASE ' . $this->field->dispatch($sqlWalker);
for ($i=0, $limiti=count($this->values); $i < $limiti; $i++) {
$query .= ' WHEN ' . $this->values[$i]->dispatch($sqlWalker) . ' THEN ' . $i;
}
$query .= ' END)';
return $query;
}
}
You can write your own DQL extension.
In case that the field that you want to "order by" is an ENUM data type, then ORDER BY will work in the order in which the values were defined for that ENUM field.
For example, I had a filed defined as enum('n','pe','o','ap','c') that was giving a weird ordering. The ordering got fixed after updating the enum to: enum('ap','c','n','o','pe')