How to get mongodb collection iterator? - php

I'm connecting to mongo db like this:
$mongoClient = new MongoDB\Client($db_string);
Getting collection like this:
$collection = $mongoClient->selectCollection('database_name', 'collection_name');
And getting collection iterator like this:
$iterator = $collection->find();
However last call shoots error:
[error] Could not retrieve source count from demo_article: Authentication failed.
What I'm doing wrong here?
UPDATE:
Here:
protected function initializeIterator()
{
$this->iterator = $this->collection->find();
if($this->iterator instanceof Traversable) {
echo "**Traversable!**";
}
iterator is Traversable. But then, this code is called from SourcePluginBase:
protected function doCount() {
$iterator = $this->getIterator();
if($iterator instanceof Traversable) {
echo "**TRAVERSABLE!**";
}else{
echo "**NOT TRAVERSABLE!**";
}
and it's not Traversable?! How can it loos that traversable status ?

As stated in the documentation for the MongoDB\Client class, the constructor does not perform the actual connection:
A MongoDB\Driver\Manager is constructed internally. Per the Server Discovery and Monitoring specification, MongoDB\Driver\Manager::__construct() performs no I/O. Connections will be initialized on demand, when the first operation is executed.
It means that the connection will be opened only when you execute the first query. If you provided no credentials in the connection string, or if they are incorrect, then you get an "Authentication failed" error on that query.

Related

PHP Doc comment after unserialization

The ReflectionMethod instance from PHP (http://php.net/manual/en/class.reflectionmethod.php) has the getDocComment method that returns the annotation of a method. This works ok, unless you use unserialized object.
$ref = new ReflectionClass('a');
var_dump(method_exists($ref, 'getDocComment')); //bool(true)
var_dump($ref->getDocComment()); //bool(false)
$ref = unserialize(serialize($ref));
var_dump(method_exists($ref, 'getDocComment')); //bool(true)
var_dump($ref->getDocComment()); //PHP Warning: Uncaught Error: Internal error: Failed to retrieve the reflection object
Is there any way of testing if the ReflectionMethod object has correctly defined doc comment? I mean, I do not care about getting the annotation after serialize/unserialize, but I want to check if calling getDocComment is safe.
Edit: According to responses that advice error handling + fallback, I rephrase the Q.
I have some simple cache of reflections (array of ReflectionMethod objects). Until I use item from that cache, I wold like to chech its correctness. I do NOT want to handle error, I want to "predict error". Awesome would be something like hasDocComment method that does not generate any error, but returns only true/false within any ReflectionMethod object state.
The general approach of serializing reflection objects is wrong. There exists a PHP Bug report for it, but it has been set to "irrelevant":
https://bugs.php.net/bug.php?id=70719
The reason is, that you cannot connect a reflection object back to its class again, because you would have to deal with source code changes and all kinds of stuff. What you should do instead is, to serialize the name of the class and generate a NEW reflection object from that class, when you unserialize.
Code Example:
class A { }
$ref = new ReflectionClass('A');
var_dump(method_exists($ref, 'getDocComment'));
// serialize only the class name
$refClass = unserialize(serialize($ref->getName()));
// get a new reflection object from that class ...
$ref = new ReflectionClass($refClass);
var_dump(method_exists($ref, 'getDocComment'));
// If you want to serialize an object
$a = new A();
$a2 = unserialize(serialize($a));
$ref = new ReflectionClass(get_class($a2));
var_dump(method_exists($ref, 'getDocComment'));
If you need to be able to handle errors, you can try/catch the execution block. Since alt-php71-7.1.0-1 (which you seem to be using), this will throw an instance of Error instead of simply a Fatal Error, which allows you to do error handling.
<?php
class A { }
$ref = new ReflectionClass('A');
var_dump(method_exists($ref, 'getDocComment')); //bool(true)
var_dump($ref->getDocComment()); //bool(false)
// serialize only the class name
$refClass = unserialize(serialize($ref));
try {
$refClass->getDocComment();
// do your work
}
catch (Error $e) {
echo "Malformed Reflection object: ".$e->getMessage();
}
Demo
And since you can still get the class name from the malformed Reflection instance, you can instantiate a new one right in your catch block:
<?php
class A { }
$ref = new ReflectionClass('A');
var_dump(method_exists($ref, 'getDocComment')); //bool(true)
var_dump($ref->getDocComment()); //bool(false)
// serialize only the class name
$refClass = unserialize(serialize($ref));
try {
$refClass->getDocComment();
}
catch (Error $e) {
$recoveredRef = new ReflectionClass($refClass->getName());
var_dump($recoveredRef);
var_dump($recoveredRef->getDocComment()); // works correctly
echo "Malformed Reflection object, but recovered: ".$e->getMessage();
}
Demo

Azure Table Storage PHP Error

This is my PHP code
<?php
// Load Azure Drivers
require_once '../vendor/autoload.php';
use WindowsAzure\Common\ServicesBuilder;
use MicrosoftAzure\Storage\Common\ServiceException;
use MicrosoftAzure\Storage\Table\Models\QueryEntitiesOptions;
// Connection String
$connectionString = 'DefaultEndpointsProtocol=https;AccountName=<account_name>;AccountKey=<account_key>==';
// Create table REST proxy.
$tableRestProxy = ServicesBuilder::getInstance()->createTableService($connectionString);
$user_input = "Username eq '<user>'";
try {
$result = $tableRestProxy->queryEntities("<table>", $user_input);
}
catch(ServiceException $e){
echo "<h1>Error querying, please contact Admin.</h1>";
die();
}
$entities = $result->getEntities();
foreach($entities as $entity){
echo $entity;
}
?>
I have censored out all the connection and table information. But everything works when I use the demo code. But I want to retrieve the full row. When I execute this I get this error
Catchable fatal error: Object of class MicrosoftAzure\Storage\Table\Models\Entity could not be converted to string
Any ideas?
Generally speaking, you are trying to echo an object which raised this issue. As the $entity in your looping statement is an object, you cannot directly echo it.
The queryEntities() returns QueryEntitiesResult object, and then you call getEntities() function which returns Entity objects in array.
So you can use functions $entity->getXXXX() or $entity->getPropertyValue({key}) to get the properties in your table storage's entity.
You can refer to a simple sample for a quick glance.

Testing exception PHPUnit

So I playing around with PHPUnit and would like to get some insight to the output that PHPUnit generates when I try to test for an Exception. I am confused as to why I am getting a failed test. Here is my test:
class ConfigTest extends PHPUnit_Framework_Testcase
{
public function testTrueIfJobGivenExists()
{
$conf = Config::getInstance('test1.php', new Database());
$setup = $conf->getConfig();
$this->assertTrue($setup);
}
/**
* #expectedException Exception
*/
public function testExceptionIfJobGivenNotExists()
{
$conf = Config::getInstance('test.php', new Database());
$setup = $conf->getConfig();
}
}
In here I am not mocking the Database class (I have not learned how to do that yet) but basically the code looks for and entry for a job called test.php and pulls the config col for that. If the job does not exists it throws a new Exception. Here is my output:
PHPUnit 4.1.0 by Sebastian Bergmann.
.F
Time: 26 ms, Memory: 3.50Mb
There was 1 failure:
1) ConfigTest::testExceptionIfJobGivenNotExists
Failed asserting that exception of type "Exception" is thrown.
FAILURES!
Tests: 2, Assertions: 2, Failures: 1.
Here to me seems that the test is failing but looking at the PHPUnit documentation about testing exception the output looks similar. Is my test working?
EDIT: New test fail
Using Mockery I created my test like:
class ConfigTest extends PHPUnit_Framework_Testcase
{
public function tearDown()
{
Mockery::close();
}
public function testTrueIfConfigForGivenJobExists()
{
$dbJSON = array( array(
'jobConfig' => '{
"config": {
"aquisition": {
"type": "xx",
"customerKey": "xxxxx",
"login":"xxxx",
"password":"xxxxx",
"host":"xxxxxx",
"account":"",
"email":""
}
}
}'
) );
$database = Mockery::mock('Database');
$database->shouldReceive('select->where->runQuery->fetch')->andReturn($dbJSON);
$conf = Config::getInstance('getLoadsPE.php', $database);
$setup = $conf->getConfig();
$this->assertTrue($setup);
}
/**
* #expectedException Exception
*/
public function testExceptionIfJobGivenNotExists()
{
$database = Mockery::mock('Database');
$database->shouldReceive('select->where->runQuery->fetch')->andReturn(null);
$conf = Config::getInstance('getLoadsPE.php', $database);
$setup = $conf->getConfig();
$this->assertTrue($setup);
}
}
and I get
PHPUnit 4.1.0 by Sebastian Bergmann.
.F
Time: 39 ms, Memory: 4.75Mb
There was 1 failure:
1) ConfigTest::testExceptionIfJobGivenNotExists
Failed asserting that exception of type "Exception" is thrown.
FAILURES!
Tests: 2, Assertions: 3, Failures: 1
With this I dont know where the 3rd assertion is coming from. Also I dont get why Im getting the Fail test. If I comment the first test then the second passes. Any thoughts anyone?
FYI
This is what getConfig() looks like:
public function getConfig()
{
if ($this->flag) {
// Config has already been set
return true;
}
$data = self::$database->select('configs', ['jobConfig'])
->where('jobName', self::$jobName)
->runQuery()
->fetch();
if (empty($data)) {
throw new Exception("Config Exception: No config available for " . self::$jobName, 1);
}
if (count($data) > 1) {
throw new Exception("Config Exception: More than one config for same job!!!", 1);
}
$arr = json_decode($data[0]['jobConfig'], true);
// maybe threre is a better way of doing this
if (array_key_exists('aquisition', $arr['config'])) {
$this->aquisition = $arr['config']['aquisition'];
}
if (array_key_exists('ftpSetup', $arr['config'])) {
$this->ftpSetup = $arr['config']['ftpSetup'];
}
if (array_key_exists('fileSetup', $arr['config'])) {
$this->fileSetup = $arr['config']['fileSetup'];
}
if (array_key_exists('fileMaps', $arr['config'])) {
$this->fileMaps = $arr['config']['fileMaps'];
}
if (array_key_exists('fileRows', $arr['config'])) {
$this->fileRows = $arr['config']['fileRows'];
}
$this->flag = true;
return true;
}
}
#expectedException Exception is not a good idea here. If an exception is thrown in your test setup (e.g. first line of you test) your test will still pass.
You could use:
//given
$conf = ...;
try {
//when
$conf->getConfig();
$this->fail("YourException expected");
//then
} catch (YourException $e) {}
But it's messy and will not work with Exception (because phpunit fail also throws Exception). So you would have to use a custom exception.
You can try CatchException from ouzo goodies:
//given
$conf = ...;
//when
CatchException::when($conf)->getConfig();
//then
CatchException::assertThat()->isInstanceOf("Exception");
The obvious answer to your question is that there actually is a job in your database at the time the test is run, and therefore your code is not throwing the exception you expect.
This may or may not be correct, but from your code there is no way for us to know that; in fact, from your code, there is no way for the test to adequately test for that case because you don't know what's going to be in the database at the time the test is run. This is why mocking dependencies like the database is so important: you won't actually test your code the way you think you're testing it unless all the external stuff is set up exactly the way you want it to be.
I personally find it hard to wrap my head around testing and when I've been away from it for a few days (like on a Monday morning), I find it helpful to stick to a formula to get me back into the groove. I like to use the "given, when, then" pattern when writing my tests. I picked this up from Jeffrey Way's book "Laravel Testing Decoded". Here's what it looks like:
public function testSomething()
{
// given
// ... set up everything for the test here
// when
// ... execute the code that's being tested
// then
// ... assert
}
So in your case, it might look something like this:
/**
* #expectedException Exception
*/
public function testExceptionIfJobGivenNotExists()
{
// given
// I don't know what your database interface looks like, so I'm
// making stuff up here
$database = Mockery::mock("Database");
$database->shouldReceive("query")->with("SELECT something")->andReturn(null);
// set up the config object
$conf = Config::getInstance('test.php', $database);
// when
// execute your code here
$setup = $conf->getConfig();
// then
// normally you'd assert something here, but in this case, the exception
// handler will take care of it
}
(I've assumed you're using Mockery for mocking. I've also assumed that your database class will return null when you query for a job and one doesn't exist.)
Don't sweat the mocking - it's really not that hard. All I've done here is replace your new Database() with a "fake" database object (ie. mocked). The shouldReceive method simply tells Mockery that the query method should be called with some arguments and return a value. Mocking can be much more complicated than this, but to start out, this is pretty simple.
Why is this important?
This test is supposed to tell you what happens when there's no job in the database. In your test, you have no way of knowing whether your test is actually testing that, because you really have no way of knowing what the database class is returning when you run the query. In my example, on the other hand, I've "faked" the database class and ensured that it's going to return exactly what I want it to return, every time the test is run.
You expect exception to be thrown but it is not thrown. That's why your test fails. Check if your code with dataset test.php should really throw an exception.

