4

I'm creating a HTTP RESTful API plugin for Craft. In this case, I'm trying to return Elements (based on criteria), and include their content (via $element->getContent()).

By default, if I return just the Elements collection returned by craft()->elements->getCriteria($type)->find(), the content is not included.

I'm also running each Element through a Transformer which uses ModelHelper::packageAttributeValue($value), and converts attributes to their proper PHP type using attribute configs.

I'm not sure the best way to go about including content in my responses dynamically. Suggestions?

Edit:

I've just found out that $element->getContent() returns fields that aren't even associated with that particular element. Weird. Anybody know anything about this? I've instead resorted to using:

$fields = array_map(function (FieldLayoutFieldModel $model) {
    return $model->getField();
}, $element->getFieldLayout()->getFields());

Not sure what's best here.

4

I've determined what I think to be the best way to dynamically add Element's field content values to my responses.

First off, the reason why field content values are being returned using $element->getContent() regardless of the Element relationship with the fields, is because the content table has field values as columns themselves. So when a Content model is populated, all fields are included. If I setup a field for an Entry, it will appear as a field for a User when using this method.

My solution:

$entries = array();

$results = craft()->elements->getCriteria(ElementType::Entry)->find();

foreach ($results as $model) {
    $entry = array();

    $attributes = $model->getAttributes();

    foreach ($attributes as $name => $value) {
        $entry[$name] = $value; // Do some transformation here (type casting, etc.)
    }

    $content = $model->getContent(); // No extra DB queries here - Model is already populated with content values

    $fields = array_map(function (FieldLayoutFieldModel $model) {
        return $model->getField();
    }, $model->getFieldLayout()->getFields());

    foreach ($fields as $field) {
        $entry[$field->handle] = $content->{$field->handle};
    }

    $entries[] = $entry;
}

return $this->returnJson(array(
    'entries' => $entries,
));

In my particular development, I've separated a lot of the above logic into services, which I'm using like Transformers.

This helps me deliver field content values through my API. I spent hours pouring through source code, and I'm pretty confident this is the best solution based on efficiency, best practices, and similarity with logic concepts found throughout built-in services and models. Let me know what you guys think.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.