1

I have a custom field that will be saving data to its own table. So if my field is in a Matrix field, I need to save the Matrix Field ID and Matrix Block ID to my table so I know what the data belongs to. I’m having a hard time figuring out how to get that data in my fieldtype. I’m using the onAfterElementSave method. I’ve been looking for attributes and types and whatnot on $this, $this->element->getType(), $this->element->getType()->getAttributes() and so far I’m just not having any luck finding this information. Can anyone point me in the right direction here?

4

The BaseFieldType class (which all FieldTypes extend) has a contentPostLocation property, which will give you the "path" to the field inside the entry model. The value is returned as a string, e.g. fields.myCustomFieldTypeHandle.

If your field is inside a Matrix block, the contentPostLocation path will include the Matrix field's handle – as well as the block ID – e.g.

fields.matrixFieldHandle.12.fields.myCustomFieldTypeHandle

Based on this, by exploding the contentPostLocation string and testing its length, you can figure out if the field is "standalone" or embedded in a Matrix block:

$contentPath = explode('.', $this->contentPostLocation);
if (count($contentPath) > 2) {
    // Not standalone (i.e. probably inside a Matrix block)
}

The Matrix' field's handle will be the second segment in the path. You can use the FieldsService to pull the actual field, in order to get its ID. It's probably also a good idea to confirm that it is indeed a Matrix field, which is easily done by checking its fieldtype's classHandle property:

$matrixFieldHandle = $path[1];
$matrixField = craft()->fields->getFieldByHandle($matrixFieldHandle);
if ($matrixField && $matrixField->fieldType->classHandle === 'Matrix')
{
    // Yup, it's a Matrix field!
    $matrixFieldId = $matrixField->id;
}

Finally, the block ID would be the next segment in the contentPostLocation path, i.e. $matrixBlockId = (int) $contentPath[2];

Putting it all together, something like this should do the trick:

public function onAfterElementSave()
{
    $contentPath = explode('.', $this->contentPostLocation);
    if (count($contentPath) > 2)
    {
        $matrixFieldHandle = $contentPath[1];
        $matrixField = craft()->fields->getFieldByHandle($matrixFieldHandle);
        if ($matrixField && $matrixField->fieldType->classHandle === 'Matrix')
        {
            $matrixFieldId = $matrixField->id;
            $matrixBlockId = (int) $contentPath[2];
        }
    }
}
1
  • This got me pointed in the right direction. It still feels like I’m jumping through a lot of hoops. I modified had to get a little bit more info than what was available here though. I’ll post another answer as well so I can do a code demonstration.
    – TJ Draper
    Sep 24 '15 at 2:26
2

mmikkel got me very close and pointed in the right direction. Here is what I ultimately did to get the info I needed. This seems like jumping through hoops but it does work.

$contentType = $this->element->elementType;
$matrixBlockId = null;
$matrixFieldId = null;

if ($contentType === 'MatrixBlock') {
    $contentPath = explode('.', $this->contentPostLocation);

    $matrixField = craft()->fields->getFieldByHandle($contentPath[1]);

    $matrixBlockId = $contentPath[2];

    $matrixFieldHandle = $contentPath[4];

    $matrixService = new MatrixService();

    $matrixBlock = $matrixService->getBlockById($matrixBlockId);

    foreach ($matrixBlock->getFieldLayout()->getFields() as $thisField) {
        $thisFieldId = $thisField->getAttribute('fieldId');

        $field = craft()->fields->getFieldById($thisFieldId);

        if ($field->getAttribute('handle') === $matrixFieldHandle) {
            $matrixFieldId = $thisFieldId;

            break;
        }
    }
}
2

I have done something similar to this where I needed a custom FieldType that saves its data to its own table and works inside (and outside) a Matrix Field. The other answers with contentPostLocation might work but seem complicated to get the ids and/or data you need.

When your FieldType is used inside a Matrix Field a different ElementType will be returned. You can check this in $this->element->elementType and your check for MatrixBlock works nicely.

Now when inside the matrix .. ;) $this->element->id will be the id of the MatrixBlockElement, so your BlockId. $this->element->fieldId will be your fieldId (the matrix's field id)

And if you need the actual element where this block belongs to (as I did) you can use $this->element->ownerId to get the owner element (parent element?). You can look at MatrixBlockElementType for more clues.

Saving your data in onAfterElementSave() will be the same, e.g. the following will get you the data for your Block and also when its not used as a Block (note this works because its getting the data for the Element so it doesn't care about any differences)

$fieldHandle = $this->model->handle; $content = $this->element->getContent(); $data = $content->getAttribute($fieldHandle);

1
  • I think this answer should be accepted over mine – this is obviously a better approach :) Nov 4 '15 at 21:37

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.