phalcon / cphalcon

High performance, full-stack PHP framework delivered as a C extension.
https://phalcon.io
BSD 3-Clause "New" or "Revised" License
10.79k stars 1.96k forks source link

[BUG] Phalcon\Mvc\Model.Same db table names, different databases, different models are handled as one class. #501

Closed alvassin closed 11 years ago

alvassin commented 11 years ago

Hello, i have two different databases, let call them forum and blog. In each database i have table accounts, that contains specific for each database data for same accounts. I mean, that each table has different columns, rules, everything.

Example of models:

// Blog.Accounts model
namespace Blog;

class Accounts
{
    public $id;
    public $brand_account_id;

    public function initialize()
    {
        $this->setConnectionService('dbBlog');
    }

    public function getSource()
    {
        return 'Accounts';
    }   
}

// Forum.Accounts model
namespace Forum;

class Accounts
{
    public $id;
    public $server;

    public function initialize()
    {
        $this->setConnectionService('dbForum');
    }

    public function getSource()
    {
        return 'Accounts';
    }   

    public function columnMap()
    {
        return [
            'id'     => 'id',
            'Server' => 'server',
        ];
    }
}

Ok. now let's try to work with both models:

$account = Blog\Accounts::findFirst(array(
    'brand_account_id = :account:',
    'bind' => array('account' => $accountId),
));

$account2 = Forum\Accounts::findFirst(array(
    'id= :account:',
    'bind' => array('account' => $accountId),
));

Finally i see exception: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'Accounts.Server' in 'field list' file: /var/www/trunk/app/controllers/AccountController.php line: 67

Server property exists only in Forum\Accounts model, and we really do not use it here! Perhaps smth is going wrong with cache or someting inside phalcon?

I've doublechecked my code, bug is reproduceable and i can't find it on my side. Could you check it please?

P.S. Perhaps this will be useful information: If i rename any table (in mysql, not model class) for example to "Accounts1", everything will work fine. I am using last version (from master), updated it yesterday.

alvassin commented 11 years ago

Could you please assist with this bug? Its quite important for me, because it makes batch requests functionality implementation for jsonrpc 2.0 impossible :((

niden commented 11 years ago

@avasin We will look into this as soon as we can. Thanks for the detailed explanation and hints on where the issue lies.

xboston commented 11 years ago

already fixed, cool! test - ok ;)

в ветке 1.0.1 уже поправлено https://github.com/phalcon/cphalcon/commit/42ac1fdf32915d0ca4de76522a42c61912e5cecd , проверил - работает отлично

phalcon commented 11 years ago

This is fixed in the 1.0.1 branch

alvassin commented 11 years ago

Thanks a lot!

alvassin commented 11 years ago

@phalcon @niden just tested with same models, i see an exception of $model->save():

Column 'Server\" isn't part of the column map file

Exception message is different, but bug appears again when using 2 models with same table names from different databases :((

So, it is not fixed.. please check it again...

alvassin commented 11 years ago

@phalcon @niden bug is not fixed... can you reopen the ticket please?

niden commented 11 years ago

@avasin Could you please create a failing test to help us identify the error? You can clone the repo and issue a pull request.

Thanks!

alvassin commented 11 years ago

I have very little experience with git.. but i will by end of this week, thank you :)

niden commented 11 years ago

Let me know how can I help with this :) On Apr 4, 2013 5:18 PM, "Alexander" notifications@github.com wrote:

I have very little experience with git.. but i will by end of this week, thatnk you :)

— Reply to this email directly or view it on GitHubhttps://github.com/phalcon/cphalcon/issues/501#issuecomment-15924588 .

phalcon commented 11 years ago

Please let us know when the tests are ready to re-open this issue, thanks

alvassin commented 11 years ago

@phalcon @niden

