mhsdesign / PackageFactory.ComponentFactory

GNU General Public License v3.0
0 stars 0 forks source link

DISCUSSIONS #1

Open mhsdesign opened 1 year ago

mhsdesign commented 1 year ago

Which arguments should be available for the component factory

Node is the most obvious.

return #[Component('Neos.Demo:Content.Headline')] function(Node $node): string
{
    return $node->getProperty('title');
};

but it might make sense to add further ones like in the Component View

for contents:

        Node $contentNode,
        Node $documentNode,
        Node $site,
        ContentSubgraphInterface $subgraph,
        bool $inBackend,

for pages:

        Node $documentNode,
        Node $site,
        ContentSubgraphInterface $subgraph,
        bool $inBackend,
        ActionRequest $request

Currently im keeping the Controllercontext somewere global and dont pass it along everywhere. This is done similar to https://github.com/nezaniel/Nezaniel.ComponentView/blob/3cfb0f304a787dfb77cbab44e8f912ac79d0d604/Classes/Domain/UriService.php#L53 -> eventually we want to get rid of the controller context, but even then one might ask if i do want to pass the current actionRequest down to EVERY method. (Id like the tunnel through space a little better -> at least syntactically)

The global Controllercontext could be implemented and consumed with similar syntax for Reacts context.

caching

Also i was wondering how we would annotate caching and go cached by default (fusion) or uncached by default (ComponentView)

Maybe it would also be fun to have a useMemo similar to react

$title = useMemo(
  fn () => $node->getProperty('title');
  [$node]
)

but it think this is most definitely a schnappsidee and not even helpful, as we want to cache whole node content components.

caching could be annotated via annotations

return #[Component('Neos.Demo:Content.Headline')]  #[Cache(entryIdentifier: ..., tags: ...)] function(Node $node): string
{
    return $node->getProperty('title');
};

Helper functions vs static methods?

we will need a lot of helpers, basically what the fusion objects were doing and is neos specific. Native things like join will obviously replace Neos.Fusion:Join without further replacement.

Following prototypes are critical

...

in my super early draft, i decided for functions, as they are fun to look at - but they are not fun to implement.

$content = editable(...);

vs

$content = Neos::editable(...);
mhsdesign commented 1 year ago

Also i went currently with anonymous functions, but anonymous classes might be even better (they do not support dependency injection directly, but i could extend a class with DI.

<?php

return new class('Neos.Demo:Content.Headline') extends NeosComponentFactory
{
   public function fromNode(Node $node): string
   {
      return $node->getProperty("foo");
   }
}

for dependency injection of any helpers, one could utilize inject*

or with DI

/** @var $container ContainerInterface */
return new class (
    $container->get(SomeHelper::class)
) {
    public function __construct(
        private SomeHelper $someHelper
    ) {
    }
};
return new class {
     #[Flow\Inject]
     public SomeHelper $someHelper; // note must be public, or could also be protected if we like to use reflection. (see php DI)
};

BDD -> Boilerplate driven design

return new class {
     private SomeHelper $someHelper

     public function injectSomeHelper(SomeHelper $someHelper): void
     {
          $this-> someHelper = $someHelper;
     }

};

of back to (not autloaded classes)

<?php

namespace Any\Thing; // _should_ align at least to the package - but completely optional

// the class name can be any non conflicting name - must not be duplicated in the same namespace in codebase...
#[Component('Neos.Demo:Content.Headline')]
readonly class HeadlineFactory implements ComponentFactoryInterface
{
   // via reflection like CompileTimeObjectManager, we can map the arguments
   public function __construct(
      private SomeHelper $someHelper
   ) {
   }
}

or use real flow classes that would work with flows di. But this requires a proper psr4 setup and correct namespacing and file names ...

mhsdesign commented 1 year ago

For out of band reload we need rendering entry points for each component, and how can we fix https://github.com/neos/neos-ui/pull/2892?

Also fusions rendering entry points are more specific, as one could have an element two times displayed on a page.

mhsdesign commented 1 year ago

Question?

is a real factory to hard to setup and to bloaty (java style)

https://github.com/PackageFactory/atomic-fusion-presentationobjects/blob/master/Documentation/02_PresentationObjectFactories.md#writing-the-factory

<?php declare(strict_types=1);
namespace Vendor\Site\Presentation\Image;

use Neos\Flow\Annotations as Flow;

/**
 * @Flow\Scope("singleton")
 */
final class ImageFactory extends AbstractComponentPresentationObjectFactory
{
    /**
     * @param TraversableNodeInterface $node
     * @return ImageInterface
     */
    public function forImageNode(TraversableNodeInterface $node): ImageInterface
    {
        // Optional: Use assertions to ensure the incoming node type
        assert($node->getNodeType()->isOfType('Vendor.Site:Content.Image'));

        return new Image(
            $node->getProperty('image__src')
                ? $this->uriService->getAssetUri($node->getProperty('image__src'))
                : $this->uriService->getDummyImageUri()
            $node->getProperty('image__alt') ?? '',
            $node->getProperty('image__title')
        );
    }
}
mhsdesign commented 1 year ago

How much are we really limited by php illegal keywords in class names?

do we want to allow mixing integration and presentation?

return #[Component('Neos.Demo:Content.Headline')] function(Node $node): string
{
    return '<p>' . $node->getProperty('title') . '</p>';
};

or worse:

return #[Component('Neos.Demo:Content.Headline')] function(Node $node): string
{
    ob_start();
    ?>
       <p>hello</p>
     <?php

    return ob_get_contents();
};

keine Kindersicherung! alles ist erlaubt.

mhsdesign commented 1 year ago

How critical are unplanned fusion overrides … for example for adjusting fe code of the fusion form builder

mhsdesign commented 1 year ago

Hmm thinking about it

$content = editable(
    renderingStuff: $renderingStuff,
    property: 'title',
    block: false
);

Feels a bit weird (maybe the name renderingStuff is too long and could be shortened to ctx

But how about extra methods or services on the renderingStuff

Like

$content = $renderingStuff->editable(
    property: 'title',
    block: false
);
$content = $renderingStuff->editable->for(
    property: 'title',
    block: false
);

Might be too bloaty but less god object:

Editable::for($renderingStuff)->get(
    property: "title"
);
editable($renderingStuff)->for(property: 'title');

wilhelm said he likes $renderingStuff->editable()

but he would probably go for

$content = $renderingStuff->makeEditable(
    property: 'title',
    block: false
);
mhsdesign commented 1 year ago

Also I remember the time where I was totally convinced by fluid because it appeared so simple, that why I build this https://neos-project.slack.com/archives/C04HF7TT9/p1624907972026500 (not really useful ^^, but whatever)

my point is to maybe reduce boilerplate code even more:

/** @var $node Node */

return new Headline(
    $node->getProperty('title')
)