TYPO3/Extbase How to create unique slug within create action? - typo3

I have slug field in my TCA and in general it works, when adding via Backend > List module, even if I won't input any value the unique eval ensures that slug will be unique, so when I'll create many rows with the same name Foo TYPO3 backend will enshure that it will resolve to unique slugs like foo, foo-1, foo-2, etc. Kudos!:
'slug' => [
'exclude' => true,
'label' => 'Slug',
'displayCond' => 'VERSION:IS:false',
'config' => [
'type' => 'slug',
'generatorOptions' => [
'fields' => ['name'],
'fieldSeparator' => '/',
'replacements' => [
'/' => '',
],
],
'fallbackCharacter' => '-',
'eval' => 'unique',
'default' => '',
'appearance' => [
'prefix' => \BIESIOR\Garage\UserFunctions\SlugPrefix::class . '->getPrefix'
],
],
],
However when creating a new object from my form within new/create actions (typical Extbase CRUD from extension_builder as you can see) like:
public function createAction(Car $newCar)
{
$this->addFlashMessage(
'The object was created. Please be aware that this action is publicly accessible unless you implement an access check. See https://docs.typo3.org/typo3cms/extensions/extension_builder/User/Index.html',
'',
\TYPO3\CMS\Core\Messaging\AbstractMessage::WARNING);
$this->carRepository->add($newCar);
$this->redirect('list');
}
of course slug is note set.
My first idea is to duplicate the logic of TCA type='slug' and just add this functionality with some own JS, AJAX and PHP, however that sounds as overload and time consumption. Especially that I don't want the user to care about slug part at all. Is there any simple API for lookup for a unique slug of the given table that can be used in custom action instead?
Note this question is not about how to handle it with JS, that's just concept. I would like to skip this part for FE user at all, he doesn't need to know what the slug is. Just during creating a new object, I want to get unique value like foo-123 instead.

In addition to Jonas Eberles answer here's another example which also respects the eval configuration of the slug field (can be uniqueInSite, uniqueInPid or simply unique).
use TYPO3\CMS\Core\DataHandling\Model\RecordStateFactory;
use TYPO3\CMS\Core\DataHandling\SlugHelper;
use TYPO3\CMS\Core\Utility\GeneralUtility;
...
public function createAction(Car $newCar)
{
$this->carRepository->add($newCar);
GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager::class)->persistAll();
$record = $this->carRepository->findByUidAssoc($newCar->getUid())[0];
$tableName = 'tx_garage_domain_model_car';
$slugFieldName = 'slug';
// Get field configuration
$fieldConfig = $GLOBALS['TCA'][$tableName]['columns'][$slugFieldName]['config'];
$evalInfo = GeneralUtility::trimExplode(',', $fieldConfig['eval'], true);
// Initialize Slug helper
/** #var SlugHelper $slugHelper */
$slugHelper = GeneralUtility::makeInstance(
SlugHelper::class,
$tableName,
$slugFieldName,
$fieldConfig
);
// Generate slug
$slug = $slugHelper->generate($record, $record['pid']);
$state = RecordStateFactory::forName($tableName)
->fromArray($record, $record['pid'], $record['uid']);
// Build slug depending on eval configuration
if (in_array('uniqueInSite', $evalInfo)) {
$slug = $slugHelper->buildSlugForUniqueInSite($slug, $state);
} else if (in_array('uniqueInPid', $evalInfo)) {
$slug = $slugHelper->buildSlugForUniqueInPid($slug, $state);
} else if (in_array('unique', $evalInfo)) {
$slug = $slugHelper->buildSlugForUniqueInTable($slug, $state);
}
$newCar->setSlug($slug);
$this->carRepository->update($newCar);
}
with custom finder in the repository to fetch assoc array instead of the mapped object for $racord argument
public function findByUidAssoc($uid)
{
$query = $this->createQuery();
$query->matching(
$query->equals('uid', $uid)
);
return $query->execute(true)[0];
}
Note that the record needs to be persisted before executing above code.
References:
SlugHelper::generate
SlugHelper::buildSlugForUniqueInSite
SlugHelper::buildSlugForUniqueInPid
SlugHelper::buildSlugForUniqueInTable

