Yii служить AR с его отношениями () через SOAP - PullRequest
1 голос
/ 01 декабря 2011

МОЙ ВОПРОС:

Какой самый умный способ раскрыть через @soap AR, который имеет отношения ()?Можно ли выставить связанный AR, не назначая его вручную общедоступному члену @soap?Можно ли каким-либо образом связать имя отношения, определенное в relations (), с переменной @soap?

Вот небольшой пример того, что я делал.Я действительно успешно поделился записью AR с соответствующими записями AR, но я думаю, что это грязно, и хочу спросить, знает ли кто-нибудь более элегантный способ.

ФОН:

Я успешно открыл AR запись через мыло, добавив открытые переменные, помеченные @soap:

В модели свойств:

 /** @soap @var integer */ public $id;
 /** @soap @var string */  public $street;
 /** @soap @var string */  public $city;
 /** @soap @var integer */ public $fk_state;
 /** @soap @var string */  public $property_title;

Это работает нормально!

Следующее, что я хочу, это отправить связанную запись AR как часть запроса (хочу добавить сведения о состоянии, поэтому сначала я добавилвыражение отношения в модели Property для модели States:

 /**
     * @return array relational rules.
     */
    public function relations()
    {
        return array('STATE' => array(self::BELONGS_TO, 'State', 'fk_state'), );
    }

... также добавьте переменные @soap в модель State:

/** @soap @var integer */ public $id;
/** @soap @var string */  public $title;
/** @soap @var integer */ public $code;

Теперь я добавлю public @soap publicпеременная модели Property для хранения связанного объекта AR:

 /** @soap @var State */   public  $_STATE;

это означает, что я хочу отправить объект типа State через SOAP.

Последнее, перед обработкой данныхсостоит в том, чтобы назначить соответствующую AR-запись STATE для общедоступной переменной @soap $ _STATE:

$model->_STATE = State::model()->STATE; // assign related AR object to to the public @soap variable

Это немного грязно, потому что:

  1. потребностьчтобы делать это $ model -> _ STATE присваивание все время
  2. избыточно иметь both связанный AR, называемый STATE, и общедоступная переменная @soap $ _STATE, которая содержит в основном ту же информацию

Есть идеи?

Спасибо!

Ответы [ 2 ]

0 голосов
/ 30 октября 2012

Я тоже нахожу это раздражающим.

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

Но CActiveRecord использует магическую функцию __get () для загрузки отношений. И __get () не вызывается для существующего открытого свойства, поэтому, если вы объявите их do , они никогда не загрузятся. Вы всегда должны явно загружать их, используя $ model-> STATE = $ model-> getRelated ('STATE').

Я думал о создании подкласса CWsdlGenerator и переопределении processType (), чтобы проверить наличие нового комментария к документу, чтобы позволить вам явно объявить магические свойства; но processType () является закрытым, поэтому его нельзя переопределить.

CWebServiceAction можно разделить на подклассы, и там вы можете переопределить createWebService (), чтобы установить для CWebService-> generatorConfig использование другого класса вместо CWsdlGenerator. Я создал копию с именем CWsdlGeneratorMagic и добавил 10 строк для анализа комментария к документу. Мне не нравится это решение, но оно может сработать.

В комментариях к документации класса моей модели (они объявляют волшебные свойства отношений 'HAS_MANY' pictures 'и' sources '):

/**
 * The following is for the SOAP WSDL generator replacement CWsdlGeneratorMagic
 * @magic Picture[] $pictures
 * @magic Source[] $sources
 */

В моем классе контроллеров:

/**
 * Make this a webservice
 */
public function actions() {
  return array(
    'api'=>array(
        'class'=>'CWebServiceActionMagic',
    ),
  );
}

в CWebServiceActionMagic.php:

protected function createWebService($provider,$wsdlUrl,$serviceUrl)
{
    $a = new CWebService($provider,$wsdlUrl,$serviceUrl);
    $a->generatorConfig = 'CWsdlGeneratorMagic';
    return $a;
}

в CWsdlGeneratorMagic (в конце processType (), сразу после закрывающей скобки foreach ($ class-> getProperties () as $ property)):

// Handle magic properties
$comment = $class->getDocComment();
$matches = array();
if (preg_match_all('/@magic\s+([\w\.]+(\[\s*\])?)\s*?(.*)$/mi', $comment, $matches, PREG_SET_ORDER)) {
    foreach ($matches as $match) {
        $name = trim($match[3]);
        $name = ltrim($name, '$');
        $this->_types[$type][$name]=array($this->processType($match[1]),trim($match[3]));  // name => type, doc
    }
}
// end handling of magic properties
return 'tns:'.$type;

Я думаю, что можно установитьогенератор CWebService в файле конфигурации приложения, чтобы вам не понадобился CWebServiceActionMagic, но я не смог заставить его работать.

Объявления @magic в основном повторяют объявления @property, но только для тех, которые я хочу раскрыть в WSDL. (Вероятно, следует назвать это @soapmagic или что-то вроде этого).

0 голосов
/ 02 декабря 2011

Как насчет создания Поведения для этих повторяющихся шагов?

А как насчет перезаписи магического метода __get для автоматического обслуживания состояния?

...