Skip to content

Instantly share code, notes, and snippets.

@iamandrewluca
Last active June 17, 2022 12:34
  • Star 17 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save iamandrewluca/7b9a7a3d5463f6f27f668eb2fcdda1ad to your computer and use it in GitHub Desktop.
typo3 extbase categories
<?php
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::makeCategorizable(
$_EXTKEY,
'tx_mymodels_domain_model_mymodel'
);
#
# Table structure for table 'tx_mymodels_domain_model_mymodel'
#
CREATE TABLE tx_mymodels_domain_model_mymodel (
categories int(11) unsigned DEFAULT '0' NOT NULL,
);

To use Extbase CategoryRepository, to work with Categories on our model we need to:

Add in ext_tables.sql, in our model, the categories field categories int(11) unsigned DEFAULT '0' NOT NULL, Make your model categorizable, by adding bellow snipet in ext_tables.php

\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::makeCategorizable(
    $_EXTKEY,
    'tx_mymodels_domain_model_mymodel'
);

Create own Category model and CategoryRepository by extending extabase Category and CategoryRepository

namespace MyVendor\MyModels\Domain\Model;
class Category extends \TYPO3\CMS\Extbase\Domain\Model\Category {}
namespace MyVendor\MyModels\Domain\Repository;
class CategoryRepository extends \TYPO3\CMS\Extbase\Domain\Repository\CategoryRepository {}

In your MyModelController inject CategoryRepository

/**
 * CategoryRepository
 *
 * @var \MyVendor\MyModels\Domain\Repository\CategoryRepository
 * @inject
 */
protected $categoryRepository = null;

Add to your model categories field with getters and setters

/**
 * categories
 *
 * @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\MyVendor\MyModels\Domain\Model\Category>
 * @lazy
 */
protected $categories;

/**
 * Get categories
 *
 * @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\MyVendor\MyModels\Domain\Model\Category>
 */
public function getCategories()
{
    return $this->categories;
}

/**
 * Set categories
 *
 * @param  \TYPO3\CMS\Extbase\Persistence\ObjectStorage $categories
 * @return void
 */
public function setCategories($categories)
{
    $this->categories = $categories;
}

In Configuration\TypoScript\setup.txt map back your model to extbase category table

plugin.tx_mymodels.persistence.classes {
	MyVendor\MyModels\Domain\Model\Category {
		mapping {
			recordType = 0
			tableName = sys_category
		}
	}
}

Use this way:

// gets all categories, all across the site
$categoryRepository->findAll();

// gets categories for this model
$myModel->getCategories();

// get all models for specific category
$collection = \TYPO3\CMS\Frontend\Category\Collection\CategoryCollection::load(
        $categoryId,
        TRUE,
        'tx_mymodels_domain_model_mymodel',
        'categories'
);

If you want to take categories records only from a sys folder you need to configure repository:

defaultQuerySettings->setRespectStoragePage(true)
defaultQuerySettings->setStoragePageIds($storagePageIds); 
<?php
/**
* categories
*
* \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\TYPO3\CMS\Extbase\Domain\Model\Category>
* @lazy
*/
protected $categories;
/**
* MyModel constructor.
*/
function __construct()
{
$this->categories = new ObjectStorage();
}
/**
* Get categories
*
* @return ObjectStorage<\TYPO3\CMS\Extbase\Domain\Model\Category>
*/
public function getCategories()
{
return $this->categories;
}
/**
* Set categories
*
* @param ObjectStorage $categories
* @return void
*/
public function setCategories($categories)
{
$this->categories = $categories;
}
@exotec
Copy link

exotec commented Jun 14, 2018

very useful. many thanks

@martin-eberle
Copy link

Very useful summary!

Is this still the recommended way to do it? Especially, where does the part from ext_tables.php now belong to since ext_tables.php is deprecated?

@stigfaerch
Copy link

@marteb
Put it in /Configuration/TCA/Overrides/tx_yourtable.php

@Schweriner
Copy link

You may add @var to line 5 of MyModel.php to prevent an error:

* @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\TYPO3\CMS\Extbase\Domain\Model\Category>

@izirikovic
Copy link

Really useful. Thank you.

One question: I implemented this into my custom extension, and everything seems to work fine. But, in some cases the error message appears in the frontend: 'ColumnMap for property "categories" of class "XXX" is missing'.
Think this line returns an error: "$constraints[] = $query->equals('categories.uid', intval($settings["categoriesList"]));"
Once the cache is cleared everything is working, but after few hours an error appear again.

In general, everything is implemented based on your example. Do you have any hint, how to resolve this issue?

@schnoedet
Copy link

Same here, works fine but after few hours the categories disappear. The error is: Could not find class definition for name "Vendor\Extname\Domain\Model\Category". After clearing the cache everything is ok. My Typoversion is 8.7.18

@ste101
Copy link

ste101 commented Mar 20, 2019

Thank you very much.

I got the problem that only uid and pid was set. Other fields where empty.
Than I changed all
<\MyVendor\MyModels\Domain\xxx\Categoryxxx>
to
\TYPO3\CMS\Extbase\Domain\xxx\Categoryxxx>
and removed Category model and CategoryRepository and it worked as expected.

@exotec
Copy link

exotec commented Mar 23, 2019

I got also a strange behaviour in TYPO3 8.7.24 like schnoedet describes above.
If no user is logged in the backend, the categories not shown in FE. After login to the backend and clear the caches the categories shown in FE. But after a while, again no categories are shown in the FE.

UPDATE

I have in the TCA of my model, for the field categories, implemented the code from Georg Ringers EXT:news and it works. I can clear the caches, log out from the BE and the categories are available in the FE.

        'categories' => [
            'exclude' => true,
            'label' => $ll . 'tx_news_domain_model_news.categories',
            'config' => [
                'type' => 'select',
                'renderType' => 'selectTree',
                'treeConfig' => [
                    'dataProvider' => \GeorgRinger\News\TreeProvider\DatabaseTreeDataProvider::class,
                    'parentField' => 'parent',
                    'appearance' => [
                        'showHeader' => true,
                        'expandAll' => true,
                        'maxLevels' => 99,
                    ],
                ],
                'MM' => 'sys_category_record_mm',
                'MM_match_fields' => [
                    'fieldname' => 'categories',
                    'tablenames' => 'tx_geevents_domain_model_event',
                ],
                'MM_opposite_field' => 'items',
                'foreign_table' => 'sys_category',
                'foreign_table_where' => ' AND (sys_category.sys_language_uid = 0 OR sys_category.l10n_parent = 0) ORDER BY sys_category.sorting',
                'size' => 10,
                'minitems' => 0,
                'maxitems' => 99,
                'behaviour' => [
                    'allowLanguageSynchronization' => true,
                ],
            ]
        ],

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment