<p>With a highly complex hierarchical object with many layers of sub-objects, etc., I found that it was much easier in the end to just store the raw JSON in the database in a text-field, and decode it manually before passing it to the template to allow full access to the object hierarchy using <code>dot</code> or <code>array</code> syntax.</p>

<p>In the plugin's fieldtype class definition, define the column type as <code>String</code> with no text limit (using the additional <code>column</code> declaration):</p>

<pre><code>public function defineContentAttribute()
{
    return array(AttributeType::String, 'column' =&gt; ColumnType::Text);
}
</code></pre>

<p>In the fieldType template file the string can then be decoded as a json object manually to make it available to the template using <code>JsonHelper::decode()</code>:</p>

<pre><code>public function getInputHtml($name, $value)
{
    $jsonObj = JsonHelper::decode($value);
    return craft()-&gt;templates-&gt;render('myPlugin/fieldtypes/Myfield/input', array(
        'name'          =&gt; $name,
        'value'         =&gt; $value,
        'jsonObj'       =&gt; $jsonObj
    ));
}
</code></pre>

<p>And in the template, (assuming the json was properly formatted) the full json object can now be traversed using dot syntax:</p>

<pre><code>{# access first level attribute #}
&lt;p&gt;{{ jsonObj.id }}&lt;/p&gt;
{# access deeper object array level attribute #}
&lt;p&gt;{{ jsonObj.objArray.data[0].id }}&lt;/p&gt;
</code></pre>

<p>Note: In php, for some unexplained reason, <code>JsonHelper::decode($jsonStr)</code> doesn't seem to allow access to the attributes, so instead the php equivalent <code>php_decode($jsonStr)</code> can be used:</p>

<pre><code>$jsonObj = json_decode($entry-&gt;jsonStr);
$Id = $jsonObj-&gt;id;
</code></pre>

CC BY-SA 3.0
2014-10-13T02:35:09.997Z
2014-10-14T01:53:14.870Z
2014-10-14T01:53:14.870Z
Douglas McDonald
<p>You already mentioned the related answer in <a href="https://craftcms.stackexchange.com/questions/2565/custom-field-type-with-multiple-values/3048#3048">custom fieldtype with multiple values</a>, and it actually is perfect for your usecase.</p>

<p>It doesn't really matter how you transport the data over to Craft, because if the content is set to AttributeType::Mixed, then Craft will JSON encode/decode it when requested.</p>

<p>So, to save your data, send over an array, like so:</p>

<pre><code>$stripeCustomer = [
    "id" =&gt; "cus_4v68MrZu3za8XT",
    "object" =&gt; "customer",
    "etc" =&gt; "etcetcetc"
    ];

// Transport $stripeCustomer to Craft with Ajax
</code></pre>

<p>In the context of Javascript, you'd send over the serialized form data.</p>

CC BY-SA 3.0
2014-10-12T21:57:46.143Z
I guess what I was looking for is a way to send it over as a single object with object attributes, rather than having to define the object before I send it. It's a rather complicated object, with sub arrays of additional objects, etc. coming from a third party service. And some of the attributes are optional and will not always be defined, etc.
Douglas McDonald
CC BY-SA 3.0
2014-10-12T22:07:51.333Z
I changed the attribute type to `mixed` and am sending the field value as `value` and trying to reference it as `{{ value.id }}` or `{{ value['id'] }}` but obviously getting an error — `Impossible to access a key ("id") on a string variable ("Stripe_Customer JSON:...`
Douglas McDonald
CC BY-SA 3.0
2014-10-12T19:46:47.410Z
2014-10-12T20:34:30.280Z
2017-04-13T12:51:00.253Z
Fred Carlsen
<p>Completely untested, but a possibility would be to define your content attribute like so:</p>

<pre><code>return array(AttributeType::Mixed, 'model' =&gt; 'MyPluginContentModel');
</code></pre>

<p><code>MyPluginContentModel</code> would have every possible value that you would want to expose to your template ('id', 'obj', 'etc') defined as an attribute.</p>

<p>When Craft pulls the JSON from the database, it should decode it and populate your <a href="http://buildwithcraft.com/docs/plugins/models" rel="nofollow">model</a> with any matching attributes it finds.</p>

<p>That gets returned to your template and you can access it via <code>{{ value.id }}</code>.</p>

CC BY-SA 3.0
2014-10-12T23:41:45.757Z
Is this possible without an actual Model Class file with all the attributes pre-defined? Or are you suggesting I create a plugin Model with `value` as one of the attributes?
Douglas McDonald
CC BY-SA 3.0
2014-10-12T23:45:04.707Z
You'd need a model class file for this to work with all of the possible attributes you want to expose to the template defined. Updated the answer.
Brad Bell
CC BY-SA 3.0
2014-10-12T23:55:41.303Z
How would that work when one of the properties is another object (i.e. a list with its own properties and an array of `card` objects), would I have to also create models of each of those sub-objects, etc, etc? Ugh. That was exactly was I was trying to avoid.
Douglas McDonald
CC BY-SA 3.0
2014-10-12T23:56:30.930Z
Afraid so... the best I've got right now.
Brad Bell
CC BY-SA 3.0
2014-10-13T00:19:40.350Z
I'll keep working on it, see if I can come up with something easier. Thank you though!!! Much appreciated.
Douglas McDonald
CC BY-SA 3.0
2014-10-12T22:46:15.360Z
2014-10-12T23:44:28.533Z
2014-10-12T23:44:28.533Z
Brad Bell
<p>I would like to store a json object in a custom fieldtype, and be able to traverse the object's attributes using twig dot syntax in my template. I am currently storing the raw json object as a string, but I'm not sure what I need to do to be able to reference the stored string as an object.</p>

<p>Here is a shortened example of the raw json string that is being stored:</p>

<pre><code>"Stripe_Customer JSON: {
    "id": "cus_4v68MrZu3za8XT",
    "object": "customer",
    "cards": { "object": "list", "total_count": 0, "has_more": false, "url": "/v1/customers/cus_4v68MrZu3za8XT/cards", "data": [ ] },
    "subscriptions": { "object": "list", "total_count": 0, "has_more": false, "url": "/v1/customers/cus_4v68MrZu3za8XT/subscriptions", "data": [ ] },
    "etc": "etcetcetc"
}"
</code></pre>

<p>In my template I would like to be able to reference the objects properties in some way (i.e. <code>{{ fieldHandle.id }}</code>) for display only; and on the back-end within a service, I would like to set object properties before saving back to the DB (i.e <code>fieldhandle-&gt;id = value</code>).</p>

<p>I am not sure whether <code>defineContentAttribute</code> should return <code>AttributeType</code> <code>String</code> or <code>Mixed</code> in this case.</p>

<pre><code>public function defineContentAttribute()
{
    return AttributeType::String;
    //return AttributeType::Mixed;
}
</code></pre>

<p>And if it should be a string, how would one define the column type as "Text" vs the default <code>VARCHAR(255)</code>?</p>

<p>Update: I see that there is a similar question regarding <a href="https://craftcms.stackexchange.com/questions/2565/custom-field-type-with-multiple-values/3048#3048">custom fieldtype with multiple values</a>, however, in this case, the end-user will not be manipulating the data directly in any way — they will be filling in dummy fields that will be send to a third party service via javascript/ajax, a result object returned, and then forwarded (again via ajax) to a back-end service method to be processed and saved to the DB.</p>

<plugin-development><custom-fieldtype><json>
How to store json data in a custom fieldtype so that it's data can be referenced as attribute values?
# How to store json data in a custom fieldtype so that it's data can be referenced as attribute values?

(Asked by: username_0 on 2014-10-12)

I would like to store a json object in a custom fieldtype, and be able to traverse the object's attributes using twig dot syntax in my template. I am currently storing the raw json object as a string, but I'm not sure what I need to do to be able to reference the stored string as an object.
Here is a shortened example of the raw json string that is being stored:
"Stripe_Customer JSON: {
    "id": "cus_4v68MrZu3za8XT",
    "object": "customer",
    "cards": { "object": "list", "total_count": 0, "has_more": false, "url": "/v1/customers/cus_4v68MrZu3za8XT/cards", "data": [ ] },
    "subscriptions": { "object": "list", "total_count": 0, "has_more": false, "url": "/v1/customers/cus_4v68MrZu3za8XT/subscriptions", "data": [ ] },
    "etc": "etcetcetc"
}"

