Why is my Joomla user plugin not called? - plugins

I've written a small user plugin for Joomla! that should change the return url on logging in depending on the user's group. However, it's not even being called. What am I doing wrong?
class plgUserPluginName extends JPlugin
{
/**
* This method should handle any login logic and report back to the subject
*
* #param array $user Holds the user data
* #param array $options Array holding options (remember, autoregister, group)
*
* #return boolean True on success
* #since 1.5
*/
public function onUserLogin($user, $options = array())
{
$user = JFactory::getUser();
$db = JFactory::getDBO();
$db->setQuery(
'SELECT link_id FROM '.$db->quoteName('#__mt_links') .
' WHERE '.$db->quoteName('user_id').' = '.$db->quote($user->id)
);
$link_id = $db->loadResult();
if(!$link_id){
$db->setQuery(
'SELECT group_id FROM '.$db->quoteName('#__user_usergroup_map') .
' WHERE '.$db->quoteName('user_id').' = '.$db->quote($user->id)
);
$group_id = $db->loadResult();
if($group_id == somegroupid) $options['return'] = 'abc';
elseif($group_id == someothergroupid) $options['return'] = 'xyz';
}
return true;
}
}
My xml is:
<?xml version="1.0" encoding="utf-8"?>
<extension version="2.5" type="plugin" group="user">
<name>plg_user_pluginname</name>
<version>1.0.0</version>
<description>PLG_USER_PLUGINNAME_XML_DESCRIPTION</description>
<files>
<filename plugin="pluginname">pluginname.php</filename>
<filename>index.html</filename>
</files>
<languages>
<language tag="en-GB">en-GB.plg_user_pluginname.ini</language>
<language tag="en-GB">en-GB.plg_user_pluginname.sys.ini</language>
</languages>
<config>
</config>
</extension>

I am not sure which of the following two solved it, but
a) I renamed my plugin to plgUserPluginname instead of plgUserPluginName (small n for name)
b) I changed accessibility from Registered to Public
and it's being called now!

Related

How to upload a file with TYPO3 Fluid form.upload and pass it to Extbase controller

