j4mie/idiorm

rowCount

featureless opened this issue · 14 comments

HI,

Why not use PDOStatement :: rowCount to get the number of rows affected by the last statement.

This property could be populated in the _run function after the statement execution like this:
$this->_rowCount = $statement->rowCount();

Regards,

Can you give me a use case for this feature?

Yes, I know it's a raw_query use but....

$follows->raw_query('update follows set follow = 0 where (item_id=:item_id and user_id=:user_id)', array('item_id'=>$item_id,'user_id'=>$user_id))
    ->find_many();
return $follows->rowCount();

I think this could be more useful with delete() and delete_many().

tag commented

As a workaround, consider $result->get_db() to access the PDO object directly. A fuller example might be $result->get_db()->rowCount().

Unfortunately, PDOStatement::rowCount() is inconsistent across database providers, and if the comments on the documentation page are to be believed, not even consistent across versions of the database. Per the PHP documentation, "[T]his behaviour is not guaranteed for all databases and should not be relied on for portable applications."

@featureless @tag has beaten me to it. I was going to suggest that you drop down to the PDO object directly for this. I wanted a use case though to ensure that it was an appropriate suggestion :)

@tag thanks for the idea, but unfortunately it did not work, get_db() return a PDO object not PDOStatement.

Of course. Good catch. Re-opening.

Any one want to work on a patch for this?

for reasons of portability, I could understand that it isn't implemented, another solution could be to have access to PDOStatement in idiorm, so it would be possible to have rowCount and also columnCount, debugDumpParams, errorCode, errorInfo

@featureless sounds like a good idea, but I am not sure how it would be possible. Want to submit a pull request?

I think a simple solution could be to add a new property and function like that:

protected $_last_statement = null;

public function execute($query, $input_parameters = array()) {
    $statement = self::$_db->prepare($query);
    $success = $statement->execute($input_parameters);
    $this->_last_statement = $statement;

    return $success;
}

After replacing code like

$statement = self::$_db->prepare($query);
$statement->execute($this->_values);

By:

$this->execute($query,$this->_values);

For example _run could be:

protected function _run() {
        $query = $this->_build_select();
        $caching_enabled = self::$_config['caching'];

        if ($caching_enabled) {
                $cache_key = self::_create_cache_key($query, $this->_values);
                $cached_result = self::_check_query_cache($cache_key);

                if ($cached_result !== false) {
                        return $cached_result;
                }
        }

        self::_log_query($query, $this->_values);
        $this->execute($query,$this->_values);

        $rows = array();
        while ($row = $this->_last_statement->fetch(PDO::FETCH_ASSOC)) {
                $rows[] = $row;
        }

        if ($caching_enabled) {
                self::_cache_query_result($cache_key, $rows);
        }

        return $rows;
}

This could work out OK. I do not have the time to complete this change though so it would be great if someone could pick it up and submit a full pull request.

tag commented

I can play with it. I'll make sure it works with raw_execute(), and will look into save() too, so we can grab it on creates and updates.

Given these other concerns, it might be more straightforward to not abstract out ORM::execute() as described by @featureless, and just create an accessor method, ORM::get_last_statement() ... I'll tinker.

Is there agreement on at least ORM::get_last_statement() and protected $_last_statement;?

Thanks for looking into this. Yes, those two namings sound good.

tag commented

See pull request. Ended up following @featureless's concept very closely, although I used _execute(), and made it protected, as raw_execute() is already in place. PDOStatement should now be available after save(), _run() (all selects), delete(), delete_many(), and raw_execute(). I think I got 'em all.

I neglected to add a test. Maybe when I get home tonight.

Hi tag, good job! thanks.