CakePHP:如何在自定义数据源中实现查找类型?

时间:2013-09-02 12:22:51

标签: php cakephp datasource

我正在尝试在Cake中创建costum数据源。这个costum数据源使用HasOffers api(如果你们中的任何人都熟悉它)。

此API的结构如下(取自HasOffers API文档):

$base = 'https://api.hasoffers.com/Api?';

$params = array(
    'Format' => 'json'
    ,'Target' => 'Offer'
    ,'Method' => 'findAll'
    ,'Service' => 'HasOffers'
    ,'Version' => 2
    ,'NetworkId' => 'my-network-id'
    ,'NetworkToken' => 'my-api-key'
    ,'filters' => array(
        'Offer.name' => array( 'LIKE' => 'My Offer' )
        ,'Offer.default_payout' => array( 'GREATER_THAN_OR_EQUAL_TO' => 10 )
    )
);

$url = $base . http_build_query( $params );

$result = file_get_contents( $url );

现在您可以看到很多参数用于确保您获得正确的数据并且您实际上已“允许”提取数据。

回到蛋糕:

现在我开始按照Cake Documentation datasource example

上的教程创建自己的数据源

目前,我只对阅读数据源感兴趣(即我不关心更新,创建或删除)。

为此目的,我做了以下事情:

<?php
App::uses('HttpSocket', 'Network/Http');

class HasOffersStat extends DataSource {

    /**
     * An optional description of your datasource
     */
    public $description = 'Has Offer stat';
    public $base = 'http://bloglicsystem.api.hasoffers.com/Api?';


    /**
     * Our default config options. These options will be customized in our
     * ``app/Config/database.php`` and will be merged in the ``__construct()``.
     */
    public $config = array(
        'Service' => 'HasOffers',
        'Version' => 2,
        'Format' => 'json',
        'NetworkID' => "my-network-id",
        'NetworkToken' => 'my-network-token',
        'APIDomain' => 'http://bloglicsystem.api.hasoffers.com/Api?'
    );

    /**
     * If we want to create() or update() we need to specify the fields
     * available. We use the same array keys as we do with CakeSchema, eg.
     * fixtures and schema migrations.
     */
    protected $_schema = array(
        'id' => array(
            'type' => 'integer',
            'null' => false,
            'key' => 'primary',
            'length' => 11,
        ),
        'name' => array(
            'type' => 'string',
            'null' => true,
            'length' => 255,
        ),
        'message' => array(
            'type' => 'text',
            'null' => true,
        ),
    );

    /**
     * Create our HttpSocket and handle any config tweaks.
     */
    public function __construct($config) {
        parent::__construct($config);
        $this->Http = new HttpSocket();
    }


    public function makeApiCall($params)
    {
        $params = array_merge($this->params, (array)$params);
        $api_response = json_decode(file_get_contents($this->base.$this->config. http_build_query($params)    ), true);
        return $api_response['response'];
    }

    /**
     * Since datasources normally connect to a database there are a few things
     * we must change to get them to work without a database.
     */

    /**
     * listSources() is for caching. You'll likely want to implement caching in
     * your own way with a custom datasource. So just ``return null``.
     */
    public function listSources($data = null) {
        return null;
    }

    /**
     * describe() tells the model your schema for ``Model::save()``.
     *
     * You may want a different schema for each model but still use a single
     * datasource. If this is your case then set a ``schema`` property on your
     * models and simply return ``$model->schema`` here instead.
     */
    public function describe($model) {
        return $this->_schema;
    }

    /**
     * calculate() is for determining how we will count the records and is
     * required to get ``update()`` and ``delete()`` to work.
     *
     * We don't count the records here but return a string to be passed to
     * ``read()`` which will do the actual counting. The easiest way is to just
     * return the string 'COUNT' and check for it in ``read()`` where
     * ``$data['fields'] === 'COUNT'``.
     */
    public function calculate(Model $model, $func, $params = array()) {
        return 'COUNT';
    }

    /**
     * Implement the R in CRUD. Calls to ``Model::find()`` arrive here.
     */
    public function read(Model $model, $queryData = array(), $recursive = null) {
        /**
         * Now we get, decode and return the remote data.
         */
        $params = array(
            'Format' => 'json',
            'Target' => 'Report'
        );

        $res = $this->makeApiCall($params);
        return array($model->alias => $res);
    }
  }

然后在我的app / config / database.php中添加了以下行:

    public $HasOfferStat = array(
    'datasource' => 'HasOffersStat',
    'NetworkID' => "my-network-id",
    'NetworkToken' => 'my-network-key',
    'APIDomain' => 'http://bloglicsystem.api.hasoffers.com/Api?'
);

现在很有趣这实际上有效!我的模型和数据源之间的链接正在运行,但我需要一些帮助!

使用蛋糕魔法我应该可以从我的控制器执行以下操作:

$this->MyModel->find('all');

但我不太明白这会怎么样?我需要在我的数据源中创建什么才能使魔术蛋糕方法有效?

1 个答案:

答案 0 :(得分:2)

这取决于您是否需要关注这些“神奇”的查找方法,模型中会出现“神奇”(请参阅​​Model::find()Model::buildQuery()Model::_readDataSource()和{{1方法),根据查找类型生成适当的查询。

数据源在Model::_find*()方法中接收这些查询,并且必须评估并正确使用它们,就像在the linked example中一样。

所以这一切都取决于您的具体需求,如果您需要根据查找类型执行某些特殊操作,那么您始终可以在read方法中检查Model::$findQueryType并采取相应的行动。

另见CakePHP Datasources Plugin,它适用于Cake 1.3,但是你应该明白这一点。