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);
I want upload some image to server with rest API using Codeigniter.
But I have a problem after upload image / refresh phpmyadmin on this table.
I know this problem is classic, what I'm already todo:
Re-Create the table 2 times.
Make ID to Autoincrement (actually I'm make it AI at first make table)
Not include ID on insert operation, and make it AI automatic.
I'm already truncate the table 2 times
but nothing change anything, at I'm refresh page phpmyadmin this error always appear.
What's my mistake ?
Thanks
If you think my error because my code Rest-API, here's my code:
Controller:
public function upload_post()
{
// $config['max_size'] = '100';
// $config['max_width'] = '1024';
// $config['max_height'] = '768';
$msgCreated = ['status' => true, 'message' => 'Image Has Been Upload'];
$msgFailCreated = ['status' => false, 'message' => 'Failed to Upload Image !'];
$config['upload_path'] = './image/';
$config['allowed_types'] = 'gif|jpg|png';
$this->load->library('upload', $config);
$this->upload->initialize($config);
if (!$this->upload->do_upload('file')) {
$this->set_response($msgFailCreated, 404);
} else {
$info = $this->upload->data();
$image_path = base_url("image/" . $info['raw_name'] . $info['file_ext']);
$data = [
"name_image" => $this->input->post('name_image'),
"image" => $image_path
];
if ($this->mahasiswa->insertImage($data)) {
$this->set_response($msgCreated, 201);
} else {
$this->set_response($msgFailCreated, 400);
}
}
}
Model:
//? Membuat Upload Image
public function insertImage($data){
return $this->db->insert('image', $data);
}
I have a script which adds a product in cart with custom option image and it was working perfect till CE 1.9.2.1 but after up gradation to latest version it troughs exception that Please specify the product's required option(s).
Below is code, please guide me if something has to change for newer version .
<?php
$productId = xxx;
$image = 'path to image(tested image exists)';
$product = Mage::getModel('catalog/product')->load($product_id);
$cart = Mage::getModel('checkout/cart');
$cart->init();
$params = array(
'product' => $productId,
'qty' => 1,
'options' => array(
$optionId3inmycase => array(
'type' => 'image/tiff',
'title' => $image,
'quote_path' => '/media/custom/' . $image,
'order_path' => '/media/custom/' . $image,
'fullpath' => Mage::getBaseDir() . '/media/custom/' . $image,
'secret_key' => substr(md5(file_get_contents(Mage::getBaseDir() . '/media/custom/' . $image)), 0, 20)),
)
);
$request = new Varien_Object();
$request->setData($params);
$cart->addProduct($product, $request);
$cart->save();
if ($itemId > 0) {
$cartHelper = Mage::helper('checkout/cart');
$cartHelper->getCart()->removeItem($itemId)->save();
}
Mage::getSingleton('checkout/session')->setCartWasUpdated(true);
$this->_redirect('checkout/cart/');
?>
One quick solution is to rewrite Mage_Catalog_Model_Product_Option_Type_File class and change validateUserValue() function.
around line 129, replace
$fileInfo = $this->_getCurrentConfigFileInfo();
with
$fileInfo = null;
if (isset($values[$option->getId()]) && is_array($values[$option->getId()])) {
// Legacy style, file info comes in array with option id index
$fileInfo = $values[$option->getId()];
} else {
/*
* New recommended style - file info comes in request processing parameters and we
* sure that this file info originates from Magento, not from manually formed POST request
*/
$fileInfo = $this->_getCurrentConfigFileInfo();
}
but its old code and will have APPSEC-1079 security issue.
and to download image this uploaded image in order detail etc. add this function in same model class.
/**
* changed the image save address as we are saving image in custom
* Main Destination directory
*
* #param boolean $relative If true - returns relative path to the webroot
* #return string
*/
public function getTargetDir($relative = false)
{
$fullPath = Mage::getBaseDir('media') . DS . 'custom';
return $relative ? str_replace(Mage::getBaseDir(), '', $fullPath) : $fullPath;
}
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)
I have a problem with ZF, my code looks OK, but I can't take the parameter ID, it return true, and i'm accesing the url right http://site.com/admin/news/newsedit/1
So my code looks like this:
Route
$ad = self::$frontController->getRouter();
$ad->addRoute('newsedit',
new Zend_Controller_Router_Route(
'news/newsedit/:id',
array(
'module' => 'admin',
'controller' => 'news',
'action' => 'newsedit'
)
)
);
Action
public function newseditAction()
{
/*
Disable Layout
*/
$this->_helper->layout->disableLayout();
/*
#return : boolen OR string
*/
$_id = ($this->_getParam('id') !== NULL) ? (int)$this->_getParam('id') : false;
if ($_id) {
/*
#return : array
*/
$_get = $this->news->select()->where('id = ?', $_id);
if (count($_get) > 0) {
$this->view->data = $_get;
}
}
Zend_Debug::dump($this->_getParam('id'));
}
What I'm doing wrong?
Try the following:
First check if the routes are set in your controller. Use
print_r($this->getFrontController()->getRouter()->getRoutes());
to confirm.
If not, you are setting the router in the wrong instance.
Use:
$ad = Zend_Controller_Front::getInstance()->getRouter();
instead.
on a sidenote:
$_get = $this->news->select()->where('id = ?', $_id);
this doesnt return any rows. this is a Zend_Db_Table_Select object not an Zend_Db_Rowset Object.
You would need to do:
$select = $this->news->select()->where('id = ?', $_id);
$_get = $this->news->fetchAll($select);
or even easier:
$_get = $this->news->find($_id)
greetings