PHP: Can iterator_to_array() throw an exception on a MongoCursor

Can using iterator_to_array() on a MongoCursor instance throw an exception in PHP 5.3? In other words, do I need to wrap iterator_to_array() calls on MongoCursor instances in try-catch statements or not?
e.g.,
$mongo = new Mongo();
$mongo_db = $mongo['my_database'];
$mongo_coll = $mongo_db['my_collection'];
// This
$cursor = $mongo_coll->find();
$documents = iterator_to_array($cursor);
// Versus this.
$cursor = $mongo_coll->find();
try {
$documents = iterator_to_array($cursor);
} catch (Exception $e) {
//...
}
iterator_to_array() can throw exceptions because it calls next().
I think the first comment as of now on this page http://www.php.net/manual/en/mongo.queries.php will be of interest to you, but don't know if it will be first when you view it so here is the deal.
You can check if the cursor is valid by using $cursor->valid().
And the comment says that you might have to rewind the cursor after receiving it, as it is sometime not rewound when received.
...
$cursor = $mongo_coll->find();
$cursor->rewind();
if ($cursor->valid()) {
$documents = iterator_to_array($cursor);
}
The advantage to the above try catch block is that the try catch block might throw the exception while you could have used the cursor when the cursor was actually valid.
Find method returns Traversable object or throws an exception.
Iterator_to_array is accepting Traversable object.
Exception should appear only if something really bad happens in Mongo driver or in Mongo during iteration. Maybe disconnection.

