Dereference field has no affect on subquery after calling hasOne() #97

Closed
LostInTheWeb opened this Issue Sep 15, 2012 · 6 comments

Comments

Projects
None yet
3 participants
@LostInTheWeb

Following from the question raised at

http://stackoverflow.com/questions/10392457/pathfinder-exception-unable-to-include-model-model-using-setmodel/10396547#comment16698871_10396547

The dereference_field can be set by $m->dereference_field, but my reading of the source code leads to the conclusion that because the Reference::setModel() called inside hasOne() generates the subquery using the dereference_field. Changing dereference_field after hasOne() has not affect on the subquery.

So I modified the hasOne() function to the following, where hasOne sets the dereferenced_field variable. However, this does not fix the problem of changing the dereference_field after hasOne has been called.

/atk4/lib/Model/Table.php

/** Defines one to many association */
function hasOne($model,$our_field=null,$display_field=null,$deref_field_name=null){
    if(!$our_field){
        if(!is_object($model)){
            $tmp=preg_replace('|^(.*/)?(.*)$|','\1Model_\2',$model);
            $tmp=new $tmp; // avoid recursion
        }else $tmp=$model;
        $our_field=($tmp->table).'_id';
    }
    $r=$this->add('Field_Reference',$our_field);
    $r->dereferenced_field=$deref_field_name;
    $r->setModel($model,$display_field);
    return $r;
}
@romaninsh

This comment has been minimized.

Show comment Hide comment
@romaninsh

romaninsh Sep 16, 2012

Member

We can take advantage of the second argument which can be an array in Agile Toolkit. Suppose your object has a property "dereferenced_field". Adding an object like this allows to override the property:

$this->add('Field_Reference',array('dereferenced_field'=>'test_deref', 'name'=>'test_id'));

it also seem that passing 2nd argument to the hasOne() can transparently invoke this feature without the need of extra argument. Possibly additional functionality could be helpful here, can you confirm that the suggested format works for you?

Member

romaninsh commented Sep 16, 2012

We can take advantage of the second argument which can be an array in Agile Toolkit. Suppose your object has a property "dereferenced_field". Adding an object like this allows to override the property:

$this->add('Field_Reference',array('dereferenced_field'=>'test_deref', 'name'=>'test_id'));

it also seem that passing 2nd argument to the hasOne() can transparently invoke this feature without the need of extra argument. Possibly additional functionality could be helpful here, can you confirm that the suggested format works for you?

@LostInTheWeb

This comment has been minimized.

Show comment Hide comment
@LostInTheWeb

LostInTheWeb Sep 17, 2012

Hi Romans,

Yes the suggested approach works for me. However, I should have been more clear in my issue. The expected behaviour of linking Models using hasOne() would be able to override the the default value of "dereference_field" after calling it.

Pseudocode:

class Model_EmployeeA extends Model_Table {
    $person = $this->hasOne('Person');
}

class Model_EmployeeB extends Model_Table {
    $person = $this->hasOne('Person');
    // The below code would be expected to work, but it does not as the subquery has already been generated during the hasOne() call.
    $person->dereferenced_field = 'person_name'
}

class page_MyPage extends Page {

     // case 1 - default behaviour
    $employee = $this->add('Model_EmployeeA')->getAny();
    $person = $employee->ref('Person')->debug();
    // 

    select `idemployee`,(select `name` from `person` where `employee`.`person_idperson` = `person`.`idperson` ) `person_idperson_2` from `employee` where `employee`.`idemployee` = "1"

    // case 2 - changing dereferenced_field should yield the following query, but does not.
    $employee = $this->add('Model_EmployeeB')->getAny();
    $person = $employee->ref('Person')->debug();

    select `idemployee`,(select `name` from `person` where `employee`.`person_idperson` = `person`.`idperson` ) `person_name` from `employee` where `employee`.`idemployee` = "1"

}

Is there a way to add to the API a method for regenerating the subquery after hasOne() is called. This would need a change to the Reference class, but you are the best person to decide this.

Hi Romans,

Yes the suggested approach works for me. However, I should have been more clear in my issue. The expected behaviour of linking Models using hasOne() would be able to override the the default value of "dereference_field" after calling it.

Pseudocode:

