Activerecord-association: create new object (find class)

余生颓废 提交于 2019-12-03 04:04:22

You can also use build_association() in the relationship classes.
Simplest way to use it is through the Model's __call, i.e. if your relation is something like $person->company, then you could instantiate the company with
$company = $person->build_company()

Note that this will NOT also make the "connection" between your objects ($person->company will not be set).
Alternatively, instead of build_company(), you can use create_company(), which will save a new record and link it to $person

In PHPActiveRecord, you have access to the relations array. The relation should have a name an you NEED TO KNOW THE NAME OF THE RELATIONSHIP/ASSOCIATION YOU WANT. It doesn't need to be the classname, but the classname of the Model you're relating to should be explicitly indicated in the relation. Just a basic example without error checking or gritty relationship db details like linking table or foreign key column name:

class Person extends ActiveRecord\Model {
    static $belongs_to = array(
                       array('company',
                                 'class_name' => 'SomeCompanyClass')
                                 );
    //general function get a classname from a relationship
    public static function getClassNameFromRelationship($relationshipName)       
       foreach(self::$belongs_to as $relationship){
          //the first element in all relationships is it's name
          if($relationship[0] == $relationshipName){
             $className = null;
                if(isset($relationship['class_name'])){
                  $className = $relationship['class_name'];
                }else{
                  // if no classname specified explicitly,
                  // assume the clasename is the relationship name
                  // with first letter capitalized
                  $className = ucfirst($relationship);
                }
                return $className               
            }
        }   
        return null;
     }
}

To with this function, if you have a person object and want an object defined by the 'company' relationship use:

$className = $person::getClassNameFromRelationship('company');
$company = new $className();

I'm currently using below solution. It's an actual solution, instead of the $has_one[1] hack I mentioned in the question. If there is a method in phpactiverecord I'm going to feel very silly exposing msyelf. But please, prove me silly so I don't need to use this solution :D

I am silly. Below functionality is implemented by the create_associationname call, as answered by @Bogdan_D


Two functions are added. You should probably add them in the \ActiveRecord\Model class. In my case there is a class between our classes and that model that contains extra functionality like this, so I put it there.

These are the 2 functions:

  • public function findClassByAssociation($associationName)
    • Called with the name of the association you are looking for.
    • Checks three static vars (has_many,belongs_to and has_one) for the association
    • calls findClassFromArray if an association is found.
    • from the person/company example: $person->findClassByAssociation('company');
  • private function findClassFromArray($associationName,$associationArray)
    • Just a worker-function that tries to match the name.

Source:

/**
 * Find the classname of an explicitly defined 
 * association (has_one, has_many, belongs_to). 
 * Unsure if this works for standard associations 
 * without specific mention of the class_name, but I suppose it doesn't!
 * @todo Check if works without an explicitly set 'class_name', if not: is this even possible (namespacing?)
 * @todo Support for 'through' associations.
 * @param String $associationName the association you want to find the class for
 * @return mixed String|false if an association is found, return the class name (with namespace!), else return false
 * @see findClassFromArray 
 */
public function findClassByAssociation($associationName){
    //$class = $this::$has_one[1]['class_name'];
    $that = get_called_class();
    if(isset($that::$has_many)){
        $cl = $this->findClassFromArray($associationName,$that::$has_many);
        if($cl){return $cl;}
    }
    if(isset($that::$belongs_to)){
        $cl = $this->findClassFromArray($associationName,$that::$belongs_to);
        if($cl){return $cl;}
    }
    if(isset($that::$has_one)){
        $cl = $this->findClassFromArray($associationName,$that::$has_one);
        if($cl){return $cl;}
    }
    return false;
}

/**
 * Find a class in a php-activerecord "association-array". It probably should have a specifically defined class name!
 * @todo check if works without explicitly set 'class_name', and if not find it like standard
 * @param String $associationName 
 * @param Array[] $associationArray phpactiverecord array with associations (like has_many)
 * @return mixed String|false if an association is found, return the class name, else return false
 * @see findClassFromArray
 */
private function findClassFromArray($associationName,$associationArray){
    if(is_array($associationArray)){
        foreach($associationArray as $association){
            if($association['0'] === $associationName){
                return $association['class_name'];
            }
        }
    }
    return false;
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!