Bernd Wilke πφ
Bernd Wilke πφ

Reputation: 10791

How can I enhance fe_users in TYPO3?

I want to build a phone book based on the table fe_users.

So I used the EXT:extensionbuilder to enhance the table by some fields. with that stub I tried to build some lists (multiple views with different grouping and ordering) and a detail view.

While the additional fields are inserted in the data base and a plugin is available from the extensionbuilder generated code I have big problems to get the views working.

At first the list-view missed a lot. I added control for startpage and recursion depth and added these paramters to the findAll() method of the repository.

As the generated code does not work in any way I had to replace it completely and needed to insert all given fields also in my inherited domain model (just a declaration was needed, no getter() or setter())

Now I want to make the detail view (showaction) work.

Therefore I need to insert working code in findByUid() of the repository class. As expected from the list view experience the generated code did not work either.

first error:

(1/2) #1297759968 TYPO3\CMS\Extbase\Property\Exception

Exception while property mapping at property path "": It is not allowed to map property "address". 
You need to use $propertyMappingConfiguration->allowProperties('address') to enable mapping of this property.

as the error repeated for every field I inserted:

    public function initializeShowAction() {
        $propertyMappingConfiguration = $this->arguments['phonebookItem']->getPropertyMappingConfiguration();
        // allow all properties:
        $propertyMappingConfiguration->allowAllProperties();
        $propertyMappingConfiguration->allowCreationForSubProperty('Tx_Phonebook_PhonebookItem');
        // or just allow certain properties
        //$propertyMappingConfiguration->allowProperties('address');
    }

in my inherited repository.

Now my error is:

(1/2) #1297759968 TYPO3\CMS\Extbase\Property\Exception

Exception while property mapping at property path "": Creation of objects not allowed. 
To enable this, you need to set the PropertyMappingConfiguration Value "CONFIGURATION_CREATION_ALLOWED" to TRUE

I have no hint where to set this value.


Any help welcome. even a complete alternative for displaying.

I'm stuck to fe_useres as it is the only way to get the data from the AD, where the information is stored. Otherwise I need an additional importer to get the data from the AD into other records.


EDIT: my files

Classes/Controller/PhonebookItemController.php:

<?php
namespace Vendor\Phonebook\Domain\Model;

/**
 * PhonebookItem
 */
class PhonebookItem extends \TYPO3\CMS\Extbase\Domain\Model\FrontendUser
{
// Declaration of all new fields and their getter and setter
// like:

    /**
     * office
     * 
     * @var string
     */
    protected $office = '';
    /**
     * Returns the office
     * 
     * @return string $office
     */
    public function getOffice()
    {
        return $this->office;
    }

    /**
     * Sets the office
     * 
     * @param string $office
     * @return void
     */
    public function setOffice($office)
    {
        $this->office = $office;
    }

// meanwhile additional: declaration of all fields of the core fields to table fe_users
// like:
    /**
     * @var string
     */
    protected $name = '';
}

Classes/Domain/Repository/PhonebookItemRepository.php:

<?php

namespace Vendor\Phonebook\Domain\Repository;

use Vendor\Phonebook\Domain\Model\PhonebookItem;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Persistence\QueryInterface;
use TYPO3\CMS\Extbase\Persistence\QueryResultInterface;
use TYPO3\CMS\Extbase\Persistence\Repository;
use TYPO3\CMS\Core\Database\ConnectionPool;

/**
 * Class PhonebookItemRepository
 */
class PhonebookItemRepository extends Repository
{

    public function __construct(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager = NULL) {
        if (!$objectManager) {
            $objectManager = GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\Object\ObjectManager::class);
        }
        $this->objectType = Vendor\Phonebook\Domain\Model\PhonebookItem::class;
        parent::__construct($objectManager);
    }

    public function findAll($startPage = 0,$recursive = 0)
    {

        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('fe_users');

        $pidList = $startPage;

        if ($recursive) {
            $queryGenerator = $this->objectManager->get('TYPO3\\CMS\\Core\\Database\\QueryGenerator');
            $pidList = $queryGenerator->getTreeList($startPage, $recursive, 0, '1');
        }

        $rows = $queryBuilder
            // Select one ore more fields …
            ->select('*')
            // … from a table …
            ->from('fe_users')
            // … that fits into this condition.
            ->where(
            // This looks a bit strange, but ensures that the condition is coded in the most suitable way for the database.
                $queryBuilder->expr()->in('pid', $pidList, true)
            )
            ->orderBy('username', 'ASC')
            ->orderBy('name','ASC')
            ->orderBy('first_name','ASC')
            ->orderBy('last_name','ASC')
            // Run the query …
            ->execute()
            // … and fetch all results as an associative array.
            ->fetchAll();

        return $rows;

        /* == Original code from ExtensionBuilder: ==
        $this->objectType = Vendor\Phonebook\Domain\Model\PhonebookItem::class;
        $query = $this->createQuery();
        $this->ignoreEnableFieldsAndStoragePage($query);
        $query->getQuerySettings()->setRespectSysLanguage(false);
        //$and = [$query->equals('uid', $uid)];

        /// @var PhonebookItem $phonebookItem
        $phonebookItems = $query
//          ->matching($query->logicalAnd($and))
            ->execute();

        return $phonebookItems;
        */
    }
}

