Call to private PHPExcel_IOFactory::__construct() from context - TYPO3 - typo3

Hi have to create an excel export using phpexcel library. So I copy the library in my class then write the following code in my controller
require_once PATH_site . 'typo3conf/ext/extension_name/Classes/Library/PHPExcel/IOFactory.php';
public function excelTest()
{
$objectManager = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\CMS\Extbase\Object\ObjectManager');
$objReader = $objectManager->get('PHPExcel_IOFactory');
}
But it return an error
Fatal error: Call to private PHPExcel_IOFactory::__construct() from
context 'TYPO3\CMS\Core\Utility\GeneralUtility' in
/opt/lampp_repository/lampp-5.6/htdocs/typo3_src-7.6.6/typo3/sysext/core/Classes/Utility/GeneralUtility.php
on line 4533

Don't include the library yourself, TYPO3 has dependency injection for that. All the php files in your Extension directory will be indexed, and all Classes inside will automatically be available, you just have to make sure, that your class cache is fresh, if in doubt by manually deleting the typo3temp/Cache/Code/ClassLoader* file.
If you want to include en external class into your own namespace, you have to hint Extbase as to how to include it, with an ext_autoload.php file, because if multiple extensions load code into the same class namespace they will collide.
It also is good practice not to inject the class itself, but an Abstrct that extends upon it, so you can customize it in an isolated manner that doesn't modify the vendor files.
Heres my approach to it:
Put all files of PHPExcel into yourextension/Classes/Vendor/PHPExcel.
Create a new file yourextension/Classes/Vendor/PHPExcel.php:
<?php
namespace Vendorname\Extensionname\Classes;
/*
* PhpExcel
*/
class PhpExcel implements \TYPO3\CMS\Core\SingletonInterface extends \PHPExcel {
// Differences from the original implementation, e.g. a writer that generates
// a filename and puts the Excel file into typo3temp
}
You should then be able to just inject the class #inject-Annotation in your ActionController:
/**
* PhpExcel
*
* #var \Vendorname\Extensionname\Classes\PhpExcel
* #inject
*/
protected $phpExcel;
Further reading:
https://wiki.typo3.org/Dependency_Injection
https://docs.typo3.org/typo3cms/CoreApiReference/ApiOverview/Autoloading/Index.html

Related

How to change the position of a column in the TYPO3 TCA?

I want to move a column from one tab to another. Is there a better way than to rewrite the types definition manually which is not very reliant in regard to extension updates changing the TCA?
It's not 100% fail safe, since there still might be extensions messing things up, but the closest you can get will be to make use of the ExtTablesInclusionPostProcessing event and put addToAllTCAtypes into the invoke method, since this will not just add new fields but even put existing fields to another tab:
<?php
declare(strict_types=1);
namespace Vendor\Extension\EventListener;
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
/**
* Class ExtTablesInclusionPostProcessing
*/
class ExtTablesInclusionPostProcessing
{
/**
* Function which may process data created / registered by extTables
* scripts (f.e. modifying TCA data of all extensions)
*
* #param AfterTcaCompilationEvent $event
*/
public function __invoke(AfterTcaCompilationEvent $event): void
{
ExtensionManagementUtility::addToAllTCAtypes('tt_content', 'fieldname', '', 'after:fieldname_in_the_other_tab');
}
}
To remove the existing field before, you could make use of this trick:
https://stackoverflow.com/a/59179916/2333754
And finally to be on the safer side you could make sure that other extensions are loaded before your own extension by putting them into the suggest section of your composer.json.
With installation of extension tcabuilder it is possible to do simple changes in the TCA.

TYPO3 queryBuilder, how to let PhpStorm recognise methods?

For example
$connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
$queryBuilder = $connectionPool->getQueryBuilderForTable($table);
$statement = $queryBuilder
->select('uid')
->from($table)
->orderBy('start_date', 'DESC')
->where(
$queryBuilder->expr()->lte('start_date', $queryBuilder->createNamedParameter($startDate, \PDO::PARAM_INT)),
$queryBuilder->expr()->neq('uid', $queryBuilder->createNamedParameter($currentUid, \PDO::PARAM_INT))
)
->setMaxResults(1)
->execute();
while ($row = $statement->fetch()) {
$prevs[] = $row;
}
How can one let PhpStorm recognise the methods select, expr, createNamedParameter, fetch etc.
PhpStorm doesn't automatically know what class $connectionPool is and so can't know what class everything derived from that is. You can tell PhpStorm what class $connectionPool is by adding an annotation:
/** #var ConnectionPool $connectionPool */
$connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
If you use the TYPO3 Plugin for PhpStorm, it's able to get the correct information from makeInstance() (and many more features).
https://plugins.jetbrains.com/plugin/9496-typo3-cms-plugin
You can do 2 steps to help PhpStorm recognise functions outside of your project:
Annotate the variables with their respective namespace:
/** #var $queryBuilder \TYPO3\CMS\Core\Database\Query\QueryBuilder **/
$queryBuilder = $connectionPool->getQueryBuilderForTable($table);
You can shorten the above when used multiple time with declaring:
use \TYPO3\CMS\Core\Database\Query\QueryBuilder;
at the top of your file, the you would just need
/** #var $queryBuilder QueryBuilder **/
As a second step include the Typo3 sources to your project (if they are not inclued in your project files already) so PhpStorm will be able to index them
I find that adding annotations for the variable type is unnecessary and just clutters up the source code.
In general, for PhpStorm to find the classes, methods etc. you have to include the TYPO3 source in your project.
You can create a PHP project which includes your entire web root (typically "public" folder), but excludes directories like filadmin, uploads, typo3temp etc. It is important to exclude these directories so PhpStorm does not unnecessarily scan them. (In particular if you run the core functional tests this is very much recommended.) I find this is the most practical approach and also useful for debugging and core development
You can create a PhpStorm project for your extension and include your TYPO3 source as well. Don't know about this off the top of my head, but should be possible.
Once you do this and PhpStorm scanned your files, it should be possible to do any of the following:
Auto-expand class and function names
Add use statements automatically (see PhpStorm help for more)
etc.
See also DynamicReturnType plugin and other plugins recommended for TYPO3 core development. The DynamicReturnType plugin along with the file dynamicReturnTypeMeta.json shipped with the core should give PhpStorm enough information for return type of classes instantiated with makeInstance for example.

