We have moved our forum to GitHub Discussions. For questions about Phalcon v3/v4/v5 you can visit here and for Phalcon v6 here.

How to totally skip columns from database? (skipAttributes does not working)

Hello!

I have for example 5 fields in database. For 3 of these i need column mapping but other two i don't need on ALL parts of my application.

Model:

namespace \Api\Models;
class Users extends \Phalcon\Mvc\Model
{
    public $field1;
    public $field2;
    public $field3;

    public function initialize()
    {
        $this->skipAttributes([
            'field4',
            'field5',
        ]);
    }

    public function columnMap()
    {
        return [
            'field_no1' => 'field1',
            'field_no2' => 'field2',
            'field_no3' => 'field3',
        ];
    }
}

In that case i have exception:

$user = Users::findFirst(42); // Phalcon\Mvc\Model\Exception: Column "field_no4" doesn't make part of the column map

So, my question is simple: how to skip fields in database in whole app?



21.7k

Em.. This is not usable for whole application ):

Or. maybe.. extending Model::find() and call $modelName->publicColumns() to get really needed columns! Not so good cuz need to extend framework, but works. Thank you.

The only way I know is the specify the columns like this:

$id = (int) $getTheIDFromSomewhere;
$userResultSet = User::findFirst([
   'id = :id:',
   'bind' => ['id' => $id],
   'columns' => 'id, name, email, username, status, role' // I didn't need columns like password, date created etc
]);


21.7k

Hmm, seems that ::find() with 'columns' and without returns different types of data ): This is bad.. refactoring of whole app again.

Looks like I got the accepted answer prematurely again :), anyway, I did a test with:

$this->view->setVar('product', \Models\Products::find(['columns' => 'id, name']));
$this->view->setVar('product', \Models\Products::find());

I get the same: Phalcon\Mvc\Model\Resultset\Simple Object where I can get each row of data like:

foreach ($product as $productRow) {
    echo $productRow->name;
}

Are you getting a stdClass, Phalcon\Mvc\Model\Query\Builder Object or some other type if you do a print_r()?



21.7k
edited Jan '15

Yep (: And i don't see button for "un-accept" answer.

Interesting. I'm not using any views at all, just raw json output. Maybe, in this layer Phalcon do a little magic?

Here are tests. Let's imagine that exists some Users::getRating() whatever it returns. I've added dockblocks to see what is REALLY returns var_dump() (real return differs from phalcon devtools 1.3.x-dev in PHPStorm 8).

First, without 'columns':

/** @type \Api\Models\Users $user */
$user = Users::findFirst($id);
$user->getRating(); // Good

/** @type \Phalcon\Mvc\Model\Resultset\Simple $user */
$users = Users::find($id);
/** @type \Api\Models\Users $user */
$user  = $users->getFirst();
$user->getRating(); // Good

Seems good. What if we add 'columns'?:

/** @type \Phalcon\Mvc\Model\Row $user */
$user = Users::findFirst(array($id, 'columns' => 'id'));
$user->getRating(); // Fatal error: Call to undefined method Phalcon\Mvc\Model\Row::getRating()

/** @type \Phalcon\Mvc\Model\Resultset\Simple $user */
$users = Users::find(array($id, 'columns' => 'id'));
/** @type \Phalcon\Mvc\Model\Row $user */
$user  = $users->getFirst();
$user->getRating(); // Fatal error: Call to undefined method Phalcon\Mvc\Model\Row::getRating()

It's broken ):



21.7k
edited Jan '15

My use-cases:

  1. Find model(s) with only needed columns. I have in database columns, that we don't need at all in whole application and that don't need in this case (e.g., we don't need to get and send user password).
  2. Fill these models with additional data (maybe, realtions or some aggregated data)
  3. Convert to array
  4. Send as json/xml

What i've tried already:

  1. Model::skipAttributes() in Model::initialize(). Simple does not working. I see them even if i do Mode::toArray(). Bad.
  2. Extending and hardly unset these bad attributes. But i don't know how to extend Model::find() and toArray() return these fields as null. Plus, i don't want to get these fields even from database (optimization). Something like this:
class Users extends BaseModel
{
    public static function findFirst($params = null)
    {
        $model = parent::findFirst($params);
        foreach (self::skippedColumns() as $field)
            unset($model->$field);
    }

    public function toArray($columns = null)
    {
        $array = parent::toArray();
        foreach (self::skippedColumns() as $field)
            unset($array[$field]);
    }

    public static function skippedFields()
    {
        return [
            'field_no4',
            'field_no5',
        ];
    }
}

Any other ideas?

Deleted my "accepted answer" post, but its still marked as solved.



21.7k

Yep, this works. I see thread as unaccepted. Maybe, it was cache.

Deleted my "accepted answer" post, but its still marked as solved.