I have TYPO3 version 7.6.18. Tell me please how make auto deleting all reference files when I repository->remove($object) ?
You can add #cascade remove to your domain model property's docblock to have it removed on removal of the entity.
Here's a snippet of the blog_example extension used in Extbase's functional tests:
/**
* The posts of this blog
*
* #var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\ExtbaseTeam\BlogExample\Domain\Model\Post>
* #lazy
* #cascade remove
*/
protected $posts = null;
Related
I tried to integrate an existing table to my extension. The problem is that the content of the table isn't taken over. I created a new model with the name of the existing table and named the properties according to the existing column names. I also implemented the corresponding getters and setters of the properties.
The name of the existing table is tx_institutsseminarverwaltung_domain_model_event.
What is my failure in this case? Just want to access the data of an existing table from another extension.
Thanks in advance.
UPDATE:
I tried this:
/**
* Protected Variable objectManager wird mit NULL initialisiert.
*
* #var \TYPO3\CMS\Extbase\Object\ObjectManagerInterface
* #inject
*/
protected $objectManager = NULL;
and listAction():
/**
* action list
*
* #return void
*/
public function listAction() {
echo "test";
$theRepository = $this->objectManager->get('\TYPO3\institutsseminarverwaltung\Domain\Repository\EventRepository');
$yourRecords = $theRepository->findAll();
$this->view->assign('events', $yourRecords);
}
But no results returned.
You should use the repository linked to this table. Something like this :
$theRepository = $this->objectManager->get(\Your\VendorName\Domain\Repository\TheRepository::class);
$yourRecords = $theRepository->findAll();
How are you trying to "consume" or access the data from the other table in your extension?
Do you have a repository for the existing table (maybe there is already an existing repository, that you can reuse)?
See german typo3 board mapping existing tables and SO thread TYPO3 / How to make repository from existing table fe_users?
solution is:
$querySettings = $this->objectManager->get('TYPO3\\CMS\\Extbase\\Persistence\\Generic\\Typo3QuerySettings');
$querySettings->setRespectStoragePage(FALSE);
$theRepository = $this->objectManager->get('TYPO3\\institutsseminarverwaltung\\Domain\\Repository\\EventRepository');
$theRepository->setDefaultQuerySettings($querySettings);
$yourRecords = $theRepository->findAll();
$this->view->assign('events', $yourRecords);
This seems simple enough but I seem to be too stupid to do it. I have added a field to fe_users called "cv" for uploading a pdf file. In my FrontendUser Model it looks like this:
/**
* #var \TYPO3\CMS\Extbase\Domain\Model\FileReference
* #cascade remove
*/
protected $cv;
Uploading a file works like a charm, I used the script from https://github.com/helhum/upload_example in parts.
The only problem is deleting such a file, or rather, removing the connection between sys_file and the user. After submitting a form and checking a checkbox, I tried to do this:
$user->setCv(null);
$user->setEdited(new \DateTime());
$this->frontendUserRepository->update($user);
$persistenceManager->persistAll();
After a page reload if I take a look at the backend, the cv File is still attached to the user (but "edited" was correctly set to the current datetime). I do not understand this, how can I set the FileReference Value to null?
Make sure to check your Model. FileReferences are stored in an M:N relation. So you must use the folling declaration in your Model:
/**
* cv
*
* #var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\TYPO3\CMS\Extbase\Domain\Model\FileReference>
* #cascade remove
*/
protected $cv = null;
with an initialization in the __constructor:
public function __construct()
{
$this->cv = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
}
Now you have your FileReference in an ObjectStorage. To clear all FileReferences you can set cv to new \TYPO3\CMS\Extbase\Persistence\ObjectStorage():
$user->removeCv(new \TYPO3\CMS\Extbase\Persistence\ObjectStorage());
$user->setEdited(new \DateTime());
$this->frontendUserRepository->update($user);
$persistenceManager->persistAll();
I try to extend the tx_news extension with the field imageright.
For that I found this tutorial: https://docs.typo3.org/typo3cms/extensions/news/2.2.1/Main/Tutorial/ExtendingNews/Index.html
The first step is to use extension_builder to add the field. As I already have a extension in where I want to implement the extension I do not want to use the extension_builder (also I tried it with a new extension and extend the news-model did not work - I have no clue how to do it right). However this are the steps I did:
In my extension my_template I added the folders and file: Classes/Domain/Model/News.php:
class MyTemplate_Domain_Model_News extends Tx_News_Domain_Model_News {
/**
* #var bool
*/
protected $imageright;
/**
* Returns the imageright
*
* #return bool $imageright
*/
public function getImageright() {
return $this->imageright;
}
/**
* Sets the sort
*
* #param bool $imageright
* #return void
*/
public function setImageright($imageright)
{
$this->imageright = $imageright;
}
}
?>
/Ressources/Private/extend-news.txt:
Domain/Model/News
Created the field imageright as tinyint in the table tx_news_domain_model_news (and added it to the SQL file)
I knew I have to create a TCA file in /Configuration/TCA/, but I have no clue how this should look like or what name it needs to have. I think this is the last step I need to make this working.
Also note the extension my_template was just a template, so before my changes there where no Classes and no TCA files.
Solution is to use this tutorial: http://www.lukasjakob.com/extend-a-typo3-extbase-model-with-custom-field/
What sounds a bit academic in the title is actually quite straightforward: I have set up a TYPO3 6.1 extbase extension that I've equipped with a scheduler task. The task is supposed to import a CSV file and save it into the extension's database fields.
But how do I tell the scheduler task to use the extension's model etc. and save the received data into the persistence layer?
I've seen this answer to a similar question: Execute repository functions in scheduler task and I think it points the right way, but I think need a full example to start understanding how the dependency injection works.
First you have to consider the aspect of performance:
If you want to insert a big amount of data, you should not use the Extbase persistence for such a task. Because if you do so, it will generate an object for each row you want to insert and persist it immediately. This is quite slow and has a big memory footprint.
If you don't have much data or you split the jobs (e.g. perform 100 import jobs per scheduler run), then use the Extbase persistence.
You can have both in CommandController context, and since CommandControllers are straight-forward to set up, you should go for them instead of an own Scheduler task.
Using Extbase persistence
In the CommandController, inject your repository:
/**
* myRepository
*
* #var \Venor\Myext\Domain\Repository\MyRepository
* #inject
*/
protected $myRepository
Then iterate through the rows you want to import (foreach) and create a new object for every row and add it to your repository:
$myObject = $this->objectManager->get('Vendor\Myext\Domain\Model\MyModel');
$myObject->setProperty('foo');
$myObject->setOtherProperty('bar');
$this->myRepository->add($myObject);
To actually save the objects to the database, you need to persist them. So you also inject the persistenceManager:
/**
* #var \TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager
* #inject
*/
protected $persistenceManager;
And use it:
$this->persistenceManager->persistAll();
You should not do that for every single object (for performance reasons); but for memory usage reasons you should not wait until after thousands of objects to persist, either. So you just insert an iterator to your foreach loop and persist every 20th, 40th, or whatever loop.
Please don't forget that the Scheduler works in Backend context, so the TypoScript must be available by module.tx_yourext. If you want to share the same settings/storagePid with the frontend part of your app, use
module.tx_yourext.persistence < plugin.tx_yourext.persistence
[...]
The TypoScript needs to be present in the root page of your website for backend modules/CommandControllers to use them. I suggest you add the stuff to myext/Configuration/TypoScript/setup.txt and add the static template of your extension to the root page.
Using DataHandler
The TYPO3 DataHandler (formerly TCEmain) is the engine the TYPO3 backend uses for inserting and modifying database records. It is very powerful.
Instead of an object, inside your loop you create an array containing all the data. The first array index is the table, the next level is the affected record, where NEW means that a new record is created. Then you can just set every field of a table with the desired value
$data = array();
$data['be_users']['NEW'] = array(
'pid' => 0,
'username' => $staffMember['IDPerson'],
'password' => md5(GeneralUtility::generateRandomBytes(40)), // random password
'usergroup' => '1,2',
'email' => $staffMember['Email'],
'realName' => $staffMember['Nachname'] . ' ' . $staffMember['Vorname'],
'lang' => 'de',
);
Now you can make an Instance of DataHandler and persist the changes:
/** #var $tce t3lib_TCEmain */
$tce = GeneralUtility::makeInstance('TYPO3\CMS\Core\DataHandling\DataHandler');
$tce->bypassAccessCheckForRecords = TRUE;
$tce->start($data, array());
$tce->admin = TRUE;
$tce->process_datamap();
$newRecordsUidArray = $tce->substNEWwithIDs['NEW'];
Please note the line $tce->admin = TRUE. This suggests to DataHandler that an admin is performing the action. This is convenient because you don't have to set allowed exclude fields for the Scheduler user and can also insert records to PID 0. But it is a possible security flaw, so carefully consider its usage.
Records inserted/updated by DataHandler logged correctly, can be reverted etc.. You can find some examples (such as adding pictures, resolving MM relations) here. In this case all DataHandler related functions were moved to an external repository class that is injected to the CommandController as described above (it's just named in Extbase convention).
A good overview of DataHandler functions can be found here.
In Addition to lorenz's answer: Beginner's Guide to set up a Command Controller Scheduler task:
My example is an import task. Change the Name part "Import" to your needs.
Create a new file EXT:Classes/Controller/ImportCommandController.php
<?php
namespace NAMESPACE\Myextension\Controller;
/***************************************************************
* Copyright notice
*
* (c) 2014
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
/**
*
*
* #package Myextension
* #license http://www.gnu.org/licenses/gpl.html GNU General Public License, version 3 or later
*
*/
class ImportCommandController extends \TYPO3\CMS\Extbase\Mvc\Controller\CommandController {
/**
* itemRepository
*
* #var \NAMESPACE\Myextension\Domain\Repository\ItemRepository
* #inject
*/
protected $itemRepository;
/**
* #var \TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager
* #inject
*/
protected $persistenceManager;
/**
*
* #param \integer $storagePid
* #param \string $url
*
* #return bool
*/
// very nice: parameters will be fields in the scheduler!
public function importCommand($storagePid = 0,$url = NULL) {
$source = utf8_encode(utf8_encode(file_get_contents($url)));
// set storage page ourselves
// not sure if really necessary
$querySettings = $this->itemRepository->createQuery()->getQuerySettings();
$querySettings->setRespectStoragePage(FALSE);
$this->itemRepository->setDefaultQuerySettings($querySettings);
// do your stuff here
$source = 'foo';
$rendered = 'bar';
// then store it
// this seems to be only necessary if we don't have an existing item yet
// but as we don't know that here, we have to do it
$item = $this->objectManager->get('STUBR\Therapiestellen\Domain\Model\Item');
// find all existing items
$all = $this->itemRepository->findAll();
// if we have an item already, take the first (and only one)
if(count($all) > 0){
$item = $all->getFirst();
}
// set / update properties
$item->setSource($source);
$item->setRendered($r);
$item->setPid($storagePid);
// either update or add it
if(count($all) > 0){
$this->itemRepository->update($item);
}
else {
$this->itemRepository->add($item);
}
// persist it
$this->persistenceManager->persistAll();
}
}
?>
In EXT:ext_localconf.php, add the command controller:
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['extbase']['commandControllers'][] = 'NAMESPACE\\Myextension\\Controller\\ImportCommandController';
Configure in Scheduler:
That's basically it!
I'm using symfony2 and mongodb, until today, everything is OK, but I create a new document, and suddenly, appears this error :
"MongoException: zero-length keys are not allowed, did you use $ with double quotes?"
$dm = $this->get('doctrine.odm.mongodb.document_manager');
$_repo = $dm->getRepository('CantaoCustomerBundle:CustomerTags');
$_repo->findOneByCustomer($customer);
The $customer it's OK, the repository is empty, and my document class is like this :
/**
* #MongoDB\ID
**/
private $id;
/**
* #MongoDB\ReferenceOne(targetDocument="Tapronto\Mats\ProductBundle\Document\Tag", cascade={"persist"})
**/
private $tag;
/**
* #MongoDB\ReferenceOne(targetDocument="Tapronto\Mats\CustomerBundle\Document\Customer", cascade={"persist"})
**/
private $customer;
/**
* #MongoDB\Float
**/
private $points;
/**
* #MongoDB\Int
**/
private $viewed;
/**
* #MongoDB\Int
**/
private $brought;
/**
* #MongoDB\Int
**/
private $favorited;
/**
* #MongoDB\Date
* #Gedmo\Timestampable(on="create")
**/
private $createdAt;
/**
* #MongoDB\Date
* #Gedmo\Timestampable(on="update")
**/
private $updatedAt;
Can anyone help me, have some idea, I tried everything and nothing seems to work
I just fixed this by using the referenced object's ID instead of the reference object itself as my search term.
$_repo->findOneByCustomer($customer->getId());
EDIT:
That isn't throwing the exception but it isn't actually returning anything either. I tried using new MongoId($id) as was suggested a few places (Doctrine MongoDB find by id), but that didn't work either. Finally, I found something in the full query builder that searches by references (note: this uses the object instead of the object's ID).
$dm->createQueryBuilder()->find('CantaoCustomerBundle:CustomerTags')
->field('customer')->references($customer)
->getQuery()->execute();
I feel like this should be done more simply (like you did originally), but this fix is working for me.
It could be that you're trying to persist an object private attribute.
If that's not the case a good way to debug is to shut off the zero-length key check so that you can actually debug by checking what it's being written into mongo.
zero-length keys are not allowed, did you use $ with double quotes?
Code: 1
You tried to save "" as a key. You generally should not do this. "" can mess up subobject access and is used by MongoDB internally. However, if you really want, you can set mongo.allow_empty_keys to true in your php.ini file to override this sanity check. If you override this, it is highly recommended that you set error checking to strict to avoid string interpolation errors.
http://php.net/manual/en/mongo.configuration.php#ini.mongo.allow-empty-keys