According to answers from Elias and Jonas, I created a class which simplifies things especially when you have more models to handle
typo3conf/ext/sitepackage/Classes/Utility/SlugUtility.php
<?php
namespace VENDOR\Sitepackage\Utility; // <- to be replaced with your namespace
use TYPO3\CMS\Core\Database\Connection;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\DataHandling\Model\RecordStateFactory;
use TYPO3\CMS\Core\DataHandling\SlugHelper;
use TYPO3\CMS\Core\Utility\GeneralUtility;
/***
*
* This file is part of the "Sitepackage" Extension for TYPO3 CMS.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* (c) 2020 Marcus Biesioroff <biesior#gmail.com>
* Concept by: Elias Häußler
* Jonas Eberle
*
***/
class SlugUtility
{
/**
* #param int $uid UID of record saved in DB
* #param string $tableName Name of the table to lookup for uniques
* #param string $slugFieldName Name of the slug field
*
* #return string Resolved unique slug
* #throws \TYPO3\CMS\Core\Exception\SiteNotFoundException
*/
public static function generateUniqueSlug(int $uid, string $tableName, string $slugFieldName): string
{
/** #var Connection $connection */
$connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable($tableName);
$queryBuilder = $connection->createQueryBuilder();
$record = $queryBuilder
->select('*')
->from($tableName)
->where('uid=:uid')
->setParameter(':uid', $uid)
->execute()
->fetch();
if (!$record) return false;
// Get field configuration
$fieldConfig = $GLOBALS['TCA'][$tableName]['columns'][$slugFieldName]['config'];
$evalInfo = GeneralUtility::trimExplode(',', $fieldConfig['eval'], true);
// Initialize Slug helper
/** #var SlugHelper $slugHelper */
$slugHelper = GeneralUtility::makeInstance(
SlugHelper::class,
$tableName,
$slugFieldName,
$fieldConfig
);
// Generate slug
$slug = $slugHelper->generate($record, $record['pid']);
$state = RecordStateFactory::forName($tableName)
->fromArray($record, $record['pid'], $record['uid']);
// Build slug depending on eval configuration
if (in_array('uniqueInSite', $evalInfo)) {
$slug = $slugHelper->buildSlugForUniqueInSite($slug, $state);
} else if (in_array('uniqueInPid', $evalInfo)) {
$slug = $slugHelper->buildSlugForUniqueInPid($slug, $state);
} else if (in_array('unique', $evalInfo)) {
$slug = $slugHelper->buildSlugForUniqueInTable($slug, $state);
}
return $slug;
}
}
Usage in any place, like controller. Scheduler task, repository, etc. Keep in mind that record should be saved before (it may be created by Extbase, or just with plain SQL), just need to have created uid and be valid TYPO3 record.
use VENDOR\Sitepackage\Utility\SlugUtility;
use \TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager;
...
$pageSlug = SlugUtility::generateUniqueSlug(
5, // int $uid UID of record saved in DB
'pages', // string $tableName Name of the table to lookup for uniques
'slug' // string $slugFieldName Name of the slug field
)
// or
$uniqueSlug = SlugUtility::generateUniqueSlug(
123,
'tx_garage_domain_model_car',
'slug'
);
// or according to the original question,
// if you created new model object with Extbase,
// persist it, create unique slug with SlugUtility
// set the slug property to the created model object and finally update
public function createAction(Car $newCar)
{
$this->carRepository->add($newCar);
GeneralUtility::makeInstance(PersistenceManager::class)->persistAll();
$uniqueSlug = SlugUtility::generateUniqueSlug(
$newCar->getUid(),
'tx_garage_domain_model_car',
'slug'
);
if($uniqueSlug) {
$newCar->setSlug($uniqueSlug);
$this->carRepository->update($newCar);
}
$this->redirect('list');
}
// no need for second call to persistAll()
// as Extbase will call it at action's finalizing.
// etc.

You can use the SlugHelper directly. The API was obviously not made very fluent for that use case but it works...
$this->carRepository->add($newCar);
// probably you need to persist first - I am not sure if this is really necessary
$this->objectManager()->get(
\TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager::class
)->persistAll();
$table = 'tx_garage_domain_model_car';
$field = 'slug';
// a stripped down record with just the necessary fields is enough
$record = ['name' => $newCar->getName()];
$pid = $this->settings->persistence->...
$slugHelper = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(
\TYPO3\CMS\Core\DataHandling\SlugHelper::class,
$table,
$field,
$GLOBALS['TCA'][$table]['columns'][$field]['config']
);
$newCar->slug = $slugHelper->generate($record, $pid);

Related

How can I save url and local images?

