Yii通过SOAP为它的关系()服务AR

时间:2011-12-01 19:40:07

标签: activerecord soap yii foreign-key-relationship

我的问题:

通过@soap公开具有关系()的AR的最明智的方法是什么?是否可以公开相关的AR而无需手动将其分配给公共@soap成员?是否可以以某种方式将relations()中定义的关系名称与@soap变量链接起来?

这是我正在做的事情的背景。我实际上成功地用它的相关AR记录共享了AR记录,但我觉得这很麻烦,想问一下是否有人知道更优雅的方式。

背景

我通过添加使用@soap注释的公共变量

成功地通过soap公开了AR记录

在物业模型中:

 /** @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记录作为请求的一部分(想要添加状态细节,所以首先我在States模型的Property模型中添加了关系表达式:

 /**
     * @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;

现在我将一个@soap公共变量添加到Property模型中以保存相关的AR对象:

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

这意味着我想通过SOAP发送State类型的对象。

在提供数据之前,最后一件事是将STATE的相关AR记录分配给公共@soap变量$ _STATE:

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

这有点乱,因为:

  1. 需要一直执行此$ model-> _STATE分配
  2. 将相关AR称为STATE和公共@soap变量$ _STATE保持基本相同的信息是多余的
  3. 有什么想法吗?

    谢谢!

2 个答案:

答案 0 :(得分:0)

如何为这些重复步骤创建行为?

如果要覆盖__get魔术方法来自动提供状态呢?

答案 1 :(得分:0)

我也觉得这很刺激。

CWsdlGenerator使用反射并专门查找已定义的公共属性,因此它不会找到像关系这样的魔术属性。你必须将它们声明为公开。

但是CActiveRecord使用魔术__get()函数来加载关系。并且没有为现有公共属性调用__get(),因此如果执行声明它们,那么它们将永远不会被加载。你总是必须使用$ model-> STATE = $ model-> getRelated('STATE')显式加载它们。

我想到了继承CWsdlGenerator并重写processType()以检查一些新的doc注释,以允许你显式声明魔术属性;但processType()是私有的,因此无法覆盖。

CWebServiceAction可以是子类,您可以在其中覆盖createWebService()以将CWebService-> generatorConfig设置为使用不同的类而不是CWsdlGenerator。我创建了一个名为CWsdlGeneratorMagic的副本,并添加了10行来解析doc注释。我不喜欢它作为解决方案,但它可以工作。

在我的模型的类doc注释中(这些声明了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()为$ 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的generatorConfig,这样就不需要CWebServiceActionMagic了,但是我无法让它工作。

@magic声明基本上回应了@property声明,但仅限于我希望在WSDL中公开的声明。 (应该把它称为@soapmagic或者其他东西)。