Hello, i was unable to write clear test (you have quite big tests infrastructure). I wrote simplest script i could to represent the bug in clear way. Before executing the script, please execute following SQL to create databases and tables:

  CREATE DATABASE forum;
  USE forum;
  CREATE TABLE IF NOT EXISTS `accounts` (
    `id` int(11) NOT NULL AUTO_INCREMENT,
    `email` varchar(255) NOT NULL,
    `password` varchar(32) NOT NULL,
    PRIMARY KEY (`id`),
    UNIQUE KEY `email` (`email`)
  ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;

  CREATE DATABASE blog;
  USE blog;
  CREATE TABLE IF NOT EXISTS `accounts` (
    `id` int(11) NOT NULL AUTO_INCREMENT,
    `forum_account_id` int(11) NOT NULL,
    `name` varchar(20) NOT NULL,
    PRIMARY KEY (`id`)
  ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;

And php script, representing the bug:

<?php

$di = new \Phalcon\DI();

$di->set('dbBlog', function() use ($config) {
    return new \Phalcon\Db\Adapter\Pdo\Mysql([
        'host'     => 'localhost',
        'dbname'   => 'blog',
        'username' => 'root',
        'password' => '',
    ]);
});

$di->set('dbForum', function() use ($config) {
    return new \Phalcon\Db\Adapter\Pdo\Mysql([
        'host'     => 'localhost',
        'dbname'   => 'forum',
        'username' => 'root',
        'password' => '',    
    ]);
});

$di->set('modelsManager', 'Phalcon\Mvc\Model\Manager');
$di->set('modelsMetadata', 'Phalcon\Mvc\Model\MetaData\Memory');

class BlogAccounts extends Phalcon\Mvc\Model
{
    public $id;
    public $forum_account_id;
    public $name;

    public function initialize()
    {
        $this->setConnectionService('dbBlog');
    }

    public function getSource()
    {
        return 'accounts';
    }
}

class ForumAccounts extends Phalcon\Mvc\Model
{
    public $id;
    public $email;
    public $password;

    public function initialize()
    {
        $this->setConnectionService('dbForum');
    }

    public function getSource()
    {
        return 'accounts';
    }
}

// Bug example:
$forumAccount = new ForumAccounts();
$forumAccount->email    = 'test@test.com';
$forumAccount->password = md5('hackme');
if (!$forumAccount->save()) {
    echo "forum inserting issue: \n";
    var_dump($forumAccount->getMessages());
}

$blogAccount = new BlogAccounts();
$blogAccount->forum_account_id = $forumAccount->id;
$blogAccount->name = 'test name';
if (!$blogAccount->save()) {
    echo "blog inserting issue: \n";
    var_dump($blogAccount->getMessages());

    /**
     *  blog inserting issue:
     *  array(2) {
     *    [0]=>
     *    object(Phalcon\Mvc\Model\Message)#19 (4) {
     *      ["_type":protected]=>
     *      string(10) "PresenceOf"
     *      ["_message":protected]=>
     *      string(17) "email is required"
     *      ["_field":protected]=>
     *      string(5) "email"
     *      ["_model":protected]=>
     *      NULL
     *    }
     *    [1]=>
     *    object(Phalcon\Mvc\Model\Message)#20 (4) {
     *      ["_type":protected]=>
     *      string(10) "PresenceOf"
     *      ["_message":protected]=>
     *      string(20) "password is required"
     *      ["_field":protected]=>
     *      string(8) "password"
     *      ["_model":protected]=>
     *      NULL
     *    }
     *  }
     */
}
alvassin commented 11 years ago

As you can see in my last comment in the code - blog model can't be inserted. Phalcon thinks, that it has email/password fields, when it actually have not.

niden commented 11 years ago

Somehow it thinks that the connection used is the one of the forum vs. the blog. I will try and get a test set to help you out and get this bug fixed.

alvassin commented 11 years ago

@niden, @phalcon hello, kindly reminding about this issue :)

alvassin commented 11 years ago

@niden @phalcon btw, could you please reopen this issue?

phalcon commented 11 years ago

I can't still see the bug, I created two databases with tables you're mentioning, running the test without problem:

You can see it running here: http://test.phalconphp.com/mdb.php

However, you don't need to create a connection if both models are mapping tables in the same server, this leads to create two connections (one for each model) which is bad.

You can just set the schema which belongs each model, reusing the same connection:

class BlogAccounts extends Phalcon\Mvc\Model
{
    public $id;
    public $forum_account_id;
    public $name;

    public function initialize()
    {
        $this->setSource('accounts');
        $this->setSchema('blog');
    }

}
alvassin commented 11 years ago

@phalcon thanks very much. After big amount of days i realized that i've updated phalcon on different vm. it is so.. damn. sorry for disturbing for this issue again :) everything works fine now.