How to create a page url from page uid - typo3

I am working on a typo3 extension and I want to generate an url from the page id. Currently I create the url by appending index.php?id=ID to $GLOBALS['TSFE']->baseURL.
Is there any other way to create a readable url from the page id, and if yes, how it can be done?

Since Extbase controllers have an UriBuilder object, you should use it:
$uri = $this->uriBuilder->reset()
->setTargetPageUid($pageUid)
->setCreateAbsoluteUri(TRUE)
->build();
You can also set an array of arguments if you need to:
$arguments = array(
array('tx_myext_myplugin' =>
array(
'article' => $articleUid,
)
)
);
Or, if you don't need an extension prefix:
$arguments = array(
'logintype' => 'login'
);
(Of course you can mix the two variants.)
And then use:
$uri = $this->uriBuilder->reset()
->setTargetPageUid($pageUid)
->setCreateAbsoluteUri(TRUE)
->setArguments($arguments)
->build();

In case you are not in extbase controller context, you can use the standard TYPO3 functionality:
$url = $GLOBALS['TSFE']->cObj->typoLink_URL(
array(
'parameter' => $pageUid,
'forceAbsoluteUrl' => true,
)
);

Some answers already exist but they do not consider some of the other methods. In particular, it is very simple to do it in Fluid. Sometimes, it also depends what you have available (e.g. if a service object is already initialized. For example, I needed to resolve the URL in a middleware and $GLOBALS['TSFE']->cObj was not available there, neither Extbase, so I used method 4).
TL;DR:
if using Fluid, use Fluid (method 1)
in PHP in Extbase Controller (FE): use $this->uriBuilder (method 2)
in PHP, non Extbase (FE): use $site->getRouter()->generateUri (method 4)
in PHP, non Extbase (BE): use BackendUtility::getPreviewUrl (method 5)
decision diagram:
.
├── Fluid
│   ├── BE
│   │   └── method1-fluid-vh-link.
│   └── FE
│   └── method1-fluid-vh-link.
└── PHP
├── BE
│   ├── in-extbase-controller
│   │   └── method2-extbase-uriBuilder
│   └── non-extbase
│   └── method5-getPreviewUrl
└── FE
├── in-extbase-controller
│   └── method2-uriBuilder
└── non-extbase
├── method3-typo3link_URL
└── method4-site-router-generateUri
If you are using Fluid, this is usually the most straightforward way to render a URL or a link, e.g. use link.page to get a link to a page or use link.action to get a link to a page with Extbase plugins - considering other query parameters as well.
<f:link.page pageUid="1">link</f:link.page>
<f:link.action pageUid="1" action="display" controller="Profile" arguments="{studyid: id}">link</f:link.action>
If you are in an Extbase Controller (FE) and $this->uriBuilder is initialized (as proposed in other answer by lorenz). Important: There are 2 classes UriBuilder, an Extbase one (\TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder) and a non Extbase one (\TYPO3\CMS\Backend\Routing\UriBuilder), use the Extbase one in FE only, see TYPO3 documentation: Extbase UriBuilder.
$this->uriBuilder->uriFor($actionName, $arguments, $controllerName, $extensionName);
// or
$uri = $this->uriBuilder->reset()
->setTargetPageUid($pageUid)
->build();
If you are not in Extbase context, but in Frontend, you can use $GLOBALS['TSFE']->cObj->typoLink_URL (as proposed in other answer by cweiske). Important: $GLOBALS['TSFE']->cObj must be initialized which may not be the case in BE or CLI context or in preview mode in FE. See documentation on TypoScript typolink for more parameters.
// slightly paranoid double-checking here, feel free to leave out if you know what you are doing
if (!$GLOBALS['TSFE'] || !$GLOBALS['TSFE'] instanceof TypoScriptFrontendController
|| !$GLOBALS['TSFE']->cObj
|| !$GLOBALS['TSFE']->cObj instanceof ContentObjectRenderer
) {
return '';
}
$params = [
'parameter' => $pageId
];
return $GLOBALS['TSFE']->cObj->typoLink_URL($params);
In FE, but not in Extbase context (same as 3, but using $site, not typoLink_URL, since TYPO3 >= v9):
$queryParameters = [
'_language' = 0,
];
$siteFinder = GeneralUtility::makeInstance(SiteFinder::class);
$site = $siteFinder->getSiteByPageId($pageId);
return (string)$site->getRouter()->generateUri(
$pageId,
$queryParameters
);
If you are in Backend context, but not in an Extbase module
BackendUtility::getPreviewUrl($pid)
See also Backend class (not Extbase UriBuilder!): TYPO3\CMS\Backend\Routing\UriBuilder to create backend links to edit records (TYPO3 Documentation: Links to Edit Records)

