acf-composer
acf-composer copied to clipboard
Feature Request for ACF with() method to allow for returning of object in place of array
In Sage 9, in the Controller Files, the protected $acf
array returns each instance of a field into an object. I really liked working with that, and was wondering if there was a way, either as an option, or just natively, to do the same.
I am working with your current package, but with Sage 10, made an AcfNestedFields.php
Class, and ported over most of the functionality. I was wondering if you would maybe consider using this as inspiration to implement into this great package.
Acf Block Class
class TextBlock extends Block
{
//... previous block variables and methods
/**
* Field Names used for this block
* @var array|string[]
*/
public array $fieldNames = [
'title',
'content',
'items',
'cta',
'image',
'cta_title',
];
/**
* Data to be passed to the block before rendering.
*
* @return array
*/
public function with()
:array
{
return (new AcfNestedFields($this->fieldNames))
->getData();
}
//.. other block methods
}
AcfNestedFields.php
<?php
namespace App\SageThemeModule;
use Illuminate\Support\Str;
use function collect;
class AcfNestedFields
{
/**
* @param array $data The field names to grab get_field data for
*/
public function __construct(
protected array $data = [],
private bool $returnArrayFormat = false
) {
$this->setReturnFilter();
$this->setData($this->data);
}
/**
* Set Return Filter
*
* Return filter sober/controller/acf-array
*/
private function setReturnFilter()
:void
{
// This filter might have to be recreated, but I wasn't able to
// fully find the add_filter for this in Sage 9's vendor files
$this->returnArrayFormat =
(has_filter('sage/classes/acf/array')
? apply_filters('sage/classes/acf/array', $this->returnArrayFormat)
: false);
}
/**
* Iterates over array and adds a new snake cased key, with orignial value, for each kebab cased key
*
* Return void
*/
private function recursiveSnakeCase(&$data)
:void
{
if (!is_array($data)) {
return;
}
collect($data)
->each(fn($val, $key) => is_array($val)
? $this->recursiveSnakeCase($val)
: $data[Str::kebab($key)] = $val);
}
/**
* Convert the data for the fields to an object if returnArrayFormat is false
*
* @return void
*/
public function setDataReturnFormat()
:void
{
if ($this->returnArrayFormat) {
return;
}
if ($this->data) {
collect($this->data)
->each(fn($item, $key) => $this->data[$key] = json_decode(json_encode($item)));
}
}
/**
* Set Data
*
* Set data from passed in field keys
*/
public function setData($acf)
:void
{
if (is_string($acf)) {
$this->data = [$acf => get_field($acf)];
}
if (is_array($acf)) {
collect($acf)
->each(fn($item) => $this->data[$item] = get_field($item));
}
$this->recursiveSnakeCase($this->data);
// Convert the data to an object
$this->setDataReturnFormat();
}
/**
* Get Data
*
* Return the data
*
* @return array
*/
public function getData()
:array
{
return $this->data;
}
}
Have you taken a look at https://github.com/roots/acorn/blob/main/src/Roots/Acorn/View/Composers/Concerns/AcfFields.php ?
Have you taken a look at https://github.com/roots/acorn/blob/main/src/Roots/Acorn/View/Composers/Concerns/AcfFields.php ?
Yeah, I see it now, it's a lot cleaner, something I could adapt to instead of what I migrated above. I don't like the idea of get_fields() in an acf block, when I know what those field names are.
So I took a look at the above Class again, and played around with a bit more, and ended up with this. However, I will admit I am not super familiar with Laravel Class and methods, so I would love to know if this is the right route? I had to actually call to the toJson()
method, and decode it to get the results i was looking for.
public function getFields()
:array
{
return collect($this->data)
->mapWithKeys(fn($value) => [$value => get_field($value)])
->mapWithKeys(function ($value, $key) {
$value = is_array($value)
? json_decode((new Fluent($value))->toJson())
: $value;
$method = Str::camel($key);
return [$key => method_exists($this, $method) ? $this->{$method}($value) : $value];
})
->all();
}
Sorry for the late reply. That looks good. You could maybe do (object) $value
instead of the json_decode()
but I don't think that will handle objects recursively.
Going to close this for now as it's not entirely in scope for ACF Composer at the moment – although what you have does look useful. 😄