Multiple Foreign Key to same table Gas Orm

2019-02-20 13:38发布

问题:

Since this mornong i am facing a very big problem. I am using CodeIgniter to develop a website, and GAS ORM for the database. I have basically two tables. One named "pool", and one named "partners". I am having two associations between these two tables, so I have two foreign keys in my table Partners referencing the table pool.

Pool(#id:integer, name:varchar) Partners(#id:integer, associated_pool_id=>Pool, futur_associated_pool_id=>Pool).

As I have two references to the same table, I can't name the foreign keys "pool_id". So in my relationships with Gas ORM, I have to specify the names of the columns. I do it, but it doesn't work... Here is what I do:

class Partner extends ORM {

public $primary_key = 'id';
public $foreign_key = array('\\Model\\Pool' => 'associated_pool_id', '\\Model\\Pool' => 'future_associated_pool_id');

function _init()
{

    // Relationship definition
    self::$relationships = array(
            'associated_pool' => ORM::belongs_to('\\Model\\Pool'),
            'future_association_pool'  => ORM::belongs_to('\\Model\\Pool'),
    );

    self::$fields = array(
        'id' => ORM::field('auto[11]'),
        'name' => ORM::field('char[255]'),
        'associated_pool_id' => ORM::field('int[11]'),
        'future_associated_pool_id' => ORM::field('int[11]')
    );

}

and in my Pool class :

class Pool extends ORM {

public $primary_key = 'id';

function _init()
{
    // Relationship definition
    self::$relationships = array(
            'associated_partner' => ORM::has_many('\\Model\\Partner'),
            'future_associated_partner'  => ORM::has_many('\\Model\\Partner'),
    );

    self::$fields = array(
        'id' => ORM::field('auto[11]'),
        'name' => ORM::field('char[50]'),
    );

}

I have a test controller testing if everything is okay:

class Welcome extends CI_Controller {
public function index()
{

    $pool = \Model\Pool::find(1);
    echo $pool->name;
    $partners = $pool->associated_partner();
    var_dump($partners);
}

But I have an error saying:

Error Number: 1054

Champ 'partner.pool_id' inconnu dans where clause

SELECT * FROM partner WHERE partner.pool_id IN (1)

I don't know how to specify to Gas ORM that it shouldn't take "pool_id" but "associated_pool_id"....

Thank you for your help!!!!!!!!!!!!

回答1:

I don't know, if this topic is still up to date and interesting to some of you, but in general, I had the exact same problem.

I decided Gas ORM to be my mapper in combination with CodeIgniter. As my database structure was given and it was not following the table_pk convention of Gas, I had to define a foreign key by myself which shall refer to my custom database foreign key. However, the definition of it had no impact on anything. Like your error above, the mapper was not able to build the right SQL-statement. The statement looked similar to yours:

   SELECT * FROM partner WHERE partner.pool_id IN (1)

Well, it seems like Gas ignores the self-defined foreign keys and tries to use the default table_pk convention. This means, it takes the table (in your case: pool) and the primary key (id) by merging it with a underscore character.

I figured out, that the constructor of orm.php handles every primary and foreign key defined within the entities. In line 191, the code calls an if clause combined with the empty function of php. As the primary key is defined always and there is no negation in the statement, it skips the inner part of the clause every time. However, the inner part takes care of the self-defined foreign keys.

Long story short, I added a negation (!) in line 191 of orm.php which leads me to the following code:

if ( ! empty($this->primary_key))
    {
        if ( ! empty($this->foreign_key))
        {
            // Validate foreign keys for consistency naming convention recognizer
            $foreign_key = array();

            foreach($this->foreign_key as $namespace => $fk)
            {
                $foreign_key[strtolower($namespace)] = $fk;
            }

            $this->foreign_key = $foreign_key;
        }
        else
        {
            // If so far we didnt have any keys yet, 
            // then hopefully someone is really follow Gas convention
            // while he define his entity relationship (yes, YOU!)
            foreach ($this->meta->get('entities') as $name => $entity)
            {
                if ($entity['type'] == 'belongs_to')
                {
                    $child_name     = $entity['child'];
                    $child_instance = new $child_name;
                    $child_table    = $child_instance->table;
                    $child_key      = $child_instance->primary_key;

                    $this->foreign_key[strtolower($child_name)] = $child_table.'_'.$child_key;
                }
            }
        }
    }

Well, this little fix helped me out a lot and I hope some of you can take advantage of this hint as well.