How to register modules for advanced functions

When I select Web/Functions in the menu of typo3 cms 9.5.4 backend, I get this error:
Advanced functions
No modules have been registered. Please contact your system administrator.
I am the system administrator. I can't find anywhere how to register modules. How do I register any modules?
Like Peter wrote, the Extension func was removed from core, is actually not marked as compatible with version 9.5. and should avoided to use further more.
But follow two files will help you to register your own module:
ext/extension/ext_tables.php
// Module wizard
if (TYPO3_MODE === 'BE') {
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::insertModuleFunction(
'web_func',
\Vendor\Extension\MyModuleFunction::class,
null,
'LLL:EXT:extension/Resources/Private/Language/locallang_module.xlf:mymodulefunction'
);
}
ext/extension/Classes/MyModuleFunction.php
<?php
namespace Vendor\Extension;
class MyModuleFunction
{
/**
* Initialize the object
*
* #param \object $pObj A reference to the parent (calling) object
* #throws \RuntimeException
*/
public function init($pObj)
{
// Required method
}
/**
* Checking for first level external objects
*/
public function checkExtObj()
{
// Required method
}
/**
* Main function creating the content for the module.
*
* #return string HTML content for the module, actually a "section" made through the parent object in $this->pObj
*/
public function main()
{
return '<h1>My module function</h1>';
}
}
As far as I know, EXT:wizard_crpages and EXT:wizard_sortpages are not maintained anymore in TYPO3 9.x.
EXT:func has been moved to the TYPO3 Extension Repository to preserve the possibility to register your own wizards.
UPDATE:
The possibility to create multiple pages and to sort pages is now available via the context menu in the page tree. Just do a left or right click on the icon in front of any page and choose More options ... from the context menu.

Loading PHPExcel library in Zend Framework 2 only in current action

I would like to use PHPExcel library in a zend framework 2 project. But I don't want to load it for the overall project, just in one particular action. How can I do this?
If your PHPExcel library is load by composer.phar yo can access the class through:
$objPHPExcel = new \PHPExcel();
else, you must include path of your library before use :
/** Include path **/
ini_set('include_path', ini_get('include_path').';<relative directory path>/');
/** PHPExcel */
include 'PHPExcel.php';
$objPHPExcel = new PHPExcel();
To use PHPOffice/PHPExcel library into zend framework 2, you can use the zf2 module MvlabsPHPExcel.
Through composer:
$ php composer.phar require mvlabs/mvlabs-phpexcel
And after that you'll be able to use inside you controller particular action:
$phpExcelObject = $this->serviceLocator->get('mvlabs.phpexcel.service')->createPHPExcelObject();
I recommend to use dependency injection in your controller by injecting the 'mvlabs.phpexcel.service' as a controller dependency.

TYPO3: How to use storage pid from pagetree in backend module?

I created an extension using Extension Builder, and included a backend module, under the web section. In the generated code, there are two constants for the storage pid: one for plugins and one for modules.
Now I like my module to use the storage pid from the selected page or folder in the pagetree, like page, list, or template modules do. How can I use storage pid from pagetree instead of using a constant, in a backend module?
To get the selected page from the page tree in your backend module, one way is to simply get the id param, ideally in your initializer.
Since extbase reads the storage pid from your module (or plugin for the frontend) settings, you can just override the storagePid part so you don't have to set the pid for each query / otherwise in your repositories.
The following should work. However, I use this in a CommandController and not in a controller used in the backend. I hadn't to change anything there because the repositories automatically scoped records to the selected page.
class Tx_MyExt_Controller_BackendController extends Tx_Extbase_MVC_Controller_ActionController {
/**
* #var Tx_Extbase_Configuration_ConfigurationManagerInterface
* #inject
*/
protected $configurationManager;
/**
* #var int Current page
*/
protected $pageId;
/**
* Action initializer
*
* #return void
*/
protected function initializeAction()
{
$this->pageId = (int)t3lib_div::_GP('id');
$frameworkConfiguration = $this->configurationManager->getConfiguration(Tx_Extbase_Configuration_ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK);
$persistenceConfiguration = array('persistence' => array('storagePid' => $this->pageId));
$this->configurationManager->setConfiguration(array_merge($frameworkConfiguration, $persistenceConfiguration));
}
}