In my template I would like to be able to reference the objects properties in some way (i.e. {{ fieldHandle.id }}) for display only; and on the back-end within a service, I would like to set object properties before saving back to the DB (i.e fieldhandle->id = value).
I am not sure whether defineContentAttribute should return AttributeType String or Mixed in this case.
public function defineContentAttribute()
{
    return AttributeType::String;
    //return AttributeType::Mixed;
}

And if it should be a string, how would one define the column type as "Text" vs the default VARCHAR(255)?
Update: I see that there is a similar question regarding custom fieldtype with multiple values, however, in this case, the end-user will not be manipulating the data directly in any way — they will be filling in dummy fields that will be send to a third party service via javascript/ajax, a result object returned, and then forwarded (again via ajax) to a back-end service method to be processed and saved to the DB.

**Tags:** plugin-development, custom-fieldtype, json

---

## 3 answers

### Answer by username_0 on 2014-10-13. Score: 2 | Accepted answer

With a highly complex hierarchical object with many layers of sub-objects, etc., I found that it was much easier in the end to just store the raw JSON in the database in a text-field, and decode it manually before passing it to the template to allow full access to the object hierarchy using dot or array syntax.
In the plugin's fieldtype class definition, define the column type as String with no text limit (using the additional column declaration):
public function defineContentAttribute()
{
    return array(AttributeType::String, 'column' => ColumnType::Text);
}