I'm working on a project that uses the Spotify API. I get all the top tracks and top artists from users. I save the information into my database, the image that I get from Spotify is a URL image. Like this https://i.scdn.co/image/ab67616d0000b27300d5163a674cf57fe79866a6
In my CMS I want to be able to change the image of an artist or track. For this, I copied the code from the docs https://backpackforlaravel.com/docs/4.1/crud-fields#image-1 "public function setImageAttribute($value) and put this in my model. Everything is working fine for this part, I can upload a new image and it saves into my public folder and gets displayed in my table.
The problem that I have is that when a new user logs in and the artist/track data needs to be saved in the database it goes through this setImageAttribute($value) in the model and doesn't add the URL into the database column.
Is there a way that I can add the URL image without going through the setImageAttribute function in the model?
The controller:
//get Top Artists
$client = new Client([]);
$topartists = $client->get('https://api.spotify.com/v1/me/top/artists?time_range=medium_term&limit=25&offset=5', [
'headers' => [
'Authorization' => 'Bearer ' . $token,
],
]);
$listtopartists = json_decode($topartists->getBody(), true);
$p = 25;
foreach ($listtopartists['items'] as $topartist) {
$artist = TopArtist::where('artist_id', $topartist['id'])->first();
$artist_genre = json_encode($topartist['genres']);
if ($artist === null) {
$new_artist = TopArtist::create([
'artist_id' => $topartist['id'],
'name' => $topartist['name'],
'genres' => $artist_genre,
'users_popularity' => $p,
'popularity' => $topartist['popularity'],
'image' => $topartist['images'][0]['url'],
'url' => $topartist['external_urls']['spotify'],
]);
$spotify_user->topArtists()->attach($new_artist->id);
} else {
$exists = $spotify_user->topArtists()->where('spotify_user_id', $spotify_user->id)->where('top_artist_id', $artist->id)->get();
if ($exists->isEmpty()) {
$spotify_user->topArtists()->attach($artist->id);
}
}
$p--;
}
The Model:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;
class TopArtist extends Model
{
use \Backpack\CRUD\app\Models\Traits\CrudTrait;
use HasFactory;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'artist_id',
'name',
'popularity',
'users_popularity',
'url',
'image',
'genres',
'status',
];
/**
* The attributes that should be cast to native types.
*
* #var array
*/
protected $casts = [
'id' => 'integer',
'status' => 'boolean',
];
public function setImageAttribute($value)
{
$attribute_name = "image";
// or use your own disk, defined in config/filesystems.php
$disk = config('backpack.base.root_disk_name');
// destination path relative to the disk above
$destination_path = "public/storage/artists";
// if the image was erased
if ($value==null) {
// delete the image from disk
\Storage::disk($disk)->delete($this->{$attribute_name});
// set null in the database column
$this->attributes[$attribute_name] = null;
}
// if a base64 was sent, store it in the db
if (Str::startsWith($value, 'data:image'))
{
$image = \Image::make($value)->encode('jpg', 90);
$filename = md5($value.time()).'.jpg';
\Storage::disk($disk)->put($destination_path.'/'.$filename, $image->stream());
\Storage::disk($disk)->delete($this->{$attribute_name});
$public_destination_path = Str::replaceFirst('public/', '', $destination_path);
$this->attributes[$attribute_name] = $public_destination_path.'/'.$filename;
}
}
public function spotifyUsers()
{
return $this->belongsToMany(\App\Models\SpotifyUser::class);
}
}
I fixed it, I had to add an else statement after
if (Str::startsWith($value, 'data:image'))
in the model where I set $this->attributes[$attribute_name] = $value;.

Security Group subpanel doesn't exist for quotes, contrats, invoices, and events modules

