Activerecord-association: создать новый объект (найти класс)

У меня есть модель с отношением, и я хочу создать экземпляр нового объекта типа отношений.

Пример. У человека есть компания, и у меня есть объект person: теперь я хочу создать компанию-объект.

Класс companyobject определен в отношении, поэтому я не думаю, что мне нужно «знать» этот класс, но я должен попросить человека-объекта предоставить мне новый экземпляр компании типа? Но я не знаю, как это сделать.

Это – я думаю – тот же вопрос, что и объект новой модели, через ассоциацию , но я использую PHPActiveRecord , а не рубиновый.


Причина этого: у меня есть абстрактный person суперкласса, и у двух детей есть свое отношение к типу объекта компании. Мне нужно создать экземпляр правильного класса у абстрактного человека.

static $has_one является получение его непосредственно из static $has_one массива static $has_one :

 $class = $this::$has_one[1]['class_name']; $company = new $class; 

Конечно, число с жестким кодом, конечно, может быть устранено путем поиска имени ассоциации в массиве, но это все еще довольно уродливо.


Если кто-то знает, как это реализовано в Ruby, и как отличается реализация phpactiverecord, я могу получить оттуда некоторые идеи?


Некоторое тестирование показало, что хотя «поиск моего имени класса в массиве» выглядит странно, он не оказывает никакого влияния на производительность, и в использовании он достаточно функциональный.

Solutions Collecting From Web of "Activerecord-association: создать новый объект (найти класс)"

Вы также можете использовать build_association() в классах отношений.
Самый простой способ использовать это через __call модели, т. Е. Если ваше отношение – это что-то вроде компании $person->company , то вы можете создать экземпляр компании с помощью
$company = $person->build_company()

Обратите внимание, что это НЕ также приведет к «соединению» между вашими объектами ( $person->company не будет установлена).
В качестве альтернативы вместо build_company() вы можете использовать create_company() , который сохранит новую запись и свяжет ее с $ person

В PHPActiveRecord у вас есть доступ к массиву отношений. Отношение должно иметь имя, которое вам НЕОБХОДИМО ЗНАТЬ ИМЯ СВЯЗИ / АССОЦИАЦИИ, ВЫ ХОТИТЕ . Это не должно быть имя класса, но имя класса модели, о которой вы говорите, должно быть явно указано в отношении. Просто базовый пример без проверки ошибок или подробных отношений db, таких как привязка таблицы или имени столбца внешнего ключа:

 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; } } 

Для этой функции, если у вас есть объект person и хотите, чтобы объект, определенный отношениями «компания», использовал:

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

В настоящее время я использую ниже решение. Это фактическое решение, а не $has_one[1] hack, о котором я упоминал в вопросе. Если в phpactiverecord есть метод, я буду чувствовать себя очень глупо, разоблачающе себя. Но, пожалуйста, докажите мне глупость, поэтому мне не нужно использовать это решение: D

Я глуп. Ниже функциональность реализуется вызовом create_associationname, на что отвечает @Bogdan_D


Добавлены две функции. Вероятно, вы должны добавить их в класс \ActiveRecord\Model . В моем случае есть класс между нашими классами и этой моделью, которая содержит дополнительные функции, подобные этому, поэтому я разместил его там.

Это две функции:

  • public function findClassByAssociation($associationName)
    • Вызывается с именем ассоциации, которую вы ищете.
    • Проверяет три статических vars ( has_many , belongs_to и has_one ) для ассоциации
    • вызывает findClassFromArray если найдена ассоциация.
    • от лица / компании: $person->findClassByAssociation('company');
  • private function findClassFromArray($associationName,$associationArray)
    • Просто рабочая функция, которая пытается сопоставить имя.

Источник:

 /** * 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; } , /** * 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; } , /** * 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; } , /** * 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; }