Phalcon datetime in model query error - php

I am trying to execute a query like this:
Select * from table where created_at > DATE_SUB(NOW(), INTERVAL 1 DAY) in phalcon model query form. But i keep getting the following error:
Syntax error, unexpected token INTEGER(1), near to ' DAY)',
By query building is like below
$donations = Donations::query()
->where('created_at > DATE_SUB(NOW(), INTERVAL 1 DAY)')
->execute();
The above code gives me that error. Now i have tried like below
$donations = Donations::query()
->where('created_at > :holder:')
->bind(["holder" => 'DATE_SUB(NOW(), INTERVAL 1 DAY)'])
->execute();
Although this binding does not give me an error, it gives me a 0 result but i have a few rows inserted into the table to check this and when i execute the query in phpmyadmin it works correctly, So i assumed there might be a datetime mix up in the phalcon library setup of mine but when i changed from 1 DAY to 1 MONTH there is still not result. Can someone guide me on this.

INTERVAL, DATE_SUB, NOW() and other similar are MySQL only features and are not supported by PHQL.
You have two options:
1) Rewrite your WHERE condition by using PHP date:
$date = date('Y-m-d', strtotime('-1 DAY')); // Modify according to your date format
$donations = Donations::query()
->where('created_at > :holder:')
->bind(["holder" => $date)
->execute();
2) Extend MySQL with a dialect class:
$di->set('db', function() use ($config) {
return new \Phalcon\Db\Adapter\Pdo\Mysql(array(
"host" => $config->database->host,
"username" => $config->database->username,
"password" => $config->database->password,
"dbname" => $config->database->name,
"dialectClass" => '\Phalcon\Db\Dialect\MysqlExtended'
));
});
More info in the following links:
How to extend: https://forum.phalconphp.com/discussion/1748/date-sub-interval-mysql#C6291
The dialect class itself: https://github.com/phalcon/incubator/blob/master/Library/Phalcon/Db/Dialect/MysqlExtended.php

Related

Find data 2 days before date mysql and fat free framework

