Access form data in multiple actions on same page - typo3

I'm trying to access a submitted object from one action in an other action on the same page, while making it available to both actions.
Example: Site /search/ has two plugins embedded:
SearchPlugin
shows search form
submits form to itself
ResultPlugin
should get form data from SearchPlugin
Now if I submit the SearchPlugin form data to itself I only have the form data available in the SearchPlugin action, not in the ResultPlugin. If it submit the SearchPlugin form to the ResultPlugin action I only have the data available in the ResultPlugin, not in the SearchPlugin.
I need the data to be available in both plugins/actions on the same site after submitting.
Is this somehow possible?

Built-in Extbase configuration option
You can use view.pluginNamespace to have both plugins use the same HTTP parameter namespace, (e.g. search instead of tx_extension_plugin1/tx_extension_plugin2): https://docs.typo3.org/m/typo3/book-extbasefluid/master/en-us/b-ExtbaseReference/Index.html
That will make your Extbase actions be able to "share" all parameters. Make sure that all your plugin actions are ready for that.
(Keep in mind though that this "feature" might be deprecated once probably because it adds some architectural burden to efficient resolving of routing configurations. But that is just rumor and I got the idea from here: https://github.com/TYPO3-Documentation/TYPO3CMS-Book-ExtbaseFluid/pull/379/files)
Custom solution
You can manually set up parameters for your Extbase actions in an initializeAction:
$pluginContexts = [
'tx_extension_plugin2',
];
// look for a SearchObject in a different (HTTP) plugin namespace
if (!$this->request->hasArgument('searchObject')) {
foreach ($pluginContexts as $pluginContext) {
$foreignPluginContext = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP($pluginContext);
if (isset($foreignPluginContext['searchObject'])) {
$searchObject = $foreignPluginContext['searchObject'];
// if needed do some mapping to object here or validate
...
$this->request->setArgument('searchObject', $searchObject);
break;
}
}
}

Related

TYPO3 v10: How to access TSFE in Backend/Scheduler Task?

The current situation:
I am trying to access the TypoScript configuration of the frontend from within the backend (or rather a scheduler task). Previously with Typo3 v8 and v9, I initialized entire $GLOBALS["TSFE"] object, however this was already hack the last time around (using mostly deprecated calls) and now it has all been removed with the v10 release.
My goal:
Access the TypoScript configuration of the frontend of a certain page (root page of a site would be fine) from within a scheduler job.
Background of the whole project:
I have a periodic scheduler job that sends emails to various users (fe_users). The email contains links to certain pages (configured UIDs in typoscript) as well as file attachments and the likes (generated by other extensions, which are also fully configured via typoscript). Currently, I basically initialize the entire frontend from within the backend, but as I said before, its inefficient, super hacky and I doubt it was the intended way to solve this problem.
Getting TypoScript settings in the backend is ugly, but possible.
You need a page ID and a rootline which you can pass to \TYPO3\CMS\Core\TypoScript\TemplateService::runThroughTemplates().
Something along these lines:
$template = GeneralUtility::makeInstance(TemplateService::class);
$template->tt_track = false;
$rootline = GeneralUtility::makeInstance(
RootlineUtility::class, $pageId
)->get();
$template->runThroughTemplates($rootline, 0);
$template->generateConfig();
$typoScriptSetup = $template->setup;
You can get inspiration from \TYPO3\CMS\Extbase\Configuration\BackendConfigurationManager::getTypoScriptSetup and \TYPO3\CMS\Tstemplate\Controller\TypoScriptTemplateObjectBrowserModuleFunctionController
This won't get any better and is not intended to be done such way. I would use as configuration:
plain PHP, e.g. in $GLOBALS['TYPO3_CONF_VARS]`
YAML site config if depending on various sites
You can build links by using e.g. something like that
protected function generateUrl(int $pageId, int $recordId)
{
$additionalParams = 'tx_xxxx[action]=show&tx_ixxxx[controller]=Job&tx_xxxx[job]=' . $recordId;
return BackendUtility::getPreviewUrl($pageId, '', null, '', '', $additionalParams);
}

Backend access rights for news records

Is it possible to store all records of the news extension (ext:news) on the same storage page, but show only records, which are created by the loggedin backend user?
So the current backend user can just see and edit his own records? Admins should see all records of course.
No, this is not possible, since backend user permissions on record level are not implemented in TYPO3.
So you either have to separate the news records of the users in separate sysfolders or you could try to use hooks (e.g. $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.db_list_extra.inc']['getTable']) or XClass to customize TYPO3 backend to your needs. I do not recommend the latter, since the TYPO3 backend permission system is complex and you would need to make sure to restrict record access in several parts of TYPO3 (e.g. recordlist, element browser, related news field, ...)
There are two ways to archive that:
If the backend user is not too much. You can just create a page(type
is folder) named with the backend user name. And in the backend user
module you can set the permission(Not for the group user but for the
single backend user only).
if the backend user is too much. and You just wanna set permissions for the group and all backend users are sharing the same rules. You can refer to Hook:https://docs.typo3.org/p/georgringer/news/main/en-us/Tutorials/ExtendNews/Hooks/Index.html so that the basic logic is like this:
2.1 get current logged-in user group.
2.2 if the group is Reporter, we can use the hook for the listing page:
$constraints[] = $query->equals('cruser_id', $be_id);
Edit(3/3/2022):
Hi Chris, Yes you are right.
Today, I have got a chance to dig into the news extension. I think we can still make it by the hook
in your ext_localconf.php
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][\TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList::class]['modifyQuery'][$_EXTKEY]
= \T3docs\SitePackage\Hooks\DatabaseRecordListHook::class;
(Please make sure the namespace is correct)
within the file : T3docs\SitePackage\Hooks\DatabaseRecordListHook.Create a function named modifyQuery:
public function modifyQuery($parameters,
$table,
$pageId,
$additionalConstraints,
$fields,
$queryBuilder)
{
if ($table === 'tx_news_domain_model_news') {
$tsconfig = $GLOBALS['BE_USER']->getTSConfig();
if (!empty($tsconfig['options.']['be_users'])) {
$be_users = $tsconfig['options.']['be_users'];
$queryBuilder->andWhere('cruser_id IN (' . $be_users . ')');
}
}
return $queryBuilder;
}
in the user Options tab set Tsconfg : options.be_users = 3,100
(3,100 is the be_user id. And the 2 two backend users's news will show up)
thus, it works for me.

Passing data between form views in Pyramid

I'm making a project in pyramid framework, so i have a view which have a form in it with 2 input type texts and a submit button.
The form is a post method, so im getting them with a POST request.
I want to send them to a new view and display them on the screen.
meaning:
on 0.0.0.0:6543 is the form on first view.
I want to display the values the user insert in the input on 0.0.0.0:6543/here
I tried with HTTPfound but i guess im missing an understanding on how to really pass the variables.
Please help me...
The easiest way to accomplish is to use sessions.
You need a session backend which stores your data on a server (see pyramid_redis_session). There are also cookie-based session solutions where all data is stored on the client side.
The first view writes all passed over data to a session:
request.session["mydata"] = value
The second view reads data from the session
print(request.session["mydata"])
Another way to pass the data from one view to another is via the URL. This does not require server-side support, unlike sessions. Also, it's RESTful ;)
return HTTPFound('/here?greeting=Hello&subject=World')
In your second view you then simply get the variables from request.GET:
greeting = request.GET.get('greeting', '')
subject = request.GET.get('subject', '')
# pass the data to the template
return {
"greeting": greeting,
"subject": subject
}
Regarding your comment: You can't use HTTPFound with POST. You can, however, directly submit your form to /here using <form method="post" action="/here" ...>. In this case you'll be able to access the data using request.POST.get('greeting').

Symfony2 Form Rest Api only add to Relation

I am using Symfony2 as Rest Api for a JS Frontend App. I came across a scenario where I want users to "invite" (=add) Users to a Group. But I want to only allow them to add Users to the existing Relation and not "overwrite" the whole relation, which is the standard behaviour in combination with a regular Symfony2 Form.
What would be the best practice to achieve this behaviour?
Additional Comment:
I am using Ember-Data in the frontend and my frontend would probably send a put request with the whole Group including additional users (but not all).
My JSON Payload would look something like this:
{
"usergroup": {
"name":"yxcv2",
"stake":"sdfghj",
"imageName":null,
"userCount":5,
"users":[
5,
6,
7
],
"gameGroup":"13",
}
}
In this scenario User 1,2,3 and 4 are already members of the group. And instead of replacing 1,2,3,4 with 5,6,7, I want to ADD 5,6,7 to the already existing members.
A LINK request should be used to add an item to an existing collection instead of overwriting it with a POST request.
Using a symfony form you'd post the User (id) plus a hidden field _method with value LINK to something like /groups/{id}.
routing would be something like this:
group_invite:
path: /groups/{id}
defaults: { _controller: YourBundle:Group:inviteUser }
methods: [LINK]
You could use FOSRestBundle's implicit resource name definition, too.
For the method override to work the config setting framework.http_method_override needs to be set to true ( = default value - available since symfony version 2.3).
More information can be found in the documentation chapter:
How to use HTTP Methods beyond GET and POST in Routes

zend framework urls and get method

I am developing a website using zend framework.
i have a search form with get method. when the user clicks submit button the query string appears in the url after ? mark. but i want it to be zend like url.
is it possible?
As well as the JS approach you can do a redirect back to the preferred URL you want. I.e. let the form submit via GET, then redirect to the ZF routing style.
This is, however, overkill unless you have a really good reason to want to create neat URLs for your search queries. Generally speaking a search form should send a GET query that can be bookmarked. And there's nothing wrong with ?param=val style parameters in a URL :-)
ZF URLs are a little odd in that they force URL parameters to be part of the main URL. I.e. domain.com/controller/action/param/val/param2/val rather than domain.com/controller/action?param=val&param2=val
This isn't always what you want, but seems to be the way frameworks are going with URL parameters
There is no obvious solution. The form generated by zf will be a standard html one. When submitted from the browser using GET it will result in a request like
/action/specified/in/form?var1=val1&var2=var2
Only solution to get a "zendlike url" (one with / instead of ? or &), would be to hack the form submission using javascript. For example you can listen for onSubmit, abort the submission and instead redirect browser to a translated url. I personally don't believe this solution is worth the added complexity, but it should perform what you're looking for.
After raging against this for a day-and-a-half, and doing my best to figure out the right way to do this fairly simple this, I gave up and did the following. I still can't believe there's not a better way.
The use case that necessitates this is a simple record listing, with a form up top for adding some filters (via GET), maybe some column sorting, and Zend_Paginate thrown in for good measure. I ran into issues using the Url view helper in my pagination partial, but I suspect with even just sorting and a filter-form, Zend_View_Helper_Url would still fall down.
But I digress. My solution was to add a method to my base controller class that merges any raw query-string parameters with the existing zend-style slashy-params, and redirects (but only if necessary). The method can be called in any action that doesn't have to handle POSTs.
Hopefully someone will find this useful. Or even better, find a better way:
/**
* Translate standard URL parameters (?foo=bar&baz=bork) to zend-style
* param (foo/bar/baz/bork). Query-string style
* values override existing route-params.
*/
public function mergeQueryString(){
if ($this->getRequest()->isPost()){
throw new Exception("mergeQueryString only works on GET requests.");
}
$q = $this->getRequest()->getQuery();
$p = $this->getRequest()->getParams();
if (empty($q)) {
//there's nothing to do.
return;
}
$action = $p['action'];
$controller = $p['controller'];
$module = $p['module'];
unset($p['action'],$p['controller'],$p['module']);
$params = array_merge($p,$q);
$this->_helper->getHelper('Redirector')
->setCode(301)
->gotoSimple(
$action,
$controller,
$module,
$params);
}