Updating to Kirby 4 from 3

I am trying to upgrade Kirby 3 to 4 but I got below errors which i am not sure how to fix.
I have been using objects that extend StructureObject in Kirby 3 like:
class TestStructureObject extends StructureObject

And then it was passed down and Model was expected in those function, but now I Am getting:
Kirby\Content\Field::__construct(): Argument #1 ($parent) must be of type ?Kirby\Cms\ModelWithContent, TestStructureObject given

And in the past StructureObject extended Model class, but it does not do that anymore, is there another class i should use right now? Is there an easy fix to that?

How should i use it?

We need to better understand where your TestStructureObject seems to get passed to Content\Field::__construct() as $parent. Do you have any insights on this yourself?

Hard to tell right now if it’s happening somewhere in the core code itself or if this is from custom code, e.g. in your TestStructureObject class itself.

It looks that object has page setting that is being read.

$TestStructureObject->formattedCompactPrice()->html()
Then it creates field in it at the end:
return new Field($this, ‘formattedCompactPrice’, $value);

$this is $TestStructureObjec t in this case.

This return creates that error.

I think you might be fine by changing it to

return new Field(null, ‘formattedCompactPrice’, $value);

The parent is mainly needed for $field->exists() and there for checking if it actually exists in the content. This is why we had to fix the type hinting and require ModelWithContent.

Assuming that your objects don’t need to make use of this, passing null should be fine.

I am trying to test that but I am getting below error now almost on all pages.

Typed property Kirby\Cms\ModelWithContent::$content must not be accessed before initialization

Comes from: ’ /var/www/html/kirby/src/Cms/ModelWithContent.php’ line 149

Which in turn is called from: /var/www/html/website/site/plugins/redis/src/SupplementalModelContent.php
line 37

// get page's content value
        $field = $this->content()->get($method);

Which in turns is executed in custom Page that extends CMS in public function __construct(array $props)

$this->setOptionalProperties($props, ['name1', 'name2']);

Any idea how to approach that?

Plus Kirby 3 used ContentTranslation with ```
setRequiredProperties


As our plugins in their constructor use:

$this->setRequiredProperties($props, [‘name’]);

This will be a hard one. setOptionalProperties and setOptionalProperties don’t exist anymore as we are shifting away from the troublesome Kirby\Toolkit\Properties trait. They were a lot more for internal usage and I am not sure why/what for/how you used them in Kirby 3. Is the redis plugin yours?

Correct, redis one.

I think you will need to make a deep dive into your custom code and plugins as they seem to be deeply using undocumented Kirby 3 methods that have changed for Kirby 4. It’s hard to give support without the full picture but I am also afraid looking at the full picture exceeds what we can offer as support here.

Man, never that easy huh? :), will try and see what we can do about it. At first glance it does not do much and should be easy to replace if needed.

protected function setRequiredProperties(array $props, array $required)
	{
		foreach ($required as $propertyName) {
			if (isset($props[$propertyName]) !== true) {
				throw new Exception(sprintf('The property "%s" is required', $propertyName));
			}

			$this->{'set' . $propertyName}($props[$propertyName]);
		}
	}

Is there anything else in Kirby 4 that does the same thing as this function?

Most of the setter methods are gone that are called here in the last line. So you really need to approach this more from the end of what your Kirby 3 code was trying to do calling these methods.

If we have our own classes extending StructureObject in Kirby 3, how should we change them, do we extend from some other class in Kirby 4 now?
Since setters are different the results are different for those as well after upgrade causing errors.

class CustomScheduleStructureObject extends StructureObject

We used extensively this setter from structureObject, is there a way to make our classes work similar under Kirby 4?

public function __set(string $id, $props): void
	{
		if ($props instanceof StructureObject) {
			$object = $props;
		} else {
			if (is_array($props) === false) {
				throw new InvalidArgumentException('Invalid structure data');
			}

			$object = new StructureObject([
				'content'    => $props,
				'id'         => $props['id'] ?? $id,
				'parent'     => $this->parent,
				'structure'  => $this
			]);
		}

		parent::__set($object->id(), $object);
	}

Where does this method fail for you with Kirby 4?

So when you create an object and send array to __set in old solution the indexes of array were updated by $object->id() so if your $object->id() was string or whatever, your indexes became strings values of that id which later could be used to identify objects in array by that string but no more.

But now, array indexes never changes and stay numerical and are not updated by $object->id().
Old solution:

New solution goes to: