How to echo last query string in Phalcon? - php

I have worked a lot on codeigniter. In codeigniter , if there is need to get query string that is executed last, we can get it using:
echo $this->db->last_query();
exit;
But currently I am working on phalcon and I am just at beginner level in this framework. I am curious if there is a way to echo last query string in phalcon.
Thank you.

Using Raw Queries
Let us have the following query:
$phql = 'UPDATE `news` SET `category_id` = 5 WHERE `id` = :id';
$this->db->execute($phql, ['id' => 1]);
We can get debug query info with the following methods:
print_r($this->db->getSQLStatement());
UPDATE news SET category_id = 5 WHERE id = :id
print_r($this->db->getSqlVariables());
Array (
[id] => 1 )
More info about DB methods you can find here: https://docs.phalconphp.com/en/latest/api/Phalcon_Db_Adapter_Pdo.html
Working with Models
Setting up your DB connection and profiler service:
use Phalcon\Db\Profiler as ProfilerDb;
use Phalcon\Events\Manager as EventsManager;
use Phalcon\Db\Adapter\Pdo\Mysql as MysqlPdo;
$di->set('profiler', function () {
return new ProfilerDb();
}, true);
$di->set('db', function () use ($di) {
$eventsManager = new EventsManager();
// Get a shared instance of the DbProfiler
$profiler = $di->getProfiler();
// Listen all the database events
$eventsManager->attach('db', function ($event, $connection) use ($profiler) {
if ($event->getType() == 'beforeQuery') {
$profiler->startProfile($connection->getSQLStatement());
}
if ($event->getType() == 'afterQuery') {
$profiler->stopProfile();
}
});
$connection = new MysqlPdo(
array(
"host" => "localhost",
"username" => "root",
"password" => "secret",
"dbname" => "invo"
)
);
// Assign the eventsManager to the db adapter instance
$connection->setEventsManager($eventsManager);
return $connection;
});
Using it to debug your Queries:
// Send some SQL statements to the database
Robots::find();
Robots::find(
array(
"order" => "name"
)
);
Robots::find(
array(
"limit" => 30
)
);
// Get the generated profiles from the profiler
$profiles = $di->get('profiler')->getProfiles();
foreach ($profiles as $profile) {
echo "SQL Statement: ", $profile->getSQLStatement(), "\n";
echo "Start Time: ", $profile->getInitialTime(), "\n";
echo "Final Time: ", $profile->getFinalTime(), "\n";
echo "Total Elapsed Time: ", $profile->getTotalElapsedSeconds(), "\n";
}
More info on Profiler service: https://docs.phalconphp.com/en/latest/reference/models.html#profiling-sql-statements
Phalcon Prophiler Widget
I'm using a lovely debug widget for Phalcon made by Fabian Fülling. You can check the repository here: https://github.com/fabfuel/prophiler A sample screen shot of the widget in action below:

If you are running queries directly on your model instance and you are lazy, you can also do it like this:
$result = $this->_userEntriesE‌​ntries->find(array("c‌​onditions" => "FeaturedPost = 1 and FeaturedPostStatus = 1", "order" => "ID DESC", "limit" => 4))
var_dump($result);
var_dump the result object of your query. Within the PDO dump you will notice a key named _pdoStatement. This is your generated SQL query.
This is not the recommended way, just a dirty trick.

Related

Phalcon PhP - is there an EOF for model::find

I'm writing a piece of code and in it I would like to know if the result of a find if empty or not. Here is my piece of code:
public function signatureAction()
{
$info = $this->session->get('current_quote');
$object_list = ApplicationSignatureFile::find(array('conditions' => 'application_id = ?1 AND quote_id = ?2',
'bind' => [
1 => $info['application_id'],
2 => $info['quote_id'],
]));
$this->view->setVar('object_list', $object_list);
if ($object_list) {
$this->view->setVar('has_files',true);
} else {
$this->view->setVar('has_files',false);
}
}
What I don't know yet if how to check if $object_list is EOF so I can set the has_files variable better. Currently it is not working. How can I do that in a controller and in a .volt view?
This is pretty strange actually. Using findFirst or any other ORM method returns false on fail, however using find does not.
A simple workaround in your case would be to use the count method on the result set:
$test = \Models\Objects::find([
'conditions' => 'is_active = 42'
]);
if ($test->count()) {
print('I have records with is_active = 42');
d($test->toArray());
} else {
print('I do not have any records with is_active = 42');
}

Zend Framework 2 PostgreSQL lastInsertValue returns null