In case that you don't have initialized $GLOBALS['TSFE'] and would you like to avoid this bug https://forge.typo3.org/issues/71361 you have to initialize $GLOBALS['TSFE'] in this way:
if (!isset($GLOBALS['TSFE'])) {
$pid = (int)GeneralUtility::_POST('pid');
$rootline =
\TYPO3\CMS\Backend\Utility\BackendUtility::BEgetRootLine($pid);
foreach ($rootline as $page) {
if ($page['is_siteroot']) {
$id = (int)$page['uid'];
break;
}
}
$type = 0;
if (!is_object($GLOBALS['TT'])) {
$GLOBALS['TT'] = new \TYPO3\CMS\Core\TimeTracker\NullTimeTracker;
$GLOBALS['TT']->start();
}
$GLOBALS['TSFE'] =
GeneralUtility::makeInstance('TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController',
$GLOBALS['TYPO3_CONF_VARS'], $id, $type);
$GLOBALS['TSFE']->connectToDB();
$GLOBALS['TSFE']->initFEuser();
$GLOBALS['TSFE']->determineId();
$GLOBALS['TSFE']->initTemplate();
$GLOBALS['TSFE']->getConfigArray();
if
(\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded('realurl')
) {
$host =
\TYPO3\CMS\Backend\Utility\BackendUtility::firstDomainRecord($rootline);
$_SERVER['HTTP_HOST'] = $host;
}
}

Generate frontend plugin / extension link from Backend Module with cHash parameter
NOTE : Dont forget to include below lines on the top your controller
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Frontend\Page\CacheHashCalculator;
$siteUrl = GeneralUtility::getIndpEnv('TYPO3_SITE_URL') . 'index.php?';
$query = array(
'id' => 57, // Target page id
'tx_event_eventfe' => array(
'controller' => 'Event',
'action' => 'show',
'eventId' => 15 // Record uid
)
);
$cacheHasObj = GeneralUtility::makeInstance(CacheHashCalculator::class);
$cacheHashArray = $cacheHasObj->getRelevantParameters(GeneralUtility::implodeArrayForUrl('', $query));
$query['cHash'] = $cacheHasObj->calculateCacheHash($cacheHashArray);
$uri = $siteUrl . http_build_query($query);

Related

EVENT API in moodle

I am new to moodle. I'm trying to write an Events API in moodle that will be called when a user logged in and logged out. I have created a local plugin and the directory structure is as follows
os_template/
├── classes
│ └── observer.php
├── db
│ └── events.php └── version.php
db/events.php
defined('MOODLE_INTERNAL') || die();
$observers = array(
array(
'eventname' => '\core\event\user_loggedin',
'callback' => '\local_ostemplate\local_ostemplateevents::user_loggedin',
),
array(
'eventname' => '\core\event\user_loggedout',
'callback' => '\local_ostemplate\local_ostemplateevents::user_loggedin',
),
);
classes/observer.php
namespace local_ostemplate;
class local_ostemplateevents
{
public static function user_loggedin(core\event\base $event)
{
file_put_contents("test.txt","User Logged in");
}
}
But no events are called when user logged in to the moodle. Anybody please help
Your observer class "local_ostemplateevents" must have the same name as the file it is in, due to the Autoloader.
So change to something like:
os_template/
├── classes
│ └── ostemplateobserver.php
├── db
│ └── events.php
└── version.php
events.php:
defined('MOODLE_INTERNAL') || die();
$observers = array(
array(
'eventname' => '\core\event\user_loggedin',
'callback' => '\local_ostemplate\ostemplateobserver::user_loggedin',
),
array(
'eventname' => '\core\event\user_loggedout',
'callback' => '\local_ostemplate\ostemplateobserver::user_loggedin',
),
);
ostemplateobserver.php:
namespace local_ostemplate;
class ostemplateobserver {
public static function user_loggedin(core\event\base $event) {
file_put_contents("test.txt","User Logged in");
}
}