In the fieldType template file the string can then be decoded as a json object manually to make it available to the template using JsonHelper::decode():
public function getInputHtml($name, $value)
{
    $jsonObj = JsonHelper::decode($value);
    return craft()->templates->render('myPlugin/fieldtypes/Myfield/input', array(
        'name'          => $name,
        'value'         => $value,
        'jsonObj'       => $jsonObj
    ));
}

And in the template, (assuming the json was properly formatted) the full json object can now be traversed using dot syntax:
{# access first level attribute #}
{{ jsonObj.id }}
{# access deeper object array level attribute #}
{{ jsonObj.objArray.data[0].id }}

Note: In php, for some unexplained reason, JsonHelper::decode($jsonStr) doesn't seem to allow access to the attributes, so instead the php equivalent php_decode($jsonStr) can be used:
$jsonObj = json_decode($entry->jsonStr);
$Id = $jsonObj->id;


---

### Answer by username_1 on 2014-10-12. Score: 4

You already mentioned the related answer in custom fieldtype with multiple values, and it actually is perfect for your usecase.
It doesn't really matter how you transport the data over to Craft, because if the content is set to AttributeType::Mixed, then Craft will JSON encode/decode it when requested.
So, to save your data, send over an array, like so:
$stripeCustomer = [
    "id" => "cus_4v68MrZu3za8XT",
    "object" => "customer",
    "etc" => "etcetcetc"
    ];

// Transport $stripeCustomer to Craft with Ajax

In the context of Javascript, you'd send over the serialized form data.

> **Comments:**
> **username_0**: I guess what I was looking for is a way to send it over as a single object with object attributes, rather than having to define the object before I send it. It's a rather complicated object, with sub arrays of additional objects, etc. coming from a third party service. And some of the attributes are optional and will not always be defined, etc.  
> **username_0**: I changed the attribute type to `mixed` and am sending the field value as `value` and trying to reference it as `{{ value.id }}` or `{{ value['id'] }}` but obviously getting an error — `Impossible to access a key ("id") on a string variable ("Stripe_Customer JSON:...`  

---

### Answer by username_2 on 2014-10-12. Score: 3

Completely untested, but a possibility would be to define your content attribute like so:
return array(AttributeType::Mixed, 'model' => 'MyPluginContentModel');

MyPluginContentModel would have every possible value that you would want to expose to your template ('id', 'obj', 'etc') defined as an attribute.
When Craft pulls the JSON from the database, it should decode it and populate your model with any matching attributes it finds.
That gets returned to your template and you can access it via {{ value.id }}.

> **Comments:**
> **username_0**: Is this possible without an actual Model Class file with all the attributes pre-defined? Or are you suggesting I create a plugin Model with `value` as one of the attributes?  
> **username_2**: You'd need a model class file for this to work with all of the possible attributes you want to expose to the template defined. Updated the answer.  
> **username_0**: How would that work when one of the properties is another object (i.e. a list with its own properties and an array of `card` objects), would I have to also create models of each of those sub-objects, etc, etc? Ugh. That was exactly was I was trying to avoid.  
> **username_2**: Afraid so... the best I've got right now.  
> **username_0**: I'll keep working on it, see if I can come up with something easier. Thank you though!!! Much appreciated.  

---