I have code for inserting data to table. Here is my code:
public function createPage(Pages $page)
{
$data = array(
'page_name' => $page->page_name,
'parent_page_id' => $page->parent_page_id,
'category' => $page->category,
'create_date' => $page->create_date,
);
try {
$id = $this->tableGateway->insert($data);
$id = $this->tableGateway->lastInsertValue;
} catch (Exception $ex) {
throw new Exception($ex->getMessage());
}
return $id;
}
When I use MySql, I've got the row's id, but with PostgreSQL I've got null.
Yes,
$id = $this->tableGateway->getAdapter()->getDriver()->getLastGeneratedValue("sequence_name");
Or
$id = $this->tableGateway->getAdapter()->getConnection()->getLastGeneratedValue
Depending on what zf2 version you have.
However, there is some difference between Postgresql and MySql using the native php PDO class, which zf2 wraps and provide the tableGateway.
With native php PDO you may need to do something like:
"INSERT INTO tbl_table (table_name) values ('foo') RETURNING table_id;"

Stored Javascript in MongoDB

I am trying to store a query in MongoDB by using stored javascript.
It looks something like this right now:
$collection = $db->$app_id;
$query = $collection->find( $filterQuery );
$db->system->js->save(array(
"_id" => "qo8qu0",
"value" => new MongoCode("function() { return array($query) }")
));
Then I execute it:
echo "<pre>";
print_r($test = $db->execute("qo8qu0()"));
echo "</pre>";
However, I am getting this error:
Catchable fatal error: Object of class MongoCursor could not be converted to string in /var/www/dev/classes/EmailMessaging.php on line 91
Line 91 is this line (like above),
"value" => new MongoCode("function() { return array($filterQuery) }")
If I use count( $filterQuery ); instead of find( $filterQuery );
It works and returns the right number.
How can I make it work so it returns the array when using find?
Thank you
It is because of evaluation of your code. It is evaluating this:
$query = $collection->find( $filterQuery );
So that $query is a MongoCursor and then you are attempting to concatenate that class into a string:
new MongoCode("function() { return array($query) }")
You need to do the entire thing witthin eval like so:
return $this->execute('function(){ return db.collection.find(filter); }', array('filter'=>array('_id'=>1)));
count works because it returns an int which can be added to the string.
Edit
A way:
$db->system->js->save(array(
"_id" => "qo8qu0",
"value" => new MongoCode("function() { return db.collection.find(filter).toArray() }")
));
And then in your app:
$test = $db->execute("qo8qu0()", array('filter'=>array('_id'=>1)))

Auto-increment in MongoDB with CodeIgniter Alex Bilbie library

First of all, sorry for my english and I'm beginning to study MongoDB. :)
I'm trying to insert a record using the CI library to MongoDB (https://github.com/alexbilbie/codeigniter-mongodb-library/tree/v2).
The insert works perfectly, but I can't insert using the recommended function to auto-increment getNextSequence (http://docs.mongodb.org/manual/tutorial/create-an-auto-incrementing-field/).
I tried the following ways without success.
Controller:
$data = array('_id' => 'getNextSequence("myid")',
'name' => 'Test '.time(),
'email' => 'test#test.com');
$this->default_model->add($this->collection, $data);
Model:
function add($collection, $data){
return $this->mongo_db->insert($collection, $data);
}
This returns the string 'getNextSequence("relatoriosid")' as the "_id".
I also tried used the command function, like this:
Controller:
$query = 'db.collection.insert({_id: getNextSequence("myid"), name: "Test '.time().'"});';
$ret = $this->default_model->execute($query);
var_dump($ret);
Model:
function execute($query){
return $this->mongo_db->command($query);
}
This way, returns the error:
["errmsg"]=> string(136) "exception: JavaScript execution failed: ReferenceError: getNextSequence is not defined near 'quence("myid"), name: "Teste 1374' "
["code"]=> int(16722)
["ok"]=> float(0)
Has anyone implemented something similar?
Thanks in advance!
I have implemented once mongoDB in one of my project.
I had faced similar problem. But one important thing i remember that we can not modify _id. Its MongoDB inbuilt properly. Neither its good to have the auto-increament in MongoDB because you need to implement that manually.
I will recommend that have another column in structure, you can call it anything, which will be virtual unique/primary key for you, lets say that column name is data_id.
$data = array('data_id' => md5(timestamp() . "<your string>"),
'name' => 'Test '.time(),
'email' => 'test#test.com');
if we check the documentation, is specified that Generally in MongoDB, you would not use an auto-increment pattern for the _id field, or any field, because it does not scale for databases with large numbers of documents. Typically the default value ObjectId is more ideal for the _id. Here i am referring to this link.
Even on the same link, its specified that getNextSequence() we need to write it. Its not inbuilt function.
Hope this helps you.
I got that problem too here is my solution.
Add this function to appflow\application\libraries
public function getNextSequence($name = ""){
if (empty($name))
{
show_error("In order to retrieve documents from MongoDB, a collection name must be passed", 500);
}
try{
$collection_1 = 'counters';
$collection = $this->db->{$collection_1};
$result = $collection->findAndModify(
['_id' => $name],
['$inc' => ['seq' => 1]],
['seq' => true],
['new' => true, 'upsert' => true]
);
if (isset($result['seq']))
{
return $result['seq'];
}
else
{
return false;
}
}
catch (MongoCursorException $e)
{
if(isset($this->debug) == TRUE && $this->debug == TRUE)
{
show_error("MongoDB query failed: {$e->getMessage()}", 500);
}
else
{
show_error("MongoDB query failed.", 500);
}
}
}
This is the way to use.
$nextID = $this->mongo_db->getNextSequence("maindata_child");
$this->mongo_db->where(array('_id'=>$mongo_id))->push('maindata_child', array('id'=>$nextID,'data'=>$maindata_child))->update('main_data');
and don't forget to add collection "counters".
db.counters.insert(
{
_id: "userid",
seq: 0
}
)
PS. I'm use this library https://github.com/bcit-ci/CodeIgniter/wiki/Using-MongoDB-in-Codeigniter
Reference for solution : http://tbsmc.com/a/mwbwswmm-mongodb-how-to-insert-record-using-autoincrement-functionality.html

