I try to create controller that handles ajax requests.
I found out, that I have to add this to my TS config:
ajaxCall = PAGE
ajaxCall {
typeNum = 999
config.disableAllHeaderCode = 1
config.metaCharset = UTF-8
xhtml_cleaning = 0
admPanel = 0
10 = COA
10 < tt_content.list.20.registration_userregistration
}
And my controller looks like this:
/**
* JSONController
*/
class JSONController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionController {
/**
* #var string
*/
protected $defaultViewObjectName = 'TYPO3\\CMS\\Extbase\\Mvc\\View\\JsonView';
/**
* action test
*
* #return string
*/
public function testAction() {
$this->view->assign('value', "001");
}
}
This works, I get a blank page with "001" on it. But if I look at the source, there are 4 empty lines, and "001" is in the 5th line.
-empty-
-empty-
-empty-
-empty-
"001"
I have no idea why...
I don't get, why are you using some view for rendering JSON ???
public function testAction() {
$data = array('value'=>'001');
return json_encode($data);
}
Of course you should set Content-type: application/json - where do you prefer - in your TS or directly in the action before return;
Other clue: maybe it's caused by tt_content (just guesing), for JSON actions it's best to include them directly via Bootstrap, first register new FE plugin in your ext_localconf.php:
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
'VENDORNAME.' . $_EXTKEY,
'JsonDataPlugin',
array('JSON' => 'test',),
array('JSON' => 'test',)
);
And modify your TS:
myAjaxPage = PAGE
myAjaxPage {
typeNum = 999
10 = USER
10 {
userFunc = TYPO3\CMS\Extbase\Core\Bootstrap->run
extensionName = Yourextname
pluginName = JsonDataPlugin
vendorName = VENDORNAME
}
config {
disableAllHeaderCode = 1
additionalHeaders = Content-type:application/json
xhtml_cleaning = 0
admPanel = 0
debug = 0
no_cache = 1
}
}
(don't forget to change Yourextname and VENDORNAME for your own, also clear the system cache)
Finally: Check all your files and make sure that there's no empty lines before <?php and after ?> (the best option is to remove ?> from each file - and let PHP to terminate script at the end of file). Also it can be fixed in the source of TYPO3 as described in other naswer.
Okay, I got it...
I included a file with some functions named user.php
/**
* User service
*
* #var \Whmcs\Registration\Service\User
* #inject
*/
protected $user = NULL;
In this file there were empty lines after the ?> tag. These empty lines were the problem. I deleted them and now everything works fine. :)
Related
I trying to keep original file name when using System/Models/File, I got following code to extend this model:
namespace System\Models;
class NewFile extends File { public function fromPost($uploadedFile) { if ($uploadedFile === null) { return; }
$this->file_name = $uploadedFile->getClientOriginalName();
$this->file_size = $uploadedFile->getClientSize();
$this->content_type = $uploadedFile->getMimeType();
$this->disk_name = $this->getDiskName();
/*
* getRealPath() can be empty for some environments (IIS)
*/
$realPath = empty(trim($uploadedFile->getRealPath()))
? $uploadedFile->getPath() . DIRECTORY_SEPARATOR . $uploadedFile->getFileName()
: $uploadedFile->getRealPath();
//$this->putFile($realPath, $this->disk_name);
$this->putFile($realPath, $this->file_name);
return $this;
It works with file itself, it keeps original name but problem is link to attached file is still being generated. Broke my mind but cant get this work. Can anyone elaborate how to fix it?
Oh I see it seems its try to use disk_name to generate URL
so you did well for saving an image
//$this->putFile($realPath, $this->disk_name);
$this->putFile($realPath, $this->file_name);
but you just need to replace one line .. just undo your changes and make this one change
$this->file_name = $uploadedFile->getClientOriginalName();
$this->file_size = $uploadedFile->getClientSize();
$this->content_type = $uploadedFile->getMimeType();
// $this->disk_name = $this->getDiskName();
$this->disk_name = $this->file_name;
// use same file_name for disk ^ HERE
Link logic ( for referance only ) vendor\october\rain\src\Database\Attach\File.php and modules\system\models\File.php
/**
* Returns the public address to access the file.
*/
public function getPath()
{
return $this->getPublicPath() . $this->getPartitionDirectory() . $this->disk_name;
}
/**
* Define the public address for the storage path.
*/
public function getPublicPath()
{
$uploadsPath = Config::get('cms.storage.uploads.path', '/storage/app/uploads');
if ($this->isPublic()) {
$uploadsPath .= '/public';
}
else {
$uploadsPath .= '/protected';
}
return Url::asset($uploadsPath) . '/';
}
Just make disk_name also same as file_name so when file saved on disk it will use original name and when the link is generated it also use disk_name which is original file_name
now your link and file name are synced and will be same always.
if any doubt please comment.
I've upgraded Typo3 from version 4 to version 7 and the ajax endpoint isn't working anymore, is anyone know if there are undocumented changes in the usage of the simple ajax endpoint definition in typoscript?
Or can it be that the requesting URL is different now?
The original definition looks like this:
tx_courses_ajax = PAGE
tx_courses_ajax {
typeNum = 1337
10 = USER
10 {
#userFunc = tx_extbase_core_bootstrap->run
userFunc = TYPO3\CMS\Extbase\Core\Bootstrap->run
extensionName = courses
pluginName = calendar
switchableControllerActions {
Seminars {
1 = getEvent
2 = calendar
3 = getEvents
}
}
settings =< plugin.tx_courses.settings
persistence =< plugin.tx_courses.persistence
view =< plugin.tx_courses.view
}
config {
disableAllHeaderCode = 1
xhtml_cleaning = 0
admPanel = 0
debug = 1
no_cache = 1
tx_realurl_enable = 0
additionalHeaders = Content-type: application/json
}
10 < tt_content.list.20.tx_courses_ajax
}
The controller is looking like this in a simplified version:
class Tx_Kurse_Controller_SeminareController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionController {
public function calendarAction() {
$calenderCgf = '...';
file_put_contents($docroot.'uploads/jquery.fullcalendar-mini.js', $calenderCgf);
}
/**
* #return void
*/
public function getEventAction() {
$requestParams = $this->request->getArguments();
print_r($requestParams);
}
/**
* #param string $start Y-M-D H:i:s
* #param string $end Y-M-D H:i:s
*
* #return string $seminarText
*/
public function getEventsAction($start, $end) {
$start = new DateTime($start);
$end = new DateTime($end);
$seminars = $this->seminarsRepository->findEventsInPeriod($start, $end);
$requestParams = $this->request->getArguments();
print_r($requestParams);
}
/**
* #param int $seminar
* #return void
*/
public function bindingAction($seminar) {
$seminars = $this->seminareRepository->findByUid($seminar);
$this->view->assign('seminars', $seminars);
}
}
The original request-url is:
index.php?id=176&no_cache=1&tx_courses_calendar[controller]=Seminars&tx_courses_calendar[action]=binding&tx_courses_calendar[start]=2017-01-01%2000:00:00&tx_courses_calendar[end]=2017-12-30%2023:59:59&type=1337
I only get as request result in debug mode:
<!-- Parsetime: 42ms -->
So it seems that the typoscript definition is working, but something seems to be wrong :(
UPDATE: I've found the solution:
10 < tt_content.list.20.tx_courses_ajax
Must be removed because it's not doing the same as in version 4 (and it's also not necessary anymore) and after that did i've received a response with an error message. The message has said that the wanted actions are not available for this controller.
After that i've digged deeper and the Extension-Name must be configured in uppercase for the first letter, otherwise it won't work.
Just by guessing but maybe the vendorName is missing in the configuration.
I am using simple google recaptcha.
My requirement is that if google api is not available (i.e. if google server is down, know its not usual case) means not getting any reply from google server then while loding the form I will hide the google reCaptcha wrapper and while submitting the form I don't want to validate google recaptcha.
Please suggest How can I achieve this.
Google does not provide that data (assuming they are always up).
But you could go about it this way. Dynamically load the script and check for the event existence in the callback. If no event is available then it failed.
Check out the #example comment for usage.
var setAttributes = function (el, attrs) {
/**
* #method simple for in loop to help with creating elements programatically
* #param {object} el - HTMLElement attributes are getting added to
* #param {object} attrs - object literal with key/values for desired attributes
* #example setAttributes(info,{
* 'id' : 'info'
* 'class' : 'my-class-name'
* });
*/
'use strict';
var key;
for (key in attrs) {
if (attrs.hasOwnProperty(key)) {
el.setAttribute(key, attrs[key]);
}
}
return el;
};
var getScript = function (url, fullPath) {
/**
* #method dynamically add script tags to the page.
* #param {url} string with relative path and file name - do not include extension
* #param {fullPath} string with absolute path
* #example getScript('FrameAdjustChild');
* #example getScript('','https://www.google-analytics.com/analytics.js');
*/
'use strict';
var setAtt, PATH = /js/, /* or wherever you keep your scripts */
el = document.createElement('script'),
attrs = {
defer: true,
src: null,
type: 'text/javascript'
};
/** look for a string based, protocol agnostic, js file url */
if (typeof fullPath === 'string' && fullPath.indexOf('http') === 0) {
attrs.src = fullPath;
}
/** look for any string with at least 1 character and prefix our root js dir, then append extension */
if (typeof url === 'string' && url.length >= 1) {
attrs.src = PATH + url + '.js';
}
setAtt = setAttributes(el,attrs);
el.addEventListener('load', function (event) {
if (event) {
/* status is good */
}
else {
/* status is bad */
}
}, false);
document.body.appendChild(el);
return el;
};
I want to create some kind of sitemap in extbase/fluid (based on the pagetree). I have loaded the pages table into a model:
config.tx_extbase.persistence.classes.Tx_MyExt_Domain_Model_Page.mapping.tableName = pages
I have created a controller and repository, but get stuck on the part wich can load the subpages as relation into my model.
For example:
$page = $this->pageRepository->findByPid($rootPid);
Returns my rootpage. But how can I extend my model that I can use $page->getSubpages() or $page->getNestedPages()?
Do I have to create some kind of query inside my model? Or do I have to resolve this with existing functions (like the object storage) and how?
I tried a lot of things but can simply figure out how this should work.
you have to overwrite your findByPid repository-method and add
public function findByPid($pid) {
$querySettings = $this->objectManager->create('Tx_Extbase_Persistence_Typo3QuerySettings');
$querySettings->setRespectStoragePage(FALSE);
$this->setDefaultQuerySettings($querySettings);
$query = $this->createQuery();
$query->matching($query->equals('pid', $pid));
$pages = $query->execute();
return $pages;
}
to get all pages. Than you can write your own getSubpages-method like
function getSubpages($currentPid) {
$subpages = $this->pagesRepository->findByPid($currentPid);
if (count($subpages) > 0) {
$i = 0;
foreach($subpages as $subpage) {
$subpageUid = $subpage->getUid();
$subpageArray[$i]['page'] = $subpage;
$subpageArray[$i]['subpages'] = $this->getSubpages($subpageUid);
$i++;
}
} else {
$subpageArray = Array();
}
return $subpageArray;
}
i didn't test this method, but it looks like this to get alle subpages.
i wonder that i couldĀ“t find a typo3 method that return the complete Page-Tree :( So i write a little function (you can use in an extbase extension), for sure not the best or fastes way, but easy to extend or customize ;)
first you need an instance of the PageRepository
$this->t3pageRepository = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Frontend\\Page\\PageRepository');
this->t3pageRepository->init();
make the init, to set some basic confs, like "WHERE deletet = 0 AND hidden = 0..."
then with this function you get an array with the page data and subpages in. I implement yust up to three levels:
function getPageTree($pid,$deep=2){
$fields = '*';
$sortField = 'sorting';
$pages = $this->t3pageRepository->getMenu($pid,$fields,$sortField);
if($deep>=1){
foreach($pages as &$page) {
$subPages1 = $this->t3pageRepository->getMenu($page['uid'],$fields,$sortField);
if(count($subPages1)>0){
if($deep>=2){
foreach($subPages1 as &$subPage1){
$subPages2 = $this->t3pageRepository->getMenu($subPage1['uid'],$fields,$sortField);
if(count($subPages2>0)){
$subPage1['subpages'] = $subPages2;
}
}
}
$page['subpages'] = $subPages1;
}
}
}
return $pages;
}
I'm trying to get a different session configuration for 2 modules.
In my application ini i have a modules set up like :
resources.modules[] =
resources.frontcontroller.moduleDirectory = APPLICATION_PATH "/modules"
resources.frontcontroller.throwerrors = true
resources.layout.layout = "layout"
and for the sessions
resources.session.save_path = APPLICATION_PATH "/temp/session"
resources.session.use_cookies = true
resources.session.use_only_cookies = true
resources.session.gc_maxlifetime = 3600
resources.session.remember_me_seconds = 3600
resources.session.name = "sid"
resources.session.gc_probability = 1
backoffice.resources.session.save_path = APPLICATION_PATH "/temp/bo/session"
backoffice.resources.session.use_cookies = true
backoffice.resources.session.use_only_cookies = true
backoffice.resources.session.gc_maxlifetime = 3600
backoffice.resources.session.remember_me_seconds = 3600
backoffice.resources.session.name = "BOsid"
backoffice.resources.session.gc_probability = 1
but when i go the backoffice module i still have my default configuraton
Any idea what should be the best way to get different sessions for different modules ?
Thanks
I want to advise you another method of config customization for specific modules in ZF:
1. Create for each module config file: /modules/$moduleName/configs/module.ini
2. Add to the root Bootstrap the next code:
protected function _initBootstrap()
{
$_conf = new Zend_Config_Ini(APPLICATION_PATH . "/modules/" . $this->getModuleName() . "/configs/module.ini", APPLICATION_ENV);
$this->_options = array_merge($this->_options, $_conf->toArray());
}
I finally opted for a controller plug-in.
With some code like
class App_Controller_Plugin_Session extends Zend_Controller_Plugin_Abstract
{
public function routeShutdown(Zend_Controller_Request_Abstract $request)
{
$config = Zend_Registry::get('config')->toArray();
if( $this->getRequest()->getModuleName() == 'backoffice' ) {
$conf = $config['sessionBackoffice'];
} else {
$conf = $config['sessionDefault'];
}
Zend_Session::setOptions($conf);
Zend_Session::start();
}
}
The plugin need to be added at first in the registerPlugin stack if you some other plugin that require sessions.
If you have a better solution i'm open.