I am using the form.upload ViewHelper to upload a file.
<f:form enctype="multipart/form-data" action="list" name="import" object="{import}" method="POST">
<f:form.upload name="file" property="file" />
<f:form.submit value="Submit" />
</f:form>
The problem is accessing the file. The $import object contains a file name but the file does not exist.
My problem was, that the file was deleted already when it was handled. I redirected to another action in my controller action and this started a new request.
$this->redirect('list', $import);
The file will be deleted from the temporary directory at the end of the request if it has not been moved away or renamed.
(https://www.php.net/manual/en/features.file-upload.post-method.php)
How file is uploaded is not TYPO3 specific and can be handled differently, see link above.
You should also set the temporary path accordingly, see link above.
file types can be restricted with accept, e.g. accept='text/csv'
I am using this in a backend module. The following code works.
Fluid
<f:form enctype="multipart/form-data" action="create" name="import" object="{import}" method="POST">
<f:form.upload name="file" property="file" />
<f:form.submit value="Submit" />
</f:form>
Model class: Import.php
class Import extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity
{
/** #var array */
protected $file = [];
/**
* #return array
*/
public function getFile()
{
return $this->file;
}
/**
* #param array $file
* #return void
*/
public function setFile(array $file)
{
$this->file = $file;
}
}
Controller createAction()
/**
* #param Import $import
* #return void
*/
public function createAction(Import $import)
{
$file = $import->getFile();
if ($file) {
$path = $file['tmp_name'];
}
// ...
}
The action gets called with Import object containing a file property with correctly filled out metadata, e.g.
['name'] = myfile.csv
['type'] = 'text/csv'
['tmp_name'] = '/tmp/hpGLv1E'
['error'] = 0
['size'] = 51550

Sort by price low to high and high to low in product listing magento2

I am new in Magento 2. I am using Magento 2.1.1
I want to add custom price low to high and price high to low in Sort By dropdown in product listing page.
I didn't get toolbar.phtml page. Also I didn't get any stuff regarding this in google.
Step 1: Create plugins in
app/code/Vendor/Module/etc/di.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<type name="Magento\Catalog\Block\Product\ProductList\Toolbar">
<plugin name="custom_custom_block_toolbar" type="Vendor\Module\Plugin\Catalog\Block\Toolbar" />
</type>
<type name="Magento\Catalog\Model\Config">
<plugin name="custom_catalog_model_config" type="Vendor\Module\Plugin\Catalog\Model\Config" />
</type>
</config>
Step 2: Create Config.php in
app/code/Vendor/Module/Plugin/Catalog/Model/Config.php
<?php
namespace Vendor\Module\Plugin\Catalog\Model;
class Config
{
public function afterGetAttributeUsedForSortByArray(
\Magento\Catalog\Model\Config $catalogConfig,
$options
) {
$options['low_to_high'] = __('Price - Low To High');
$options['high_to_low'] = __('Price - High To Low');
return $options;
}
}
Step 3: Create Toolbar.php in
app/code/Vendor/Module/Plugin/Catalog/Block/Toolbar.php
<?php
namespace Vendor\Module\Plugin\Catalog\Block;
class Toolbar
{
/**
* Plugin
*
* #param \Magento\Catalog\Block\Product\ProductList\Toolbar $subject
* #param \Closure $proceed
* #param \Magento\Framework\Data\Collection $collection
* #return \Magento\Catalog\Block\Product\ProductList\Toolbar
*/
public function aroundSetCollection(
\Magento\Catalog\Block\Product\ProductList\Toolbar $subject,
\Closure $proceed,
$collection
) {
$currentOrder = $subject->getCurrentOrder();
$result = $proceed($collection);
if ($currentOrder) {
if ($currentOrder == 'high_to_low') {
$subject->getCollection()->setOrder('price', 'desc');
} elseif ($currentOrder == 'low_to_high') {
$subject->getCollection()->setOrder('price', 'asc');
}
}
return $result;
}
}

How to get value from FlexForm to Controller

I'm practicing on a very easy Extbase Extension and used a FlexForm to get three formula fields.
One of them is called "code" which should go to the EmbedderController.php and then to the viewer List.html.
I checked all tutorials I could find.
I don't understand how to get the FlexForm-value "code" into my Controller.
I get an empty page or don't get any value.
This is my FlexForm: Embedder.xml
<T3DataStructure>
<meta type="array">
<langChildren>0</langChildren>
<langDisable>1</langDisable>
</meta>
<ROOT>
<type>array</type>
<el>
<settings.code>
<TCEforms>
<label>Video Code</label>
<config>
<type>input</type>
<size>20</size>
<max>30</max>
<eval>trim</eval>
</config>
</TCEforms>
</settings.code>
<settings.width>
<TCEforms>
<exclude>1</exclude>
<label>Breite in Pixel</label>
<config>
<type>input</type>
<size>10</size>
<max>10</max>
<eval>trim</eval>
</config>
</TCEforms>
</settings.width>
<settings.height>
<TCEforms>
<exclude>1</exclude>
<label>Höhe in Pixel</label>
<config>
<type>input</type>
<size>10</size>
<max>10</max>
<eval>trim</eval>
</config>
</TCEforms>
</settings.height>
</el>
</ROOT>
</T3DataStructure>
And this is my EmbedderController.php
<?php
namespace HhuMediathek\Hhumediathek\Controller;
/**
* EmbedderController
*/
class EmbedderController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionController {
/**
* embedderRepository
*
* #var \HhuMediathek\Hhumediathek\Domain\Repository\EmbedderRepository
* #inject
*/
protected $embedderRepository = NULL;
/**
* action list
*
* #return void
*/
public function listAction() {
$this->settings['code'];
}
}
And this is the viewer List.html
<f:layout name="Default" />
<f:section name="main">
<iframe width='570' height='321' style='width: 570px; height: 321px; border: 1px solid #ccc;' src='//xxx.de/embed/{code}' frameborder='0' allowfullscreen></iframe>
</f:section>
Okay I could figure it out myself. For people who struggle with the same problem as I did:
My mistake was, that I didn't need the line $this->settings['code']; in the Controller at all but write {settings.code} in the viewer List.html instead of just {code}. It's completly different than I read it in my book and some tutorials but this actually worked.
The assignment of the view parameter is missing. Therefore change
public function listAction() {
$this->settings['code'];
}
to
public function listAction() {
$this->view->assign('code', $this->settings['code']);
}
This way {code} should be available in the view.
I want not to be restricted to settings.*. I use the following script in my controller.
/** #var ContentObjectRenderer $content */
$content = $this->configurationManager->getContentObject();
$flexFormString = $content->data['pi_flexform'];
$flexFormRaw = GeneralUtility::xml2array($flexFormString);
if (is_callable([FlexformUtilities::class,'arrayFlatten'])) {
$flexFormSimple = FlexformUtilities::arrayFlatten( $flexFormRaw); // second Param is ['data','sDEF','lDEF','vDEF']
$referenceUidsList = $flexFormSimple['referenceList'];
} else {
$referenceUidsList = (int)$flexFormRaw['data']['sDEF']['lDEF']['referenceList']['vDEF'];
}
The Utilities-Class contains the following flattenArray-method
protected const DEFAULT_FLATTEN_KEYS = ['data','sDEF','lDEF','vDEF'];
/**
* https://stackoverflow.com/questions/1319903/how-to-flatten-a-multidimensional-array
*
* #param array $listFlatKeys
* #param $array
* #return array
*/
public static function arrayFlatten( $array, &$listFlatKeys = self::DEFAULT_FLATTEN_KEYS)
{
if (!is_array($array)) {
return $array;
}
if (count($array) === 1) {
$key = array_key_first($array);
$value = self::arrayFlatten( $array[$key],$listFlatKeys);
if (in_array($key, $listFlatKeys)) {
return $value;
} else {
return [$key => $value];
}
}
$return = [];
foreach ($array as $key => $value) {
if (in_array($key, $listFlatKeys)) {
$return[] = self::arrayFlatten( $value, $listFlatKeys);
} else {
$return[$key] = self::arrayFlatten( $value, $listFlatKeys);
}
}
return $return;
}
I use it although in a Alias-similiar viewhelper, to get information of a flex-field in the frontend.

how to: use Tx_Extbase_Domain_Repository_FrontendUserRepository in typo3 v4.5

I am trying to read the username of a front end user whose uid is known. I tried this in my controller's showAction method:
$objectManger = t3lib_div::makeInstance('Tx_Extbase_Object_ObjectManager');
// get repository
$repository = $objectManger->get('Tx_Extbase_Domain_Repository_FrontendUserRepository ');
$newObject = $repository->findByUid($coupon->getCreator()); //this is the uid of whoever was loggin in
print_r($newObject);
echo $newObject->getUsername(); die;
but when that code runs I get:
Oops, an error occured!
"Tx_Extbase_Domain_Repository_FrontendUserRepository " is not a valid cache entry identifier.
It turns out that $repository is empty, so how do I get fe_user data?
I am using typo3 v4.5 with extbase.
Thanks
Update to show complete answer.
This is the code (it goes in my CouponController) that worked (plus the typoscript mentioned):
/**
* #var Tx_Extbase_Domain_Repository_FrontendUserRepository
*/
protected $userRepository;
/**
* Inject the user repository
* #param Tx_Extbase_Domain_Repository_FrontendUserRepository $userRepository
* #return void */
public function injectFrontendUserRepository(Tx_Extbase_Domain_Repository_FrontendUserRepository $userRepository) {
$this->userRepository = $userRepository;
}
public function showAction(Tx_Coupons_Domain_Model_Coupon $coupon) {
$userRepository = $this->objectManager->get("Tx_Extbase_Domain_Repository_FrontendUserRepository");
$newObject = $userRepository->findByUid($coupon->getCreator());
$this->view->assign('coupon', $coupon);
$this->view->assign('creatorname', $newObject->getUsername() );
}
If you are using extbase yourself you dont have to call makeInstance for your objectManager, it's already there ($this->objectManager).
anyway, you should inject this repository (see my answer here: TYPO3 - Call another repository)
Clear the Cache after the Injection.
You maybe have to disable the recordtype extbase sets for its FrontendUser:
config.tx_extbase.persistence.classes.Tx_Extbase_Domain_Model_FrontendUser.mapping.recordType >
Set the source storage pid where the repository fetches the data from:
/** #var Tx_Extbase_Domain_Repository_FrontendUserRepository $repos */
$repos = $this->objectManager->get("Tx_Extbase_Domain_Repository_FrontendUserRepository");
$querySettings = $repos->createQuery()->getQuerySettings();
$querySettings->setStoragePageIds(array(123, 567));
$repos->setDefaultQuerySettings($querySettings);
$user = $repos->findByUid(56); // Queries for user 56 in storages 123 and 567

Zend Enable SQL Query logging

I am using this to retrieve the database connection atm.
$db = Zend_Db_Table::getDefaultAdapter();
I do set this up in my config like this:
resources.db.adapter = pdo_mysql
resources.db.isDefaultTableAdapter = true
resources.db.params.host = localhost
resources.db.params.username = root
resources.db.params.password = password
resources.db.params.dbname = db
resources.db.params.profiler.enabled = true
resources.db.params.profiler.class = Zend_Db_Profiler
I would like to output everything to a sql.log for example. Is this possible to apply on the default adapter? for example through the settings, so I can ignore it in production environment?
Much appriciated.
I did look at: How to enable SQL output to log file with Zend_Db? but it didn't seem to cover my issue.
/Marcus
There is an example of extending Zend_Db_Profiler so you can write the queries to /logs/db-queries.log file.
So you have to do the following:
Create My_Db_Profiler_Log class in the library folder
Add the following lines to the application.ini
resources.db.params.profiler.enabled = true
resources.db.params.profiler.class = My_Db_Profiler_Log
Note: be aware, that the log file will become very big, very soon! So it is a good idea to log only the queries you are interested in. And this example should be considered only as a starting point in implementation of such a logging system.
Here is the code for the custom profiler class:
<?php
class My_Db_Profiler_Log extends Zend_Db_Profiler {
/**
* Zend_Log instance
* #var Zend_Log
*/
protected $_log;
/**
* counter of the total elapsed time
* #var double
*/
protected $_totalElapsedTime;
public function __construct($enabled = false) {
parent::__construct($enabled);
$this->_log = new Zend_Log();
$writer = new Zend_Log_Writer_Stream(APPLICATION_PATH . '/logs/db-queries.log');
$this->_log->addWriter($writer);
}
/**
* Intercept the query end and log the profiling data.
*
* #param integer $queryId
* #throws Zend_Db_Profiler_Exception
* #return void
*/
public function queryEnd($queryId) {
$state = parent::queryEnd($queryId);
if (!$this->getEnabled() || $state == self::IGNORED) {
return;
}
// get profile of the current query
$profile = $this->getQueryProfile($queryId);
// update totalElapsedTime counter
$this->_totalElapsedTime += $profile->getElapsedSecs();
// create the message to be logged
$message = "\r\nElapsed Secs: " . round($profile->getElapsedSecs(), 5) . "\r\n";
$message .= "Query: " . $profile->getQuery() . "\r\n";
// log the message as INFO message
$this->_log->info($message);
}
}
?>
Extend the Zend_Db_Profiler to write to an SQL.log and attach the profiler to your db adapter
<?php
class File_Profiler extends Zend_Db_Profiler {
/**
* The filename to save the queries
*
* #var string
*/
protected $_filename;
/**
* The file handle
*
* #var resource
*/
protected $_handle = null;
/**
* Class constructor
*
* #param string $filename
*/
public function __construct( $filename ) {
$this->_filename = $filename;
}
/**
* Change the profiler status. If the profiler is not enabled no
* query will be written to the destination file
*
* #param boolean $enabled
*/
public function setEnabled( $enabled ) {
parent::setEnabled($enabled);
if( $this->getEnabled() ) {
if( !$this->_handle ) {
if( !($this->_handle = #fopen($this->_filename, "a")) ) {
throw new Exception("Unable to open filename {$this->_filename} for query profiling");
}
}
}
else {
if( $this->_handle ) {
#fclose($this->_handle);
}
}
}
/**
* Intercept parent::queryEnd to catch the query and write it to a file
*
* #param int $queryId
*/
public function queryEnd($queryId) {
$state = parent::queryEnd($queryId);
if(!$this->getEnabled() || $state == self::IGNORED) {
return;
}
$profile = $this->getQueryProfile($queryId);
#fwrite($this->_handle, round($profile->getElapsedSecs(),5) . " " . $profile->getQuery() . " " . ($params=$profile->getQueryParams())?$params:null);
}
}
Haven't test it, but it should do the trick. Give it a try and let me know.
Btw you do know that you can log all queries on the mysql as well?
this will let you see sql queries to the web page , IT MIGHT BE OFF TOPIC but it helpful
I am highly recommend you to use ZF debug bar , it will give you very handy information
i am using it to see my doctrine queries , and it had support for zend db too
https://github.com/jokkedk/ZFDebug