Should I keep reconnecting to mysql in PHP?

I have a pretty large site and every page is built from several included files, my site is 100% in a procedural format and I am trying to learn to use classes and a more OOP approach in PHP.
Currently my site has a header file that is included into every page, in this header is a mysql connection that is made and last the duration of the page, so if I need to run 10 different queries from different files, they all run without needing to make a new connection, so the connection is only made once.
Now that I am trying to convert to a more OO way, I am starting with writing a mysql class to connect and run queries, so I am thinking of using the classes __construct function to make a connection to mysql, I am just curious how this would work though, everytime that class gets called it would make or try to make a connection to mysql instead of just once.
Maybe I am not thinking it out clearly. Should I just initiate this class in the header 1 time and then I wont have to worry anymore?
You could create a single global object of your MySQL class and use that object everywhere. Then your constructor would only be called once.
Or you could create new objects of your MySQL class everywhere. mysql_connect doesn't open new connections if there already is one open:
If a second call is made to mysql_connect() with the same arguments, no new link will be established, but instead, the link identifier of the already opened link will be returned.
The best way I think is to use a special class to handle mysql connections and use it as a singleton. Make the constructor private and get it to return an instance of either an existing connection or a new one.
Here's my example:
class db
{
public $host;
public $user;
public $pass;
public $database;
private static $instance = false;
private function __construct()
{
}
public static function getInstance()
{
if (self::$instance === false)
{
self::$instance = new db;
}
return self::$instance;
}
public function db_connect()
{
}
public function db_disconnect()
{
}
}
This way, whenever you call: db::getInstance()->db_connect(), you are certain there's only going to be ONE instance of that connection everywhere.
Yes, you shouldn't connect multiple times. The overhead of opening and closing the connection all the time is bigger than the cost of keeping it open during the relative small time your scripts run. So you should create an instance of the class at the start and keep it in a global variable.
It's certainly not a bad idea to write your own classes as a exercise, but maybe you should look into one of the existing solutions for database connection management (Zend_Db etc.).
You can always store the database link reference in a STATIC class variable and call it whenever needed. However, PHP by itself tries to use an existing link if it exists in the memory.
I've a sample database handler code for you, ofcourse its PHP 5 and uses PDO.
<?php
// Class providing generic data access functionality
class DatabaseHandler
{
// Hold an instance of the PDO class
private static $_mHandler;
// Private constructor to prevent direct creation of object
private function __construct()
{
}
// Return an initialized database handler
private static function GetHandler()
{
// Create a database connection only if one doesn’t already exist
if (!isset(self::$_mHandler))
{
// Execute code catching potential exceptions
try
{
// Create a new PDO class instance
self::$_mHandler =
new PDO(PDO_DSN, DB_USERNAME, DB_PASSWORD);
// Configure PDO to throw exceptions
self::$_mHandler->setAttribute(PDO::ATTR_ERRMODE,
PDO::ERRMODE_EXCEPTION);
self::$_mHandler->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
}
catch (PDOException $e)
{
// Close the database handler and trigger an error
self::Close();
trigger_error($e->getMessage(), E_USER_ERROR);
}
}
// Return the database handler
return self::$_mHandler;
}
// Clear the PDO class instance
public static function Close()
{
self::$_mHandler = null;
}
// Wrapper method for PDO::prepare
private static function Prepare($queryString)
{
// Execute code catching potential exceptions
try
{
// Get the database handler and prepare the query
$database_handler = self::GetHandler();
$statement_handler = $database_handler->prepare($queryString);
// Return the prepared statement
return $statement_handler;
}
catch (PDOException $e)
{
// Close the database handler and trigger an error
self::Close();
trigger_error($e->getMessage(), E_USER_ERROR);
}
}
// Wrapper method for PDOStatement::execute()
public static function Execute($sqlQuery, $params = null)
{
// Try to execute an SQL query or a stored procedure
try
{
$statement_handler = self::Prepare($sqlQuery);
// Execute query
$statement_handler->execute($params);
}
// Trigger an error if an exception was thrown when executing the SQL query
catch(PDOException $e)
{
// Close the database handler and trigger an error
self::Close();
trigger_error($e->getMessage(), E_USER_ERROR);
}
}
// Wrapper method for PDOStatement::fetchAll()
public static function GetAll($sqlQuery, $params = null,
$fetchStyle = PDO::FETCH_ASSOC)
{
// Initialize the return value to null
$result = null;
// Try to execute an SQL query or a stored procedure
try
{
$statement_handler = self::Prepare($sqlQuery);
// Execute the query
$statement_handler->execute($params);
// Fetch result
$result = $statement_handler->fetchAll($fetchStyle);
}
// Trigger an error if an exception was thrown when executing the SQL query
catch(PDOException $e)
{
// Close the database handler and trigger an error
self::Close();
trigger_error($e->getMessage(), E_USER_ERROR);
}
// Return the query results
return $result;
}
// Wrapper method for PDOStatement::fetch()
public static function GetRow($sqlQuery, $params = null,
$fetchStyle = PDO::FETCH_ASSOC)
{
// Initialize the return value to null
$result = null;
// Try to execute an SQL query or a stored procedure
try
{
$statement_handler = self::Prepare($sqlQuery);
// Execute the query
$statement_handler->execute($params);
// Fetch result
$result = $statement_handler->fetch($fetchStyle);
}
// Trigger an error if an exception was thrown when executing the SQL query
catch(PDOException $e)
{
// Close the database handler and trigger an error
self::Close();
trigger_error($e->getMessage(), E_USER_ERROR);
}
// Return the query results
return $result;
}
// Return the first column value from a row
public static function GetOne($sqlQuery, $params = null)
{
// Initialize the return value to null
$result = null;
// Try to execute an SQL query or a stored procedure
try
{
$statement_handler = self::Prepare($sqlQuery);
// Execute the query
$statement_handler->execute($params);
// Fetch result
$result = $statement_handler->fetch(PDO::FETCH_NUM);
/* Save the first value of the result set (first column of the first row)
to $result */
$result = $result[0];
}
// Trigger an error if an exception was thrown when executing the SQL query
catch(PDOException $e)
{
// Close the database handler and trigger an error
self::Close();
trigger_error($e->getMessage(), E_USER_ERROR);
}
// Return the query results
return $result;
}
}
?>
You should pass a connection object (probably PDO) around, and the various places should be able to pick that up, either as a parameter, or as a property of some central object which the others have a reference to, or something.
Having multiple connections can be useful, it seems insane that mysql_connect picks up an existing connection when you might have wanted a new one - but it's insane anyway. Just use PDO.
You can use that method if you use mysql_pconnect() function, wich will search if there's already a mysql connection and in case it finds it, it wouldn't create another one.
In alternative, if you consider nor to use instances in php, you can call php database object directly, like :
class DB {}
DB::connect($host, $user, $pass);
If you use this method, you don't need to worry about multiple connections. Of course that if you need to use several connections to more than one database at a time, you can make use of object instances, or make your class so it can take several parameters and store them all at once (not very recomemded this one)

Categories