/Classes/Controller/PhonebookitemController.php:

<?php
namespace Vendor\Phonebook\Controller;

use Vendor\phonebook\Domain\Repository\PhonebookItemRepository;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;

/**
 * PhonebookItemController
 */
class PhonebookItemController extends ActionController
{
    public $phonebookItemRepository;
    public $cobj = NULL;

    public $startPage;
    public $recursive;

    public function __construct() {
        $this->phonebookItemRepository = GeneralUtility::makeInstance(\Vendor\Phonebook\Domain\Repository\PhonebookItemRepository::class);
    }

    /**
     * action list
     * 
     * @return void
     */
    public function listAction()
    {
        $this->cObj = $this->configurationManager->getContentObject();

        $this->startPage = ($this->settings['pages'    ] ?? $this->cObj->data['pages'    ]) ?? $this->cObj->data['pid'];
        $this->recursive = ($this->settings['recursive'] ?? $this->cObj->data['recursive']) ?? 0;

        switch ($this->settings['plugintype']) {
            case 'listemployee':
                $this->listEmployeeAction();
                break;
            case 'listoffice':
                $this->listOfficeAction();
                break;

            default:
                $phonebookItems = $this->phonebookItemRepository->findAll($this->startPage, $this->recursive);
                $this->view->assign('phonebookItems', $phonebookItems);
                break;
        }
    }

    public function initializeShowAction() {
        $propertyMappingConfiguration = $this->arguments['phonebookItem']->getPropertyMappingConfiguration();
        // allow all properties:
        $propertyMappingConfiguration->allowAllProperties();
        $propertyMappingConfiguration->allowCreationForSubProperty('Tx_Phonebook_PhonebookItem');
        // or just allow certain properties
        //$propertyMappingConfiguration->allowProperties('address');
    }
    /**
     * action show
     * 
     * @param \Vendor\Phonebook\Domain\Model\PhonebookItem $phonebookItem
     * @return void
     */
    public function showAction(\Itkr\Phonebook\Domain\Model\PhonebookItem $phonebookItem)
    {
        $this->view->assign('phonebookItem', $phonebookItem);
    }

    /**
     * action listEmployee
     * 
     * @return void
     */
    public function listEmployeeAction()
    {
        $phonebookItems = $this->phonebookItemRepository->findAll($this->startPage, $this->recursive);
        $this->view->assign('phonebookItems', $phonebookItems);
    }

    /**
     * action listOffice
     * 
     * @return void
     */
    public function listOfficeAction()
    {
        $phonebookItems = $this->phonebookItemRepository->findAll($this->startPage, $this->recursive);
        $this->view->assign('phonebookItems', $phonebookItems);
    }
}

Solution:

As Daniel mentioned:
the parameter of the detail-/show-link were false.
After changing the url to the correct format (<f:variable name="showUrl" value="{f:uri.action(action:'show',arguments:{phonebookItem : entry.uid})}" />) all the additional methods and variable declarations were no longer necessary.

Upvotes: 0

Views: 417

Answers (2)

Krzysztof Kasprzyca
Krzysztof Kasprzyca

Reputation: 121

I think you should extend frontend user model with Typoscript configuration and then adjust model, repository and create controller for phonebook items. Example: https://extcode.github.io/cart_snippets/posts/how-to-extend-product-models-part-one

Upvotes: 0

Daniel
Daniel

Reputation: 1085

The mentioned behavior is a security mechanism of Extbase. Extbase will not allow to modify data of an stored record through GET requests.

You call the showAction probably by GET request method and submit the data. They are not allowed to be mapped, and that is a good thing. The bad thing is that you need to figure out why those fields are submitted through the request.

So the issue is your template, or wherever you build the request / url.

There is no need for your initializeAction.

Also don't build custom logic for storagePid, stick to existing fields in tt_content and extbase will respect them out of the box.

Upvotes: 1

Related Questions