How to access complex variables in page typoscript from content element via viewhelper?

I am using cobj_xpath object in my page typoscript as follows.
lib.xpath = XPATH
lib.xpath {
source = http://docsouth.unc.edu/southlit/poe/poe.xml
return = string
resultObj {
cObjNum = 1
1.current = 1
}
}
page.10 = FLUIDTEMPLATE
page.10.variables {
title < lib.xpath
title.expression = /TEI.2/text/front/titlePage/docTitle/titlePart
author < lib.xpath
author.expression = /TEI.2/text/front/titlePage/docAuthor
}
I can access the 'title' and 'author' variables in page template successfully via {title} and {author} viewhelpers but I cannot access them in the content element level. I cannot even find them in at CE level. Also I have the same problem with other COAs e.g.:
taleArgument = TEXT
taleArgument.data = GP:tale
MORE INFO:
I have created the CE via mask extension and configured it to create the required files in /Resources/Mask/ folder. In this folder there is a json file which contains the CE configuration and two folders named Backend and Frontend. Each of these folders contain Layout/Partial/Templates folders. I have inserted the CE created by mask in one of my pages. I manipulate the HTML file in Frontend/Templates as the template file and I can access the fields which I have created in the CE backend properly, so I suppose that my configuration is working well to this end.
Typo3 Version: 9.5.19
cobj_xpath and cobj_xslt version: 1.9.0
Further Investigations:
To get rid of external extensions, I installed a fresh Typo3. Then I developed a CE in my sitepackage from scratch. My configuration follows:
my_ext/Configuration/TsConfig/Page/Mod/Wizards/NewContentElement.tsconfig
mod.wizards.newContentElement.wizardItems.common {
elements {
my_ext_newcontentelement {
iconIdentifier = folder-open
title = Registration Example
description = Create a registration form
tt_content_defValues {
CType = my_ext_newcontentelement
}
}
}
show := addToList(my_ext_newcontentelement)
}
my_ext/Configuration/TCA/Overrides/tt_content.php
<?php
defined('TYPO3_MODE') or die();
call_user_func(function () {
// Adds the content element to the "Type" dropdown
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTcaSelectItem(
'tt_content',
'CType',
[
'Registration Example',
'my_ext_newcontentelement',
'form-checkbox',
],
'textmedia',
'after'
);
// Configure the default backend fields for the content element
$GLOBALS['TCA']['tt_content']['types']['my_ext_newcontentelement'] = [
'showitem' => '
--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:general,
--palette--;;general,
--palette--;;headers,
bodytext;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:bodytext_formlabel,
--div--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:tabs.appearance,
--palette--;;frames,
--palette--;;appearanceLinks,
--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:language,
--palette--;;language,
--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:access,
--palette--;;hidden,
--palette--;;access,
--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:categories,
categories,
--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:notes,
rowDescription,
--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:extended,
',
'columnsOverrides' => [
'bodytext' => [
'config' => [
'enableRichtext' => true,
'richtextConfiguration' => 'default',
],
],
],
];
});
my_ext/Configuration/TypoScript/setup.typoscript
lib.contentElement {
templateRootPaths.200 = EXT:my_ext/Resources/Private/Templates/ContentElements/
}
tt_content {
my_ext_newcontentelement =< lib.contentElement
my_ext_newcontentelement {
templateName = NewContentElement
}
}
my_ext/Resources/Private/Templates/ContentElements/NewContentElement.html:
<div>{data.bodytext -> f:format.html()}</div>
I tested my CE after adding one to the backend and it works fine so far.
Then I create a new variable in my_ext/Configuration/TypoScript/setup.typoscript:
page.10.variables {
test = TEXT
test.value = test
}
I can see the variable when I add {_all} to my page template:
but no luck when I try to catch it in my CE template:
TLDR:
each fluid rendering has it's own variables. There are no global fluid-variables.
It is obvious that you can not access test from your content element as the definition of page.10.variables results in fluid variables used while you are renderend the page-template (page.10).
In your content element you have an independent rendering with it's own set of variables.
Meanwhile you often have fluid for some rendering, but each has its own definition and variable set.
The whole page has a page fluid rendering.
Each plugin has it's own fluid rendering, probably for each action. Although they share a common extension setting which results in some common fluid variables.
Each content element has a Fluid rendering, though they might share some definition as the result from the same kind of data (a tt_content record). The kind of CE defines which template is used to start with and there are different renderings.
Using TYPO9 and ext:bootstrap_package (and ext_fluid_styled_content) you can find:
The rendering of the CEs is defined below tt_content. with the name of the CE as next key. All definitions are based on lib.dynamicContent
if you want to access any data independent from context in your fluid you could use typoscript viewhelpers like:
lib.text = TEXT
lib.text.value = test
lib.getText = TEXT
lib.getText.data = GP:text
the calls in fluid:
<f:cObject typoscriptObjectPath="lib.text" />
{f:cObject(typoscriptObjectPath:'lib.getText')}

Create Email HTML Using Partial in Zend Framework 2?

I'm working on a system where we want to queue up a batch of emails and then send them using a queue (so I can't use \Zend\Mail directly). The goal is to not have HTML inside the models that are creating the emails but instead have them in a view file. I'm trying to call the partial view helper inside the models (which I did in ZF1) but can't find anything on the web on how to do this. Is this possible in ZF2 or is there a better way? I've managed it before where we've had the HTML inside the models and it's been a mess. :-)
You can just create a template somewhere, pull the renderer from your service locator, and render away:
<?php
// this assumes you're in some AbstractActionController,
// but you could be in some service class that has the
// renderer injected, etc.
// template vars
$vars = array(/* .... */);
// create a ViewModel
$vm = new \Zend\View\Model\ViewModel($vars);
// path to your email template, compatible with your template map config.
$tpl = 'mymodule/emails/some-email-template.phtml';
$vm->setTemplate($tpl);
// get the renderer from the ServiceManager, so it's all nicely configured.
$renderer = $this->getServiceLocator()->get('Zend\View\Renderer\RendererInterface');
// render some HTML
$html = $renderer->render($vm);
You could do it this way:
1. In the module.config define those HTML mail content template views.
'view_manager' => array(
(...)
'template_map' => array(
'mail_content_1' => __DIR__ . '/../view/<MODULE_NAME>/mail_content_1.phtml',
),
(...)
)
2. Load the Template View in your model and get the HTML.
use Zend\View\Model\ViewModel;
public function getMailHTML() {
$view = new ViewModel;
$variables = array( "parm1" => "value1" );
//SET THE VARIABLES, LIKE IN PARTIALS
$view->setVariables( $variables );
//SET THE TEMPLATE VIEW KEY DEFINED IN THE module.config
$view->setTemplate( 'mail_content_1' );
//YOU'LL HAVE TO BE ABLE TO USE THE ServiceManager IN YOUR MAIL MODELS.
//RENDERING THE VIEW YOU'LL GET THE HTML
return $this->serviceManager->get( 'viewrenderer' )->render( $view );
}

Zend Navigation setting language parameter for route doesnt reflect in app

I have a zend xml config like so:
<design>
<navigation>
<frontend>
<company>
<label>Company</label>
<route>sitepage</route>
<pages>
<about>
<label>About us</label>
<route>sitepage</route>
<params>
<page>about-us</page>
<language>en</language>
</params>
</about>
Here is my sitepage route:
resources.router.routes.sitepage.type = Zend_Controller_Router_Route
resources.router.routes.sitepage.route = ":language/page/:page"
resources.router.routes.sitepage.defaults.module ="core"
resources.router.routes.sitepage.defaults.controller = "page"
resources.router.routes.sitepage.defaults.action = "view"
resources.router.routes.sitepage.defaults.page = "home"
resources.router.routes.sitepage.defaults.language = "en"
As you can see, what I do is set the page param within the <params> xml node. I tried adding the <language> parameter thinking it would automatically update to the application language, but it doesnt seem to work that way. My navigation menu just outputs, for example, http://localhost/en/page/about-us when It should be http://localhost/it/page/about-us (given that my application is registered as using the it language). How can I get my navigation to recognize the application language (it) ?
I worked this out a different way...
Here is an example for a main registration page:
routes.register_index.route = #lang/#register
routes.register_index.defaults.controller = register
routes.register_index.defaults.action = index
My navigation.xml is empty but you could use just a label and route.
You may have noticed # instead of : in my routes. This is designed mostly for i18n sites.
In my language folder, I have the regular en.php, etc. AND url-en.php, etc.
Here is what it looks like:
<?php
return array(
'lang' => 'en',
'register' => 'register',
'about' => 'about-us',
);
With this, the same route will be used for /en/register, /fr/inscription, etc. (one for each language file)
In my Bootstrap, I include these with the Rewrite initiation:
protected function _initRewrite()
{
$translator = new Zend_Translate('array', APPLICATION_PATH . '/language/url-fr.php', 'fr');
$translator->addTranslation(APPLICATION_PATH . '/language/url-en.php', 'en');
// Set the current locale for the translator
$locale = Zend_Registry::get('Zend_Locale');
$translator->setLocale($locale);
// Set it as default translator for routes
Zend_Controller_Router_Route::setDefaultTranslator($translator);
$front_controller = Zend_Controller_Front::getInstance();
$router = $front_controller->getRouter();
$config = new Zend_Config_Ini(APPLICATION_PATH . '/configs/routes.ini', APPLICATION_ENV);
$router->addConfig($config, 'routes');
$router->addDefaultRoutes();
}
This basically tells your application to translate #lang by its value from url-lang.php according to the current locale. Locale has to be set before this point in your bootstrap. You can either retrieve it from session, cookie, URL, anything.
Once this is done, you can call your route anywhere and it'll be in the current locale, using data from the special language files. Make sure your nav file has the same names as your routes and you should be fine.

Using component's routes from 'router.php' in custom Plugin in Joomla

Question: How do I enable the Routes from my component's router.php in a plugin?
I'm working on a custom Plugin which redirects the route from default user profile:
index.php?option=com_users&view=profile (SEF: /component/users/profile)
to my own component where I've got additional settings
index.php?option=com_mycomponent&view=profile (SEF: /alias/profile)
my front-end plugin:
class plgSystemMyPlugin extends JPlugin
{
// constructor
function plgSystemMyPlugin( &$subject, $params ) {
parent::__construct( $subject, $params );
}
// run after the framework has loaded and the application initialize method has been called
function onAfterInitialise() {
// when component users and view profile are called
if( isset($_GET['option'], $_GET['view'])
&& $_GET['option'] == 'com_users'
&& $_GET['view'] == 'profile' )
{
$route = JRoute::_('index.php?option=com_mycomponent&view=profile' );
JFactory::getApplication()->redirect($route, null, null, true);
}
}
}
In my component all links are routed correctly ie:
index.php?option=com_mycomponent&view=profile => /alias/profile
in the plugin JRoute translates it as follows:
index.php?option=com_mycomponent&view=profile => /component/mycomponent/profile
can not use:
core hacks
.htaccess
Joomla Redirect Plugin
in the plugin xml file you should add new parameter that will allow you to choose the desired Itemid(menuitem)
so it should look like this
<param name="menuitem" name="my_itemid" title="Target Itemid" description=""/>
Then you will need to choose desired menuitem that has the alias that you wanted from the plugin parameters in the administrator area
then in the plugin itself just use like this:
$route = JRoute::_('index.php?Itemid='.$this->params->get('my_itemid') );
and this is valid too
$route = JRoute::_('index.php?option=com_mycomponent&view=profile&Itemid='.$this->params->get('my_itemid') );