Predis Alias Sharding

I'm trying to use Predis sharding by alias, as described here. My code is basically identical, but I'm only returning empty arrays. Do my hash keys need {} around them? (EDIT: Nope, just tried it)
$api->get("/test", function () {
$servers = [
["alias" => "metadata", "port" => 6380],
["alias" => "relations", "port" => 6381],
["alias" => "dim_provider", "port" => 6382],
["alias" => "dim_revctrcode", "port" => 6383],
["alias" => "dim_enccode", "port" => 6384],
["alias" => "dim_pos", "port" => 6385]
];
$options = [
"nodehash" => function ($connection) { return $connection->getParameters()->alias; },
"cluster" => function ($options) {
$replicas = Predis\Cluster\Distribution\HashRing::DEFAULT_REPLICAS;
$hashring = new Predis\Cluster\Distribution\HashRing($replicas, $options->nodehash);
$cluster = new Predis\Connection\PredisCluster($hashring);
return $cluster;
}
];
$redis = new Predis\Client($servers, $options);
try {
$test = $redis->scard("dim_provider");
print_r($test); // Prints 0 for scard or empty Array for hgetall
} catch (Exception $e) {
print $e->getMessage();
}
$redis = new Predis\Client(["port" => 6382]);
$test = $redis->scard("dim_provider");
print_r($test); // Works.
});
EDIT: It also works if I only put one server in the $servers array. So it seems the hashing is not working right. When I throw some echos in front of the return value in nodehash I can see that it's returning the alias.
Assigning a dim_provider alias to a Redis connection and trying to get a key named dim_provider from a server are two different things.
In your script you are trying to set up a cluster of Redis instances using connection aliases (instead of the usual ip:port pairs) to calculate the distribution of your keyspace among multiple Redis servers acting as your data shards. Using this setup, the key dim_provider is sharded accordingly to the underlying distribution algorithm and could be stored on any of the 6 servers composing your cluster and defined in the $servers array.
I wanted to add how trivially easy it was to implement my clustering strategy once nrk got me on the right track. This is a really well-written library.
$api->get("/test", function () {
Class KeyCluster extends Predis\Connection\PredisCluster {
public function __construct() {
$this->pool = Array();
}
public function add (Predis\Connection\SingleConnectionInterface $connection) {
$parameters = $connection->getParameters();
if (isset($parameters->table)) {
$this->pool[$parameters->table] = $connection;
} else {
$this->pool[] = $connection;
}
}
public function getConnection (Command\CommandInterface $command) {
$key = $command->getArgument(0);
$table = explode(":", $key)[0];
return isset($this->pool[$table]) ? $this->pool[$table] : null;
}
}
$redis = new Predis\Client([
"tcp://127.0.0.1:6382?table=dim_provider",
"tcp://127.0.0.1:6383?table=dim_pos"
],[
"cluster" => new KeyCluster
]);
$result = $redis->scard("dim_provider");
print_r($result);
});

Categories