Activerecord-association: создать новый объект (найти класс) - PullRequest
2 голосов
/ 14 февраля 2012

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

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

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

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

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

Обходной путь - получить его напрямую из массива static $has_one:

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

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


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


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

Ответы [ 3 ]

4 голосов
/ 04 июля 2012

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

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

0 голосов
/ 16 февраля 2012

В PHPActiveRecord у вас есть доступ к массиву отношений.У отношения должно быть имя, которое вам нужно знать, как называется отношение / ассоциация, которую вы хотите .Это не обязательно должно быть имя класса, но имя класса модели, к которой вы относитесь, должно быть явно указано в отношении.Просто базовый пример без проверки ошибок или грубых подробностей базы данных, таких как связывание таблицы или имени столбца внешнего ключа:

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();
0 голосов
/ 15 февраля 2012

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

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


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

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

  • public function findClassByAssociation($associationName)
    • Вызывается с названием искомой ассоциации.
    • Проверяет три статических переменной (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;
}
...