Activerecord-association: create new object (find class)

后端 未结 3 1170
我在风中等你
我在风中等你 2021-02-06 18:47

I have an model with a relation, and I want to instantiate a new object of the relations type.

Example: A person has a company, and I have a person-obje

相关标签:
3条回答
  • 2021-02-06 19:20

    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();
    
    0 讨论(0)
  • 2021-02-06 19:24

    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;
    }
    
    0 讨论(0)
  • 2021-02-06 19:35

    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

    0 讨论(0)
提交回复
热议问题