I am using suiteCRM 7.7.4 (Sugar Version 6.5.24) and I need to use Security group subpanel in quotes, contracts, invoices and events modules, but for some reasons I can't find it ! I did some researches and I found that this subpanel doesn't appear by default for custom modules.. some developers recommand to do not use the studio to build this kind of relationship, because simply it will not work ! for paid version of sugarCRM they say that there was a tool called "hookup tool" that creates the relationship for you... but As I am using a free version I can't use it !
Do you have any idea ?
Thank you very much !
I finaly find a solution :
Adding this few lines to "modules/AOS_Contracts/metadata/subpaneldefs.php" :
'securitygroups' => array(
'top_buttons' => array(array('widget_class' => 'SubPanelTopSelectButton', 'popup_module' => 'SecurityGroups', 'mode' => 'MultiSelect'),),
'order' => 900,
'sort_by' => 'name',
'sort_order' => 'asc',
'module' => 'SecurityGroups',
'refresh_page' => 1,
'subpanel_name' => 'default',
'get_subpanel_data' => 'SecurityGroups',
'add_subpanel_data' => 'securitygroup_id',
'title_key' => 'LBL_SECURITYGROUPS_SUBPANEL_TITLE',
),
QRR
Verifying permissions.
follow this following steps:
1. Go to Admin
2. Go to studio
3. Select your module where you want subpanel like "invoices"
4. Go to relationship
5. Add 1 to many relationship with Security group module.
6. Now repair rebuild you will find the subapnel in invoice module.
When you create 1 to many relationship with any module it will create the subpanel.
IF its not working then go for custom subpanel.
Refer this linnk I put code from same link it worked for me
This tutorial should hopefully help you to create a new subpanel under the Contacts module in Sugar using a custom link class and driven by SugarCRM 7's new SugarQuery API.
Create a new link class
This should go into custom/modules/<YourModule>/YourNewLink.php and this class will act as the custom functionality that will build your link between the two records.
<?php
/**
* Custom filtered link
*/
class YourNewLink extends Link2
{
/**
* DB
*
* #var DBManager
*/
protected $db;
public function __construct($linkName, $bean, $linkDef = false)
{
$this->focus = $bean;
$this->name = $linkName;
$this->db = DBManagerFactory::getInstance();
if (empty($linkDef)) {
$this->def = $bean->field_defs[$linkName];
} else {
$this->def = $linkDef;
}
}
/**
* Returns false if no relationship was found for this link
*
* #return bool
*/
public function loadedSuccesfully()
{
// this link always loads successfully
return true;
}
/**
* #see Link2::getRelatedModuleName()
*/
public function getRelatedModuleName()
{
return '<Your_Module>';
}
/**
*
* #see Link2::buildJoinSugarQuery()
*/
public function buildJoinSugarQuery($sugar_query, $options = array())
{
$joinParams = array('joinType' => isset($options['joinType']) ? $options['joinType'] : 'INNER');
$jta = 'active_other_invites';
if (!empty($options['joinTableAlias'])) {
$jta = $joinParams['alias'] = $options['joinTableAlias'];
}
$sugar_query->joinRaw($this->getCustomJoin($options), $joinParams);
return $sugar_query->join[$jta];
}
/**
* Builds main join subpanel
* #param string $params
* #return string JOIN clause
*/
protected function getCustomJoin($params = array())
{
$bean_id = $this->db->quoted($this->focus->id);
$sql = " INNER JOIN(";
$sql .= "SELECT id FROM accounts WHERE id={$bean_id}"; // This is essentially a select statement that will return a set of ids that you can match with the existing sugar_query
$sql .= ") accounts_result ON accounts_result.id = sugar_query_table.id";
return $sql;
}
}
The argument $sugar_query is a new SugarQuery object, the details of which are documented here. What you essentially need to do is extend this query with whatever join/filters you wish to add. This is done in the inner join I've specified.
Note: The inner join can get really complicated, so if you want a real working example, checkout modules/Emails/ArchivedEmailsLink.php and how the core sugar team use this. I can confirm however that this does work with custom joins.
Here is the getEmailsJoin to help you understand what you can actually produce via this custom join.
/**
* Builds main join for archived emails
* #param string $params
* #return string JOIN clause
*/
protected function getEmailsJoin($params = array())
{
$bean_id = $this->db->quoted($this->focus->id);
if (!empty($params['join_table_alias'])) {
$table_name = $params['join_table_alias'];
} else {
$table_name = 'emails';
}
return "INNER JOIN (\n".
// directly assigned emails
"select eb.email_id, 'direct' source FROM emails_beans eb where eb.bean_module = '{$this->focus->module_dir}'
AND eb.bean_id = $bean_id AND eb.deleted=0\n" .
" UNION ".
// Related by directly by email
"select DISTINCT eear.email_id, 'relate' source from emails_email_addr_rel eear INNER JOIN email_addr_bean_rel eabr
ON eabr.bean_id = $bean_id AND eabr.bean_module = '{$this->focus->module_dir}' AND
eabr.email_address_id = eear.email_address_id and eabr.deleted=0 where eear.deleted=0\n" .
") email_ids ON $table_name.id=email_ids.email_id ";
}
Add a new vardef entry for the link field.
For this example, I'm going to create the custom link on the contacts module. So this code goes in custom/Extension/modules/Contacts/Ext/Vardefs/your_field_name.php
<?php
$dictionary["Contact"]["fields"]["your_field_name"] = array(
'name' => 'active_other_invites',
'type' => 'link',
'link_file' => 'custom/modules/<YourModule>/YourNewLink.php',
'link_class' => 'YourNewLink',
'source' => 'non-db',
'vname' => 'LBL_NEW_LINK',
'module' => '<YourModule>',
'link_type' => 'many',
'relationship' => '',
);
Add the new link as a subpanel
This goes under custom/Extension/modules/Contacts/Ext/clients/base/layouts/subpanels/your_subpanel_name.php
<?php
$viewdefs['Contacts']['base']['layout']['subpanels']['components'][] = array (
'layout' => 'subpanel',
'label' => 'LBL_NEW_LINK',
'context' =>
array (
'link' => 'your_field_name',
),
);
Add the label
Under
custom/Extension/modules/Contacts/Ext/Language/en_us.new_link.php
<?php
$mod_strings['LBL_ACTIVE_OTHER_INVITES'] = 'Your New Link';
Quick Repair and Rebuild
That should hopefully get you started. Keep an eye on the sugarlogs while you're debugging your queries. I also found using xdebug and SugarQueries compileSql function invaluable in figuring out what I needed to do to get a working INNER JOIN statement.
I've found this to be a surprisingly powerful solution, it means that if you need to show information related to a module that might be a few joins away, this allows you to create the links manually without having to create pointless related fields in-between the two.

Typo3 , extbase mapped entity return no results

First of all, i create a Extension with the "Extension Builder". I would like to extend the "tt_address" Extension.
What steps i do?
I create a Entity Adress and map this to existing table tt_address. In my Entity Address i create setter and getter for retrieving Addressinformations like 'city, zip and street'.
After this step i create a Repository AddressRepository which extends \TYPO3\CMS\Extbase\Persistence\Repository.
The extensionbuilder create a typoscript File ext_typoscript_setup.txt with this content:
config.tx_extbase{
persistence{
classes{
Mab\Oaaddress\Domain\Model\Address {
mapping {
tableName = tt_address
recordType = Tx_Oaaddress_Address
}
}
}
}}
I set the storagePid in my constants.txt
In the last step i would like to retrieve all Addresses from Database and show this in a list view.
class AddressController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionController {
/**
* Events repository
*
* #var \Mab\Oaaddress\Domain\Repository\AddressRepository
* #inject
*/
protected $addressRepository;
/**
* action list
*
* #return void
*/
public function listAction() {
// Exists adress repository?
//var_dump($this->addressRepository);
$addresses = $this->addressRepository->findAll();
//var_dump(count($addresses));
$this->view->assign('addresses', $addresses);
}
The table tt_address contains more than ten results. But the controller show $addresses count always 0. I clear every Cache (empty Typo3Temp folder, empty Cache through Install Tool, emptyh Backend Cache) but nothing have a effect. Why my Controller return nothing? Can someone give me a tip?
Update
After i analyse the query log, i find that this query is executed:
SELECT tt_address.* FROM tt_address WHERE 1=1 AND (tt_address.tx_extbase_type='Tx_Oaaddress_Address') AND tt_address.pid IN (148) AND tt_address.deleted=0 AND tt_address.hidden=0
How can i remove this part
tt_address.tx_extbase_type='Tx_Oaaddress_Address' from the where part of the query?
You can add:
config.tx_extbase {
persistence {
classes {
FriendsOfTYPO3\TtAddress\Domain\Model\Address {
mapping {
tableName = tt_address
recordType = Tx_TtAddress_Listview
}
}
}
}
}
And add "Tx_TtAddress_Listview" to your tx_extbase_type like:
// Configuration/TCA/Overrides/tt_address.php
$tempColumnstx_yourext_tt_address[$GLOBALS['TCA']['tt_address']['ctrl']['type']] = [
'exclude' => true,
'label' => 'yourLabe for Type',
'config' => [
'type' => 'select',
'renderType' => 'selectSingle',
'items' => [
['Person','Tx_TtAddress_Listview'],
['MyLabel','Tx_YourExt_type']
],
'default' => 'Tx_TtAddress_Listview',
'size' => 1,
'maxitems' => 1,
]
];
This adds a or to the SQL statement like:
... WHERE ((`tt_address`.`t
x_extbase_type` = Tx_YourExt_type) OR (`tt_address`.`tx_extbase_type` = Tx_TtAddress_Listview) ...

Typo3: How to upload a file and create a file reference?

i'll try to upload a file (or later multiple files) in FE. This works, like my current code. But how can i get a file reference of this file now?
/**
*
* #var array $fileData
* #var integer $feUserId
* #return \TYPO3\CMS\Extbase\Domain\Model\FileReference
*/
private function uploadFile($fileData, $feUserId) {
$storageRepository = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Resource\\StorageRepository');
$storage = $storageRepository->findByUid(1); # Fileadmin = 1
$saveFolder = $storage->getFolder($this->settings['uploadFolder']);
// Datei speichern
$fileObject = $storage->addFile($fileData['tmp_name'], $saveFolder, $feUserId.'_'.$fileData['name']);
// Dateiobjekt
$repositoryFileObject = $storage->getFile($fileObject->getIdentifier());
die(\TYPO3\CMS\Extbase\Utility\DebuggerUtility::var_dump($repositoryFileObject));
#$newFileReference = $this->objectManager->get('TYPO3\CMS\Extbase\Domain\Model\FileReference');
#$newFileReference->setOriginalResource($repositoryFileObject);
return $newFileReference;
}
There should be something like »setFileReference« by now, but I can not find the like in the API http://typo3.org/api/typo3cms/class_t_y_p_o3_1_1_c_m_s_1_1_core_1_1_resource_1_1_file_reference.html
Well, you may wanna use the following script as temporary solution, which uses the datamap process to create file references.
$sys_file_uid = $file->getUid();
$tt_content_uid = 42;
$tt_content_pid = 1337;
// Do not directly insert a record into sys_file_reference, as this bypasses all sanity checks and automatic updates done!
$data = array();
$data['sys_file_reference']['NEW' . $sys_file_uid] = array(
'uid_local' => $sys_file_uid,
'table_local' => 'sys_file',
'uid_foreign' => $tt_content_uid,
'tablenames' => 'tt_content',
'fieldname' => 'image',
'pid' => $tt_content_pid,
);
$data['tt_content'][$tt_content_uid] = array('image' => 'NEW' . $sys_file_uid);
$tce = t3lib_div::makeInstance('t3lib_TCEmain'); // create TCE instance
$tce->start($data, array());
$tce->process_datamap();
if ($tce->errorLog) {
// Error - Reference not created
// t3lib_utility_Debug::viewArray($tce->errorLog);
}
else {
// Success - Reference created
}
after hitting google for a while i figured out a article that sounded quite well to me.. gonna examine it tomorrow:
http://insight.helhum.io/post/85015526410/file-upload-using-extbase-and-fal-in-typo3-6-2
(just in case somebody else needs this before i could test it)

Zend Framework - Router - Creating Aliases

I'm building a Zend Framework 1.11.11 application and would like to make the routes and content database driven.
I've written a FrontController Plugin that retrieves the 'paths' from the database and creates an entry in the Router for each one, with the associated controller and action.
However, I'd like to be able to use 'aliases' - a URL that behaves like a normal URL, but is an alias.
For example, if I create the following:
// Create the Zend Route
$entry = new Zend_Controller_Router_Route_Static(
$route->getUrl(), // The string/url to match
array('controller' => $route->getControllers()->getName(),
'action' => $route->getActions()->getName())
);
// Add the route to the router
$router->addRoute($route->getUrl(), $entry);
Then a route for /about/ for example can goto the staticController, indexAction.
However, what's the best way for me to create an alias of this route? So if I went to /abt/ it would render the same Controller and Action?
To me it doesn't make sense to recreate the same route as I'll be using the route as the page 'identifier' to then load content from the database for the page...
you can extend static router:
class My_Route_ArrayStatic extends Zend_Controller_Router_Route_Static
{
protected $_routes = array();
/**
* Prepares the array of routes for mapping
* first route in array will become primary, all others
* aliases
*
* #param array $routes array of routes
* #param array $defaults
*/
public function __construct(array $routes, $defaults = array())
{
$this->_routes = $routes;
$route = reset($routes);
parent::__construct($route, $defaults);
}
/**
* Matches a user submitted path with a previously specified array of routes
*
* #param string $path
* #param boolean $partial
* #return array|false
*/
public function match($path, $partial = false)
{
$return = false;
foreach ($this->_routes as $route) {
$this->setRoute($route);
$success = parent::match($path, $partial);
if (false !== $success) {
$return = $success;
break;
}
}
$this->setRoute(reset($this->_routes));
return $return;
}
public function setRoute($route)
{
$this->_route = trim($route, '/');
}
}
and add new router this way:
$r = My_Route_ArrayStatic(array('about', 'abt'), $defaults);