Access $field->attrs() from a /Cms/field

Hello,

I’m trying to write a fieldmethods extension (which takes a /Cms/Field) and I’d like to access the field’s attributes (or props) from the user blueprint configuration. Is this possible in Kirby ?

Nb: I found a way to convert a Cms/Field to a Form/Field but I’m afraid that it creates a (non noticeable) bottleneck and the code will probably break at some Kirby update.

Here’s a simple example to illustrate my question:

Kirby::plugin('me/tagmethods', [
  'fieldMethods' => [
    // To Tags function : how to access `Kirby/Form/Field::$field->attrs()` from a `Kirby/Cms/Field` ?
    'toTags' => function(\Kirby\Cms\Field $cmsField){
      // I'd like to check the field type to ensure it's a tags field.
      if($cmsField->attrs['type']!=='tags') // <-- doesn't work !
        throw new Kirby\Exception\InvalidArgumentException('toTags only works on tags fields !');

      // I'd like to automatically use the separator from the user blueprint
      $separator = $cmsField->attrs['separator']??','; // <-- doesn't work !
      return $this->split($separator);
    }
  ]
]);

By the way, I came to figure that, in templates, everything is Cms namespace which seems a simple way of parsing the content file “without the heavy panel machinery”, is that right ?
Similarly, I thought that a field extension with 'methods' => [...] would provide them to the templates (like $page->myField()->myMethod()) but I needed to register it separately with fieldmethods.

Is this Form / Cms difference documented somewhere ?

First of all, your method cannot possibly work because it must be registered inside the fieldMethods extension, maybe you just forgot to copy it here?

The methods available on the Kirby\Cms\Field you can find here: Field | Kirby CMS, so it doesn’t have an attribute method.

On the frontend, you therefore cannot access anything in the blueprint, unless you go via the $page->blueprint() method. This can be useful in certain scenarios, but would be unnecessary overhead if you had to read the blueprints for everything.

As I already mentioned above, the Kirby\Cms\Field class is documented here: Field | Kirby CMS

The Kirby\Panel\Field: Field | Kirby CMS
The Kirby\Form\Field: Field | Kirby CMS

Hey Sonja, Thanks for your quick response.

Indeed, I forgot a little part in my code, it’s corrected now.

I’ll digg the $page->blueprint() way, definitely more robust then my previous method.

// returns the computed separator attribute/prop from the cms field
$cmsField->parent()->blueprint()->field($cmsField->key())['separator']; // A
// Edit : In my test setup, A is 500 to 800 times faster then B.
// Note: A only loads the sanitized blueprint, it doesn't apply dynamic field props, attrs and computed from the field specialisation as in B.
cmsField2FormField($cmsField)->separator(); // B

As for the docs question, I found these pages already, but I’m more looking for something that explains the way Kirby handles content with fields (or not?), internally, architecturally; it feels like I missed something fondamental.

So when you create a custom field with an associated fieldMethods (ex: extendedtagsfield and toTags) to retrieve it’s contents, you have to provide an as lightweight as possible method while the rest (most?) of the field mechanics are reserved for panel users, with heavier field logics, right ?


If somebody is curious about my cmsField2FormField function, here it is :

function cmsField2FormField(\Kirby\Cms\Field $field): ?\Kirby\Form\Field {
    $blueprintData = \Kirby\Cms\Blueprint::fieldProps($field->model()->blueprint()->field({$field->key())}());
    $blueprintData['model'] = $field->model();
    return \Kirby\Form\Field::factory($blueprintData['type'], $blueprintData);
}

Don’t quite know what you mean here. But a fieldMethod (custom or not) is not per se tied to a particular field, even though some field method only make sense with certain field types.

But basically, when you return a piece of content from the content object, Kirby returns this stuff as a field object. The purpose of field method is then to render this field content in some way, thereby converting, manipulating, or validating the content.

In the front end you don’t have a form with content, so the Form\Field with its error handling field props, types etc. is not useful there.

Ok, so there’s a clear distinction between manipulating content in the panel and in the frontend.
Some panel field methods could have been useful for sanitizing my field data on retrieval, but I’ll rewrite them using raw data for the fieldMethods, keeping performance in mind.

If I trust the panel users, I could just store the sanitized data and retrieve it. But I like to ensure correct retrieval for my custom field, even then the content file was edited (as the panel isn’t even mandatory in Kirby). So I’m a bit surprised that there’s no easier (or automatic) way to apply the panel sanitization methods from the frontend.

Anyways, no worries, just thinkering, I got my solution, thanks ! :slight_smile: