Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEATURE] Allow developers to define their own view #1784

Open
wants to merge 8 commits into
base: main
Choose a base branch
from

Conversation

AKaravas
Copy link
Contributor

@AKaravas AKaravas commented May 25, 2022

Now days a lot of websites are taking the headless approach, so i figured that the news extension should give the ability to the developers to use the JsonView if needed or any other view for that matter.

I added an event and a getView function which gets the view and appends the developer's wished view to the called action. It can be done for every action or individual actions. An example would be:

Create the listeners

Vendor\Ext\EventListener\NewsInitializeActionListener:
    tags:
      - name: event.listener
        identifier: 'newsInitializeExtend'
        method: 'NewsInitializeActionEvent'
        event: GeorgRinger\News\Event\NewsInitializeActionEvent

If every action should adopt the developer's wished view:

use TYPO3\CMS\Extbase\Mvc\View\JsonView;

final class NewsInitializeActionListener
{
    public function NewsInitializeActionEvent(NewsInitializeActionEvent $event): void
    {
        $event->setDefaultViewObjectName(JsonView::class);
    }
}

If only a specific action should adopt the developer's wished view:

use TYPO3\CMS\Extbase\Mvc\View\JsonView;

final class NewsInitializeActionListener
{
    public function NewsInitializeActionEvent(NewsInitializeActionEvent $event): void
    {
        if ($event->getAction() === 'list') {
            $event->setDefaultViewObjectName(JsonView::class);
        }
    }
}

Now if we want to use the JsonView, the $this->view->assignMultiple($event->getAssignedValues()); is not enough. We have to tell the JsonView which variables should be rendered. This can be done like this. I am using the listAction as an example:

Vendor\Ext\EventListener\NewsListActionListener:
    tags:
      - name: event.listener
        identifier: 'newsListExtend'
        method: 'NewsListActionEvent'
        event: GeorgRinger\News\Event\NewsListActionEvent
final class NewsListActionListener
{
    public function NewsListActionEvent(NewsListActionEvent $event): void
    {
        $event->getNewsController()->getView()->setVariablesToRender(array_keys($assignedValues));
    }
}

This will render everything as json and no templates are used. The only problem you will come across, is that the news entries are objects and can not be converted to json properly. In this case you have two options (AFAIK):

  1. Iterate through the news entries, create a new array with the entries converted to array and append the results to $event->getAssignedValues()['news']. A small example would be the following.
final class NewsListActionListener
{
    public function NewsListActionEvent(NewsListActionEvent $event): void
    {
        $news = $event->getAssignedValues()['news'];
        $assignedValues = $event->getAssignedValues();
        unset($assignedValues['news']);
        if (count($news) > 0) {
            $newArray = [];
            $i = 0;
            foreach ($news as $singleNew) {
                /** @var News $singleNew */
                $newArray[$i]['uid'] = $singleNew->getUid();
                $newArray[$i]['title'] = $singleNew->getTitle();
                $newArray[$i]['bodytext'] = $singleNew->getBodytext();
                $newArray[$i]['pathSegment'] = $singleNew->getPathSegment();
                $i++;
            }
            $assignedValues['news'] = $newArray;
            $event->setAssignedValues($assignedValues);
        }

        $event->getNewsController()->getView()->setVariablesToRender(array_keys($assignedValues));
    }
}

This works perfectly, the only con is that you have to manually iterate and select the values to append to the new created array. The same applies for the files (images, pdfs etc). You have to manually generate the links to the target file.

  1. The other way would be the ->setConfiguration() part of the JsonView.
final class NewsListActionListener
{
    public function NewsListActionEvent(NewsListActionEvent $event): void
    {
         $event->getNewsController()->getView()->setConfiguration([
            'news' => [
                '_descendAll' => [
                    '_recursive' => ['categories', 'falMedia', 'contentElements', 'tags']
                ],
            ]
        ]);
        $event->getNewsController()->getView()->setVariablesToRender(array_keys($event->getAssignedValues()));
     }
}

Pros:

  1. Much less code
  2. TYPO3 API is used.
  3. Relations are resolved

Cons:

  1. Relations are resolved but the array indexes are not 0, 1, 2 etc, but, the objectStorage index e.g. 000000006ec89aaa00000000382b1662.
  2. File Relations are resolved but the file object is not retrieved, only it's UID found on the sys_file_reference. I havent found any reference to the JsonView that allows to retrieve the file object.

Last but not least, you can take the headless approach, which in this case, you do not need any of the above. The only disadvantage is that you ll have to create the json output in your .html Templates. The headless extension has actually created an extended version of the news extension to make it headless. https://github.com/TYPO3-Headless/headless_news. But if you got to the Resources and look at the files, everything is converted to json in the .html files. This is very sensitive, because a space or a line not on the right position can cause the json output to be converted to string and can be very tedious.

If anyone can make it better, please do not hesitate to edit the code!

@DavidBruchmann
Copy link

I regret to disappoint you but the option of JSON view you've already with https://github.com/TYPO3-Headless/headless_news

@AKaravas
Copy link
Contributor Author

I know, i have written my thought for it at the bottom of my comment

@AKaravas
Copy link
Contributor Author

AKaravas commented May 25, 2022

Plus you talk about the JsonView. I tried to make it so that every view can be used. Self made or a core one. The JsonView was just an example because it the most used one after the TemplateView

@@ -35,15 +32,16 @@ public function __construct(NewsController $newsController, string $defaultViewO
}

/**
* Get the news controller
* @return NewsController
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not required, can be removed


/**
* @var string
* @param NewsController $newsController
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All not required, pleas remove

@@ -39,14 +39,14 @@ class News extends AbstractEntity
protected $l10nParent = 0;

/**
* @var DateTime
* @var DateTime|null
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am really unsure if that breaks in 10 because extbase can't get the type anymore of

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe leave those changes, also imo not related to this feature, correct?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants