Take the 2-minute tour ×
Craft CMS Stack Exchange is a question and answer site for administrators, end users, developers and designers for Craft CMS. It's 100% free, no registration required.

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.

share|improve this question

1 Answer 1

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.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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