Hi i'm trying to make a module of upcoming services and i need to show the user the services 2 or more days before the date, i am working with php fat free and mysql and i have this query:
SELECT * FROM bitacora WHERE fechaprox >= NOW() - INTERVAL 2 DAY;
this works on mysql
enter image description here
And i am trying to put this in fat free like this:
public function avisos($f3)
{
$this->M_Bitacora->cliente = 'SELECT nombre FROM cliente WHERE id_cliente= bitacora.id_cliente';
$result= $this->M_Bitacora->find('SELECT * FROM bitacora WHERE fechaprox >= NOW() - INTERVAL 2 DAY');
$items= array();
foreach($result as $bitacora){
$items[] = $bitacora->cast();
}
echo json_encode([
'mensaje' => count($items) > 0 ? '' : 'Aun no hay registros',
'info'=> [
'items' => $items,
'total' => count($items)
]
]);
}
But this is my error: Internal Server Error
PDOStatement: 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 'SELECT * FROM bitacora WHERE fechaprox >= NOW() -
INTERVAL 2 DAY' at line 1
Can you help me? or is there another way to get that data that i need?
So I'm gonna go out on a limb here and say that M_Bitacora is a DB\SQL\Mapper object right?
If you're using a mapper object, then what you're doing is you use the Mapper object to hide all that pesky SQL and tuck it somewhere else. It has a bunch of helper methods to find(), load(), and select() among other methods to quickly help you get the data you need and map it to a PHP object.
Since you're going the raw SQL route, what you're going to want is to use your db connection. If you still want to use the SQL, then it's best to get your SQL connection var that you created to run the SQL. and then like #Caius Jard suggested, use exec().
<?php
// if this is how you set up your db connection...
$f3->set('DB', new DB\SQL(/*config stuff*/);
// then in your code example above
public function avisos($f3)
{
// you can just join this in the query below. Much more efficient anyways.
//$this->M_Bitacora->cliente = 'SELECT nombre FROM cliente WHERE id_cliente= bitacora.id_cliente';
$items= $f3->DB->exec('SELECT b.*, c.nombre
FROM bitacora b
JOIN cliente c ON c.id_cliente = b.id_cliente
WHERE b.fechaprox >= NOW() - INTERVAL 2 DAY');
// it is automatically fetch as an associative array (hopefully if you configured your PDO object like that)
//$items= array();
//foreach($result as $bitacora){
// $items[] = $bitacora->cast();
//}
echo json_encode([
'mensaje' => count($items) > 0 ? '' : 'Aun no hay registros',
'info'=> [
'items' => $items,
'total' => count($items)
]
]);
}
Please check again the documentation, find takes filter as parameter, not the whole SELECT statement.
public function avisos($f3)
{
$result= $this->M_Bitacora->find(['fechaprox >= NOW() - INTERVAL 2 DAY']);
$items = array_map(function($e) { return $e->cast(); }, $result);
echo json_encode([
'mensaje' => count($items) > 0 ? '' : 'Aun no hay registros',
'info'=> [
'items' => $items,
'total' => count($items)
]
]);
}

update date to next day in laravel

I want to update my date to next day date. How Can I do it?
Now I do it using this.
$calendar = Calendar::find($id);
$calendar->update(['started_at' => $calendar->started_at->addDay(1)));
or I can do it
$calendar->started_at->addDay(1);
$calendar->save();
But this solutions is bad for me because there are 2 request in database. I wont do it using only one request.
Is there a way to dynamically update date to next day date?
For example
Calendar::where('id', $id)->updateToNextDay('started_at');
I find also sql equivalent
UPDATE `calendar` SET `started_at` = `started_at` - INTERVAL 1 DAY;
Thanks for attention.
Calendar::where('id', $id)->update() is just syntactical sugar. This proxies you to the Query Builder and is the same as running DB::table('calendar')->where('id', $id)->update();
The power of a model in an ORM is obtaining the data from the database, mapping it to properties in an object, and then manipulating that object. The overhead of a single select for an update is pretty small and if you're worried about that overhead in the development phase, you're probably overoptimizing.
If you wish to forego the select, you can use the Query Builder with a raw SQL expression. Either will call the Query Builder and run the same exact query:
Calendar::where('id', $id)
->update(['started_at' => DB::raw("started_at + INTERVAL 1 DAY")]);
or
DB::table('calendars')->where('id', $id)
->update(['started_at' => DB::raw("started_at + INTERVAL 1 DAY")]);
This should work
Calendar::where('id', $id)->update([
'started_at' => DB::raw("DATE_ADD(started_at, INTERVAL 1 DAY)")
]);
Let me know :)
$startDate = date_timestamp_get($calendar->started_at);
$date = date('Y-m-d H:i:s', strtotime('+1 day', $startDate));
$calendar->update(['started_at' => $date]);
You can write your own method in Calendar model like,
public function updateToNextDay(string $column)
{
$this->update([
$column => \Db::raw("$column + INTERVAL DAY 1");
]);
}
Not tested, but it should work.

Why doesn't this PHP MongoDB query return any results even though there is one?

I have a collection of users and users have a meta.create_date field which is an ISODate as seen below. I am trying to count how many users were created in the last N days. I have the following in the database:
{
"_id" : ObjectId("51e61fa16803fa40130a0581"),
"meta" : {
"create_date" : ISODate("2013-07-17T04:37:53.355Z")
}
}
My PHP code:
$daysAgo = new MongoDate(date('c', strtotime('-7 days')));
$query = array(
'meta.create_date' => array(
'$gte' => $daysAgo,
)
);
$result = $this->db->users->count($query);
I have also tried specifying a range using '$gte' and '$lte' where $lte => today.
However, result is coming back as 0. So what is going on here?
MongoDate() takes int time(). So, passing in a php date() to the constructor does not work. This is the proper way:
$daysAgo = new MongoDate(strtotime('-7 days'));

MongoDB using timestamps to sort

I have a mongodb that will be storing visitor data. I need to delete the data after ten minutes of not being active and will run a command through a cron. How would I do this?
Currently the collection is setup like so:
{ "_id" : ObjectId("4fd33e0b0feeda3b2406f6be"), "name" : "Dugley Reanimator", "updated" : "Some form of timestmap" }
How should I go about storing a timestamp that I search the collection with I.E for my MySql version:
$sql = mysql_query('DELETE FROM `visitors` WHERE NOW() > DATE_ADD(`last_seen`, INTERVAL 10 MINUTE)');
The ObjectId has a timestamp component to it. see the docs here. This essentially gives you a free insert time that you can use for sorting and querying.
The mongodb drives should give you a way to created an ObjectId off of a timestamp.
In Python:
gen_time = datetime.datetime(2010, 1, 1)
dummy_id = ObjectId.from_datetime(gen_time)
In Java:
Date d = new Date(some timestamp in ms);
ObjectId id = new ObjectId(d)
So once you've created an ObjectId based on "10 minutes ago" you can do a delete query using $lt
in the js console it would be:
db.collectionName.remove({_id: {$lt: <Your Object Id that represents 10 minutes ago>})
The best way to do it (if the timestamp is the same when you insert) its by using the _id field.
The _id field can indicate you the time, and you can do a $lte query to delete old values.
I've written about it here: http://blog.dicarsio.com/post/10739857186/quick-snippet-get-creation-time-from-id-on-mongodb
Your driver will use a MongoDate time (this may map to a more native representation in PHP).
You can then query using something like the following mongo statement:
db.myCollection.find({updated : { $lte : new ISODate("2012-06-09T16:22:50Z") } })
A rough translation for PHP would be:
$search = array(
'updated' => array(
'$lte' => new MongoDate($tenMinutesAgo))
);
$collection->find($search)
Or (Caveat: not tested):
$tenMinutesAgo = new DateTime();
$tenMinutesAgo->modify('-10 minutes');
$search = array('updated' => array('$lte' => $tenMinutesAgo));
$collection->find($search)

Doctrine Mongodb ODM and DateTime query

I could use some help on this problem. I'm creating an application using Symfony2 + mongodb + doctrine.
I just want to use Doctrine ODM to query all the users who have been logged in the last 5 minutes. I have a User collection with a date field called date_last_login.
So I try to use the querybuilder like that:
<?php
// Creating a DateTime object and susbtract 5 min from now
// local time is 15:40:05, timezone: 'Europe/Paris'
$_dateTime = new \DateTime();
$_interval5Min = new \DateInterval('PT5M');
$_dateTime->sub($_interval5Min);
$query = $this->createQueryBuilder('User')
->field('date_last_login')->gte($_dateTime)
->getQuery();
->execute();
When I looked at the assembled query using symfony2 profiler, here is what I got:
db.User.find({ "date_last_login": { "$gte": new Date("Fri, 23 Dec 2011 15:30:05 +0100") } });
It seems fine except that the date is 10 minutes earlier rather than 5 minutes? I just don't get it. If I dump my php DateTime object, date is correct: 2011-12-23 15:35:05 (five minutes before 15:40).
So I tried to assemble the same query without substracting any minutes and this time, everything is fine:
<?php
// local time is 15:50:00
$query = $this->createQueryBuilder('User')
->field('date_last_login')->gte(new \DateTime())
->getQuery();
->execute();
// query is ok:
db.User.find({ "date_last_login": { "$gte": new Date("Fri, 23 Dec 2011 15:50:00 +0100") } });
What am I doing wrong ?
Thank you for your help!
To create query builder for get data when date_last_login great than 5 minutes there 3 ways
1) create DateTime object with your datetime format and get timestamp from DateTime object then create MongoDate object :
$timeBefore5MinutesAgo = new \DateTime(date('Y-m-d H:i:s',\time() - 5 * 60));
$mongoDateBefore5MinutesAgo = new \MongoDate($currentDateWithTime->getTimestamp());
$query = $this->createQueryBuilder('User')
->field('date_last_login')->gte($mongoDateBefore5MinutesAgo)
->getQuery();
->execute();
2) create MongoDate object and use strtotime to convert you`r datetime format to timestamp :
$mongoDateBefore5MinutesAgo = new \MongoDate(strtotime(date('Y-m-d H:i:s',\time() - 5 * 60)));
$query = $this->createQueryBuilder('User')
->field('date_last_login')->gte($mongoDateBefore5MinutesAgo)
->getQuery();
->execute();
3) only in case Doctrine 2 ODM , you can just create DateTime object with you`r datetime format:
$timeBefore5MinutesAgo = new \DateTime(date('Y-m-d H:i:s',\time() - 5 * 60));
$query = $this->createQueryBuilder('User')
->field('date_last_login')->gte($timeBefore5MinutesAgo)
->getQuery();
->execute();
all 3 ways will create query this:
db.User.find({ "date_last_login": { "$gte": new ISODate("2014-03-15T19:35:08+02:00") } });
This is likely due to this PHP bug which was fixed in 5.3.3:
https://bugs.php.net/bug.php?id=50916

Categories