class Model_EmployeeA extends Model_Table {
    $person = $this->hasOne('Person');
}

class Model_EmployeeB extends Model_Table {
    $person = $this->hasOne('Person');
    // The below code would be expected to work, but it does not as the subquery has already been generated during the hasOne() call.
    $person->dereferenced_field = 'person_name'
}

class page_MyPage extends Page {

     // case 1 - default behaviour
    $employee = $this->add('Model_EmployeeA')->getAny();
    $person = $employee->ref('Person')->debug();
    // 

    select `idemployee`,(select `name` from `person` where `employee`.`person_idperson` = `person`.`idperson` ) `person_idperson_2` from `employee` where `employee`.`idemployee` = "1"

    // case 2 - changing dereferenced_field should yield the following query, but does not.
    $employee = $this->add('Model_EmployeeB')->getAny();
    $person = $employee->ref('Person')->debug();

    select `idemployee`,(select `name` from `person` where `employee`.`person_idperson` = `person`.`idperson` ) `person_name` from `employee` where `employee`.`idemployee` = "1"

}

Is there a way to add to the API a method for regenerating the subquery after hasOne() is called. This would need a change to the Reference class, but you are the best person to decide this.

@romaninsh

This comment has been minimized.

Show comment Hide comment
@romaninsh

romaninsh Sep 17, 2012

Member

It’s not possible to re-define that field name later, because the dereferenced field is created right away so that it can be later used to modify meta information

I agree it could be documented better.

Hi Romans,

Yes the suggested approach works for me. However, I should have been more clear in my issue. The expected behaviour of linking Models using hasOne() would be able to override the the default value of "dereference_field" after calling it.

Model_Employee_A {
$person = $this->hasOne('Person');
}

Model_Employee_B {
$person = $this->hasOne('Person');

}


Reply to this email directly or view it on GitHub.

Romans is the author of a revolutionary Web Development Framework
Agile Toolkit (www.agiletoolkit.org), which is offered under Open Source
License. Please show your support by raising awareness (tell your friends
about it) or referring any commercial web development projects towards
our skilled developer team (http://www.agiletech.ie/company/)

Here is a 25-minute video explaining why Agile Toolkit is awesome:
http://www.youtube.com/watch?v=eyeZhwP1LP4

Member

romaninsh commented Sep 17, 2012

It’s not possible to re-define that field name later, because the dereferenced field is created right away so that it can be later used to modify meta information

I agree it could be documented better.

Hi Romans,

Yes the suggested approach works for me. However, I should have been more clear in my issue. The expected behaviour of linking Models using hasOne() would be able to override the the default value of "dereference_field" after calling it.

Model_Employee_A {
$person = $this->hasOne('Person');
}

Model_Employee_B {
$person = $this->hasOne('Person');

}


Reply to this email directly or view it on GitHub.

Romans is the author of a revolutionary Web Development Framework
Agile Toolkit (www.agiletoolkit.org), which is offered under Open Source
License. Please show your support by raising awareness (tell your friends
about it) or referring any commercial web development projects towards
our skilled developer team (http://www.agiletech.ie/company/)

Here is a 25-minute video explaining why Agile Toolkit is awesome:
http://www.youtube.com/watch?v=eyeZhwP1LP4

@romaninsh

This comment has been minimized.

Show comment Hide comment
@romaninsh

romaninsh Sep 17, 2012

Member

you can always delete a field with $field->destroy() btw and create one yourself.

You can also use 3rd argument "false" to avoid creation of dereferenced field.

Member

romaninsh commented Sep 17, 2012

you can always delete a field with $field->destroy() btw and create one yourself.

You can also use 3rd argument "false" to avoid creation of dereferenced field.

@DarkSide666

This comment has been minimized.

Show comment Hide comment
@DarkSide666

DarkSide666 Oct 12, 2012

Member

Maybe it's solved with Romans commit 0917169 ?

Member

DarkSide666 commented Oct 12, 2012

Maybe it's solved with Romans commit 0917169 ?

@DarkSide666

This comment has been minimized.

Show comment Hide comment
@DarkSide666

DarkSide666 Feb 17, 2016

Member

Obsolete, should be fixed with 0917169

Member

DarkSide666 commented Feb 17, 2016

Obsolete, should be fixed with 0917169

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment