I have recently created an extension that has a file upload feature. I decided to store it as a string. I have used it like this:
In the controller:
public function initializeAction() {
if ($this->arguments->hasArgument('blog')) {
$this->arguments->getArgument('blog')->getPropertyMappingConfiguration()->setTargetTypeForSubProperty('image', 'array');
}
}
In the model:
/**
* Returns the image
*
* #return string $image
*/
public function getImage()
{
return $this->image;
}
/**
* Sets the image
*
* #param \array $image
* #return void
*/
public function setImage(array $image)
{
die(debug::var_dump($image));
if (!empty($image['name']))
{
$imageName = $image['name'];
$imageTempName = $image['tmp_name'];
$basicFileUtility = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Utility\\File\\BasicFileUtility');
$imageNameNew = $basicFileUtility->getUniqueName($imageName, \TYPO3\CMS\Core\Utility\GeneralUtility::getFileAbsFileName('uploads/tx_myextension/'));
\TYPO3\CMS\Core\Utility\GeneralUtility::upload_copy_move($imageTempName, $imageNameNew);
$this->image = basename($imageNameNew);
}
}
The TCA:
'config' => [
'type' => 'group',
'internal_type' => 'file',
'uploadfolder' => 'uploads/tx_myextension',
'show_thumbs' => 1,
'size' => 1,
'allowed' => $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'],
'disallowed' => ''
],
In my form:
<f:form action="update" name="blog" object="{blog}" >
<f:form.upload property="image" class="form-control" />
...
Now this works perfectly when a new object is created, however when I try to change this image (using updateAction), I get the this error message:
Exception while property mapping at property path "image":
No converter found which can be used to convert from "string" to "array".
I would like to avoid uploading via FAL or writing my own conversion. I'm hoping that I just missed something trivial.
Take an look to an update script from tt_address to see how to make an update.
To make it short: You must read all entries of your files and move them from upload dir to your file storage and then you must add an file_reference which connect the sys_file with your domain model:
GeneralUtility::upload_copy_move(
PATH_site . 'uploads/tx_myextension/' . $imageName,
PATH_site . 'fileadmin/tx_myextension/' . $imageName);
$fileObject = $this->storage->getFile('fileadmin/tx_myextension/' . $imageName);
if ($fileObject instanceof \TYPO3\CMS\Core\Resource\File) {
$this->fileRepository->add($fileObject);
$dataArray = [
'uid_local' => $fileObject->getUid(),
'tablenames' => 'tx_your_domain_model',
'fieldname' => 'image',
'uid_foreign' => 'your model uid',
'table_local' => 'sys_file',
'cruser_id' => 999,
'pid' => 'your_model_pid',
'sorting_foreign' => $imageCount,
'sys_language_uid' => 0
];
if ($this->getDatabaseConnection()->exec_INSERTquery('sys_file_reference', $dataArray)) {
$imageCount++;
}
}
It was a very stupid and simple mistake from my part. In the edit form I forgot to add this: enctype="multipart/form-data"
<f:form action="update" enctype="multipart/form-data" name="blog" object="{blog}" >
Related
How can I restrict allowedExtention just for $GLOBALS['TCA']['pages']['columns']['media']? But not using $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'] as it will add restriction for all FAL fields.
I found class
class ImageManipulationElement extends AbstractFormElement
{
/**
* Default element configuration
*
* #var array
*/
protected static $defaultConfig = [
'file_field' => 'uid_local',
'allowedExtensions' => null, // default: $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext']
Looks like should be something like:
$GLOBALS['TCA']['pages']['columns']['media']['config']['overrideChildTca']['allowedExtensions'] = 'jpg, jpeg';
Hard way will drope all usefull things for this field.
$GLOBALS['TCA']['pages']['columns']['media'] = [
'exclude' => true,
'label' => 'LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.media',
'config' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getFileFieldTCAConfig(
'media',
[], 'jpg, jpeg'
)
];
So not is our way. I need just some override like
$GLOBALS['TCA']['pages']['columns']['media']['config']['overrideChildTca']['columns']...['allowedExtention'] = 'jpg, jpeg';
Who know knows how to do this?
After small searching I found this example:
$allowExtensions = 'jpg,jpeg';
$GLOBALS['TCA']['pages']['columns']['media']['config']['filter'][0]['parameters']['allowedFileExtensions'] = '$allowExtensions;
$GLOBALS['TCA']['pages']['columns']['media']['config']['overrideChildTca']['columns']['uid_local']['config']['appearance']['elementBrowserAllowed']= $allowExtensions;
added to typo3conf/ext/myext/Configuration/TCA/Overrides/pages.php
I am using Magento 2.2.3 and i added a new checkbox field with require validation in address onepage checkout form by custom plugin.
I follow this guide:
https://devdocs.magento.com/guides/v2.0/howdoi/checkout/checkout_new_field.html
Now I display checkbox but validation does not work well.
Require validation only works when customer uncheck the field after checking it.
I need validation to work even when checkbox has never been checked like on first load of the form
Below is my code of LayoutProcessor:
class LayoutProcessor
{
/**
* #param \Magento\Checkout\Block\Checkout\LayoutProcessor $subject
* #param array $jsLayout
* #return array
*/
public function afterProcess(
\Magento\Checkout\Block\Checkout\LayoutProcessor $subject,
array $jsLayout
) {
$customAttributeCode = 'custom_field';
$jsLayout['components']['checkout']['children']['steps']['children']['shipping-step']['children']['shippingAddress']['children']
['shipping-address-fieldset']['children'][$customAttributeCode] = [
'component' => 'Magento_Ui/js/form/element/single-checkbox',
'config' => [
'customScope' => 'shippingAddress.custom_attributes',
'template' => 'ui/form/field',
'elementTmpl' => 'ui/form/components/single/checkbox',
],
'label' => 'Bla bla bla bla.....',
'dataScope' => 'shippingAddress.custom_attributes' . '.' . $customAttributeCode,
'provider' => 'checkoutProvider',
'sortOrder' => 251,
'required' => true,
'validation' => [
'required-entry' => true
],
'description'=>null,
'value' => '1',
];
return $jsLayout;
}
}
Zend 3 translates form labels automatically.
If forms are created using array specification, how is it possible to scan translatable form element strings with Poedit?
How to add translator->translate() functionality to forms? I tried the following in module.php onBootstrap method but this does not work:
$sm = $e->getApplication()->getServiceManager();
$vhm = $sm->get('ViewHelperManager');
$translator = $sm->get('MvcTranslator');
$vhm->get('form')->setTranslator($translator);
I want to use it like $form->translator->translate(), in such a way it would be possible to scan code with Poedit to find translatable labeles, placeholders etc.
Here's a TranslatorFactory if you need
final class TranslatorFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
// get translator files' paths from config
$paths = $container->get('config')['settings']['localization-paths'] ?? [];
$translator = new Translator();
// add zend-i18n-resources files to translator
$translator->addTranslationFilePattern(
'phpArray',
Resources::getBasePath(),
Resources::getPatternForValidator()
);
// add your translation files to translator
foreach ($paths as $path) {
$translator->addTranslationFilePattern('phpArray', $path, '%s.php');
}
// todo: replace with user's preferred language
$translator->setLocale('tr');
return $translator;
}
}
And add your factory to service manager
'service_manager' => [
'factories' => [
\Zend\I18n\Translator\TranslatorInterface::class => \MyModule\Factory\TranslatorFactory::class,
],
],
Not sure if you're still looking for a solution, so I'll add mine.
I use the TranslatorAwareTrait in my AbstractForm class.
use Zend\I18n\Translator\TranslatorAwareTrait;
abstract class AbstractForm extends \Zend\Form\Form implements
{
use TranslatorAwareTrait;
// Form stuff
}
Then, in the *FormFactory do the following:
use Zend\I18n\Translator\Translator;
use Zend\ServiceManager\Factory\FactoryInterface;
class SomeFormFactory implements FactoryInterface
{
/**
* #param ContainerInterface $container
* #param string $requestedName
* #param array|null $options
* #return mixed|object|AbstractForm
* #throws \Psr\Container\ContainerExceptionInterface
* #throws \Psr\Container\NotFoundExceptionInterface
*/
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
// Obviously you'll have more/other requirements. Fulfil them here.
$form = new SomeForm();
$form->setTranslator(
$container->get('translator')
);
return $form;
}
}
Usage example:
use Zend\I18n\Translator\TranslatorAwareTrait;
abstract class AbstractForm extends \Zend\Form\Form implements
{
use TranslatorAwareTrait;
public function init()
{
if (!$this->has('submit')) {
$this->addSubmitButton();
}
}
public function addSubmitButton($value = 'Save', array $classes = null)
{
$this->add([
'name' => 'submit',
'type' => Submit::class,
'attributes' => [
'value' =>
// Translate $value before passing to this function
$value === 'Save' ? $this->getTranslator()->translate('Save') : $value,
'class' => (!is_null($classes) ? join (' ', $classes) : 'btn btn-primary'),
],
]);
}
}
On the other hand, you could...
Translate strings before passing them if you're translating with Poedit.
If your modules contain the following config (in each module!):
'translator' => [
'translation_file_patterns' => [
[
'type' => 'gettext',
'base_dir' => __DIR__ . '/../language',
'pattern' => '%s.mo',
],
],
],
You can see here that translation is done using gettext. This is a PHP module that searches for the following code strings and translates its contents: _('translatable string').
The translation files to look for end with the .mo extension and can be found in __DIR__ . '/../language'.
Thus, if you make sure to have the PHP gettext module enabled to use this.
To use this with just normal strings, even in config for a Fieldset or a form, you could have the following:
$this->add([
'name' => 'street',
'required' => true,
'type' => Text::class,
'options' => [
'label' => _('Street'), // <<-- translated using gettext
],
]);
I have the following problem and I'm sure some of you will mark this question as duplicate but I couldn't find a specific answer for my problem.
I have an extension and I want to add images / pdf's etc. using the FAL.
According to tutorials I have to config the TCA. Well, the docs are sh.. about that point and the tutorials are based on the knowledge of TCA.
I also have to use some TypoScript, which I haven't used to this point.
Ok, as far as I got here's my question:
Where do I edit the TCA?
I have a file named ext_tables where I can see $GLOBALS['TCA'].
I also have a directory TCA with some files in it (only filled with $GLOBALES['TCA'].
And after that, how do I access these datas? I need to build a tree in the inside of a modal (pop-up is also possible)
I know these questions sound horribly easy but I couldn't find a tutorial which could explain anything at all.
I appreciate all help :)
Thanks a lot.
Your question is king of vague:
What exactly did you try so far?
Which files did you change?
Do you need the files inside your FLUIDTEMPLATE, inside your extbase controller or somewhere else?
Steps to add FAL fields to your extension
Extend the database (typo3conf/ext/yourExtFolder/ext_tables.sql):
CREATE TABLE your_database_table (
your_fal_field int(11) unsigned DEFAULT '0' NOT NULL
)
Extend the TCA:
If you extend an existing table from another extension you have the extend the TCA inside typo3conf/ext/yourExtFolder/Configuration/TCA/Overrides/your_database_table.php
Example (extend tt_content):
$newColumn = [
'field_name' => [
'image' => [
'label' => 'Image',
'config' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getFileFieldTCAConfig('image', [
'appearance' => [
'createNewRelationLinkTitle' => 'LLL:EXT:cms/locallang_ttc.xlf:images.addFileReference',
],
'minitems' => 0,
'maxitems' => 1,
], $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext']),
],
],
];
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTCAcolumns('tt_content', $newColumn);
If you add the field to your own extension your have to extend typo3conf/ext/yourExtFolder/Configuration/TCA/your_database_table.php.
Example (from TYPO3 core be_users TCA - shortened version):
return [
'ctrl' => [
'label' => 'username',
'descriptionColumn' => 'description',
],
'columns' => [
'username' => [
'label' => 'LLL:EXT:lang/Resources/Private/Language/locallang_tca.xlf:be_users.username',
'config' => [
'type' => 'input',
'size' => 20,
'max' => 50,
'eval' => 'nospace,trim,lower,unique,required',
'autocomplete' => false,
]
],
'avatar' => [
'label' => 'LLL:EXT:lang/Resources/Private/Language/locallang_tca.xlf:be_users.avatar',
'config' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getFileFieldTCAConfig(
'avatar',
['maxitems' => 1],
$GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext']
)
],
],
// Removed more `columns`, `types` and `palettes` config
];
The important part is the definition of avatar which uses the getFileFieldTCAConfig function.
Extend your extbase model (typo3conf/ext/yourExtFolder/Classes/Domain/Model/YourClass.php)
Simplified snippet from keinerweiss.de:
class YourClass extends TheModelYouWantToExtend or \TYPO3\CMS\Extbase\DomainObject\AbstractEntity {
// ...
/**
* #var \TYPO3\CMS\Extbase\Domain\Model\FileReference
*/
protected $yourField;
/**
* Returns the image
*
* #return \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\TYPO3\CMS\Extbase\Domain\Model\FileReference> $image
*/
public function getYourField() {
return $this->yourField;
}
/**
* Sets the image
*
* #param \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\TYPO3\CMS\Extbase\Domain\Model\FileReference> $image
* #return void
*/
public function setYourField($image) {
$this->yourField = $yourField;
}
}
Use your images in Fluid (From t3-developer.com):
<f:for each="{mymodel.mypictures}" as="picture">
<f:image src="{mypicture.image.uid}" alt="" treatIdAsReference="TRUE" />
</f:for>
More links (english):
https://gist.github.com/maddy2101/5668835
http://blog.scwebs.in/typo3/typo3-fal-file-abstraction-layer-in-extbasefluid-extension
More links(german):
http://keinerweiss.de/755-typo3-fal-in-einer-eigenen-extbasefluid-extension-einsetzen.html
http://t3-developer.com/ext-programmierung/techniken-in-extensions/fal-in-typo3-extensions-verwenden/
http://t3g.at/extbase-bilder-fal-in-extension-integrieren/
Domain model
class Image extends AbstractContent {
/**
* #var \TYPO3\CMS\Extbase\Domain\Model\FileReference
*/
protected $file;
/**
* Gets the image file
*
* #return \TYPO3\CMS\Extbase\Domain\Model\FileReference
*/
public function getFile() {
return $this->file;
}
/**
* Sets the image file
*
* #param \TYPO3\CMS\Extbase\Domain\Model\FileReference $file
* #return void
*/
public function setFile($file) {
$this->file = $file;
}
}
Import service fragments
/**
* #var \TYPO3\CMS\Core\Resource\ResourceStorage
*/
protected $defaultStorage;
[...]
$this->defaultStorage = ResourceFactory::getInstance()->getDefaultStorage();
[...]
$file = $this->defaultStorage->addFile(
'/tmp/4711',
$this->defaultStorage->getRootLevelFolder(),
'foo.jpg',
'overrideExistingFile'
);
$falReference = ResourceFactory::getInstance()->createFileReferenceObject(
array(
'uid_local' => $file->getUid(),
'uid_foreign' => uniqid('NEW_'),
'uid' => uniqid('NEW_'),
)
);
$reference = GeneralUtility::makeInstance(FileReference::class);
$reference->setOriginalResource($falReference);
$content = GeneralUtility::makeInstance(Image::class);
$content->setFile($reference);
After saving $content the image is available through the record and the filemount but the Ref column in BE > FILE > File List) is - and not >= 1. So its look like the reference is some how broken. When I'm using the BE to add an image to the record it's all fine. I'm using TYPO3 CMS 7.3-dev.
What's wrong with my code?
I get the hint in the Slack channel of TYPO3.
You just need to set plugin.tx_myext.persistence.updateReferenceIndex = 1 respectively module.tx_myext.persistence.updateReferenceIndex = 1 and the index will be updated.
Alternatively you could use \TYPO3\CMS\Core\Database\ReferenceIndex::updateRefIndexTable().
When I had to use FAL in my extension I found this link:
http://t3-developer.com/extbase-fluid/extensions-erweitern/fal-in-eigenen-extensions/fal-in-typo3-extensions-verwenden/
Since it is in German, I will in the very shortest explain what is done there:
extend your data model in ext_tables.sql
add a column of some char type (e.g. varchar)
add your column to the column section in your TCA array in ext_tables.php
'mypictures' => array(
'exclude' => 1,
'label' => 'My Pictures',
'config' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getFileFieldTCAConfig('image', array(
'appearance' => array(
'createNewRelationLinkTitle' => 'LLL:EXT:cms/locallang_ttc.xlf:images.addFileReference'
),
'minitems' => 0,
'maxitems' => 99,
), $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext']),
),
Extend your modelfiles. Pay attention to annotations!
You can use your media in your fluid template