Hi David,

I'm happy to hear that you like the approach, and honoured by it.

I have standardized data retrieval by key in all my work to use 
`ContainerInterface`, because IMHO this is what it is for, and it allows 
any other implementation that has some additional features. For example, it 
is possible to still fall back to `ArrayAccess` if necessary, although I 
would say that using `ContainerInterface#get()` is a better approach. Sure, 
maybe it's a small burden on the implementation; however, with a base 
implementation like dhii/data-container-base 
<https://github.com/Dhii/data-container-base/tree/develop>, and with a 
`DataObject` concrete type (coming soon) it is super easy to create 
standards-compliant contexts for use here and in all other similar places. 
Please bear in mind that this implementation is based on a an extension 
(new release coming soon) of the PSR-11, dhii/data-container-interface 
<https://github.com/Dhii/data-container-interface/tree/develop>, which 
fixes two important problems: the lack of an interface that can allow to 
only determine the existence of a value in a container (e.g. read-only), 
and the inability to determine details of a failed operation from an 
exception.

Same thing can be said about the return type: by allowing a 
`StringableInterface` (essentially a standardization of `__toString()`, see 
dhii/stringable-interface <https://github.com/Dhii/stringable-interface>) 
as well as `string` we would allow a generic algorithm that just works in 
all places, and more: `BlockInterface` extends `StringableInterface`, so 
it's entirely possible to render a template to a block. If a particular 
implementation needs to produce a lot of output and therefore needs 
streaming, it is entirely possible to create an object that both 
encapsulates a stream, and can be cast to string - in fact such streams are 
common. I have noticed however, and to my deepest regret, that 
`StreamInterface` is part of PSR-7, which is a huge, bloated standard that 
additionally completely disregards SOLID ISP, and therefore is extremely 
hard to use. I am already working to fix this problem in 
dhii/io-resource-interface 
<https://github.com/Dhii/io-resource-interface/tree/task/initial-interfaces>, 
which is much more... concise. Of course, it's super easy, and often 
advisable, to create an implementation that is both a 
`ReadableResourceInterface` and a `StringableInterface`. Therefore, I 
believe this problem is also solved by my standard.

Would be happy to hear any feedback, or answer any questions.

On Sunday, September 24, 2017 at 9:09:37 PM UTC+2, David Négrier wrote:
>
> Hey Thomas,
>
> Absolutely +1 with you regarding the need of "renderer" PSR.
>
> @Xedin: I just saw your work and I very much like the path you are 
> following with the TemplateInterface (
> https://github.com/Dhii/output-renderer-interface/blob/develop/src/TemplateInterface.php
> )
>
> @Thomas, @Hari, in the interfaces you propose, you introduce the notion of 
> a "$templatePath" (or template name in Zend). That is, your objects are 
> responsible for 2 things:
> 1 => fetching the template
> 2 => rendering the template
>
> These are 2 separate concerns and when it comes to a PSR, I believe that 
> we should only focus on the rendering part.
>
> Let me explain.
>
> Let's assume I have some code that renders a page using Twig:
>
> $this->renderer->render('path/to/index.twig', $data);
>
> If I want to switch my renderer implementation to a Plate template, I 
> cannot simply switch the renderer, I also need to change the path to the 
> template:
>
> $this->renderer->render('path/to/index.plate', $data);
>
> OR, I need to go in great details to invent a convention that 
> automatically adds the file extension to the template....
>
> Like this:
>
> $this->renderer->render('path/to/index', $data);
>
> Notice that this is something that Zend is doing: 
> https://github.com/zendframework/zend-expressive-template/blob/master/src/TemplateRendererInterface.php#L23-L24
>
> I believe that instead of representing a "renderer", we should focus on 
> objects that represents the template (like what Xedin Unknown is doing).
>
> This way, you can switch from one template to another, using simple 
> dependency injection!
>
> The interface should therefore be:
>
> interface TemplateInterface {
>     public functiion render(array $context): string
> }
>
> Now, I have 2 additional comments to make.
>
> By type-hinting to "array", we cannot use a context that would implement 
> "ArrayAccess". This can be useful in order to lazily evaluate the context. 
> Si I would switch this to;
>
> interface TemplateInterface {
>     /**
>      * @param array|ArrayAccess $context
>      */
>     public functiion render($context): string
> }
>
> Finally, regarding the return type, Hari is completely right to say that 
> we don't want a ResponseInterface (because this is not necessarily related 
> to an HTTP response). We could very well be rendereding a static HTML page 
> stored on disk, or rendering an email.
> However, we could improve over a simple "string" by using PSR-7 
> StreamInterface. That would allow for big responses that do not fit in 
> memory.
>
> So my ideal interface would be:
>
> interface TemplateInterface {
>     /**
>      * @param array|ArrayAccess $context
>      */
>     public functiion render($context): StreamInterface
> }
>
> ++
> David.
>
>
>
> Le dimanche 24 septembre 2017 15:16:06 UTC+2, Xedin Unknown a écrit :
>>
>> The changes that were pending are now merged, and can be found on the 
>> `develop` branch of the repos I mentioned. I hope this helps.
>>
>> The next step for be is to create package with base abstract 
>> implementations, which still lack the key logic, but save time for the 
>> implementors by including concrete logic for common things, like throwing 
>> exceptions, normalization, etc. It would be great to get an opinion from 
>> the honorable participants of this group :)
>>
>> On Sunday, September 24, 2017 at 10:32:17 AM UTC+2, Xedin Unknown wrote:
>>>
>>> Hi all,
>>>
>>> This is a good idea, and we are already working on this for the project 
>>> that is being built. Please take a look at 
>>> dhii/output-renderer-interface 
>>> <https://github.com/Dhii/output-renderer-interface/tree/develop>. The 
>>> readme should explain most of the things. I will try to describe how things 
>>> will work below. Please note that this is a work in progress; however, many 
>>> hours have been dedicated to making this standard as useful as possible. I 
>>> hope that it will be a good inspiration for a PSR.
>>>
>>> To put things simply, you have a `RendererInterface`, which is anything 
>>> that can produce output. This requires it to already have access to all 
>>> data that is necessary for rendering. A `BlockInterface` is a renderer that 
>>> can be cast to string, which is possible if it has sufficient data. 
>>> Interoperability is ensured via `StringableInterface`. A 
>>> `ContextRendererInterface` is something that can use a context, i.e. 
>>> additional data, for rendering. This is great for renderers, the instances 
>>> of which can be re-used to render the same "template" multiple times with 
>>> different data. The "aware" interfaces are for greater interop between 
>>> consumers of the main interfaces. Exception interfaces provide access to 
>>> aspects of the rendering, which allows obtaining information about the 
>>> rendering process without being aware of the internals of the 
>>> implementation, and without having prior reference to the instance, which 
>>> is very helpful and is a rule that we use in all standards.
>>>
>>> dhii/output-renderer-abstract 
>>> <https://github.com/Dhii/output-renderer-abstract/tree/task/initial-classes>
>>>  is 
>>> an abstract implementation, and a work in progress as well. Blocks are free 
>>> to produce output in any way they wish, so this package has just the most 
>>> abstract functionality. Right now, I am working on an 
>>> `AbstractTemplateBlock`, which uses a template to get rendered. While 
>>> designing this class, I realised (and this is a very important point) that 
>>> very good SoC can be achieved by encapsulating templates in a class that 
>>> represents a template. Without this, it doesn't seem practical to 
>>> standardize block logic to work with different templates. With templates as 
>>> a class, it's possible to render a template that works in any way inside a 
>>> block (or elsewhere). A template IMHO is just a way of saying "a form for 
>>> output that can be filled with values". In this case, a value is a 
>>> rendering context, and there is already an interface that does this - the 
>>> `ContextRendererInterface`. This is why a rename of this interface to 
>>> `TemplateInterface` is pending - because this is exactly what it is, and 
>>> it's more concise and expressive. I will be pushing the rename, as well as 
>>> the `AbstractTemplateBlock`, in a couple of hours, so that you can see the 
>>> usage.
>>>
>>> If a workgroup is being assembled to work on this standard, I would very 
>>> much like to be part of it. I have spent a lot of time standardizing output 
>>> mechanisms, and other things, very much inspired by the spirit and letter 
>>> of FIG. I will also gladly share my plans for the future standards and 
>>> implementations, as well as present other standards which I have been 
>>> working on. Many of them are being used in production by me and my team, 
>>> and are working very well so far.
>>>
>>>
>>>
>>> On Saturday, September 23, 2017 at 7:45:53 PM UTC+2, Thomas Gnandt wrote:
>>>>
>>>> With the upcoming http-middleware PSR which defines the 
>>>> RequestHandlerInterface it becomes possible to write framework independent 
>>>> modules that include ready-to-use actions (instances of 
>>>> RequestHandlerInterface). However this is not possible, until a common 
>>>> interface to render a template exists.
>>>> Any action that should work in multiple applications has to render the 
>>>> body of the response using templates, that are not part of the module 
>>>> itself. While example templates may be included in the module, these are 
>>>> generally not usable by the application that uses the module.
>>>> It therefore doesn't make sense to include a specific template engine 
>>>> as a requirement of the module. Since templates are written using engine 
>>>> specific syntax it is not feasible to use multiple template engines.
>>>> Consequently an application could only use modules that support the 
>>>> engine the application wants to use.
>>>>
>>>> In order to make the used template engine interchangeable a simple 
>>>> interface could be defined:
>>>>
>>>> interface TemplateRendererInterface
>>>> {
>>>>     public function render(ResponseInterface $response, string 
>>>> $templatePath, array $data = null): ResponseInterface;
>>>> }
>>>>
>>>> This would render the defined template with any data provided and write 
>>>> it to the body of the response.
>>>> Alternatively the following interface could be defined:
>>>>
>>>> interface TemplateRendererInterface
>>>> {
>>>>     public function render( string $templatePath, array $data = null): 
>>>> string;
>>>> }
>>>>
>>>> This provides greater flexibilty while the first interface provides 
>>>> easier usage in the specified use case (for request handlers).
>>>>
>>>

-- 
You received this message because you are subscribed to the Google Groups "PHP 
Framework Interoperability Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/php-fig/1b6dedb1-fbda-4cf0-980c-d998c1005c8d%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to