How do I get uid of a File Reference Object in TYPO3? - typo3

I am trying to get a file through this code $f = $resourceFactory->getFileObject($uid); but the problem is the uid is a protected field in the file reference object, as seen below so I am not able to get the uid, and getUid() obviously wont work either.
So how can I get the uid of the file reference (FAL)
/**
* A file reference object (File Abstraction Layer)
*
* #api experimental! This class is experimental and subject to change!
*/
class FileReference extends
\TYPO3\CMS\Extbase\Domain\Model\AbstractFileFolder
{
/**
* Uid of the referenced sys_file. Needed for extbase to serialize the
* reference correctly.
*
* #var int
*/
protected $uidLocal;
/**
* #param \TYPO3\CMS\Core\Resource\ResourceInterface $originalResource
*/
public function setOriginalResource(\TYPO3\CMS\Core\Resource\ResourceInterface $originalResource)
{
$this->originalResource = $originalResource;
$this->uidLocal = (int)$originalResource->getOriginalFile()->getUid();
}
/**
* #return \TYPO3\CMS\Core\Resource\FileReference
*/
public function getOriginalResource()
{
if ($this->originalResource === null) {
$this->originalResource = \TYPO3\CMS\Core\Resource\ResourceFactory::getInstance()->getFileReferenceObject($this->getUid());
}
return $this->originalResource;
}
}

Given you have an instance of TYPO3\CMS\Extbase\Domain\Model\FileReference then you can use getOriginalResource() to get the wrapped TYPO3\CMS\Core\Resource\FileReference. If you need the referenced file, you can then use getOriginalFile(). Thus as a chained call:
$file = $fileReference->getOriginalResource()->getOriginalFile();
Notice that you don't have to use the ResourceFactory yourself in all of this, this is taken care of internally.

Work form me.
You can find or get file refernce uid using custom query.
In Controller :
$uid = $yourObject->getUid();
$fileReference = $this->yourRepository->getFileReferenceObject($uid);
In Repository
public function getFileRefernceHeaderLogo($uid){
$query = $this->createQuery();
$queryString = "SELECT *
FROM sys_file_reference
WHERE deleted = 0
AND hidden = 0
AND tablenames='your_table_name'
AND fieldname='your_field_name'
AND uid_foreign =".$uid;
$query->statement($queryString);
return $res = $query->execute(true);
}
In Controller
$fileRefUid = $fileReference[0]['uid'];
Here you can get uid of file reference table.It is long process.
You can also get sys_file table uid for getFileObject.like,
$sys_file_uid = $fileReference[0]['uid_local'];

Related

Contentsliding is not stopping at sysfolder since TYPO3 v10 - How to solve?

The TSref entry for slide explains:
Up to Version 9 of TYPO3 the sliding stopped when reaching a folder.
Beginning with TYPO3 10 this is not longer the case. See
$cObj->checkPid_badDoktypeList.
Ok, this variable is still 255 (formerly directly, now via constant PageRepository::DOKTYPE_RECYCLER).
What exactly should I see there that will help me? Or better, how to get content sliding still working like before?
You have to extend the ContentObjectRenderer class and overwrite the getSlidePids method with your own extension.
In the boot function of ext_localconf.php:
$GLOBALS['TYPO3_CONF_VARS']['SYS']['Objects'][\TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer::class] = [
'className' => \YourVendor\YourExtensionKey\ContentObject\ContentObjectRenderer::class
];
Then you have to create your own "Classes/ContentObject/ContentObjectRenderer.php" with:
<?php
/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
namespace YourVendor\YourExtension\ContentObject;
use TYPO3\CMS\Core\Domain\Repository\PageRepository;
use TYPO3\CMS\Core\Utility\GeneralUtility;
class ContentObjectRenderer extends \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer
{
/**
* Returns all parents of the given PID (Page UID) list
*
* #param string $pidList A list of page Content-Element PIDs (Page UIDs) / stdWrap
* #param array $pidConf stdWrap array for the list
* #return string A list of PIDs
* #internal
*/
public function getSlidePids($pidList, $pidConf)
{
// todo: phpstan states that $pidConf always exists and is not nullable. At the moment, this is a false positive
// as null can be passed into this method via $pidConf. As soon as more strict types are used, this isset
// check must be replaced with a more appropriate check like empty or count.
$pidList = isset($pidConf) ? trim($this->stdWrap($pidList, $pidConf)) : trim($pidList);
if ($pidList === '') {
$pidList = 'this';
}
$tsfe = $this->getTypoScriptFrontendController();
$listArr = null;
if (trim($pidList)) {
$listArr = GeneralUtility::intExplode(',', str_replace('this', (string)$tsfe->contentPid, $pidList));
$listArr = $this->checkPidArray($listArr);
}
$pidList = [];
if (is_array($listArr) && !empty($listArr)) {
foreach ($listArr as $uid) {
$page = $tsfe->sys_page->getPage($uid);
if($page['doktype'] == PageRepository::DOKTYPE_SYSFOLDER)
break;
if (!$page['is_siteroot']) {
$pidList[] = $page['pid'];
}
}
}
return implode(',', $pidList);
}
}

Doctrine Custom ID with auto increment

I want to define some id with prefix.
For example, for one order entity its : "OR17000001"
In this example, the prefix is "OR17"
So i have declare my id entities like this :
/**
* #var string
*
* #ORM\Column(name="id", type="string", length=8)
* #ORM\Id
* #ORM\GeneratedValue(strategy="CUSTOM")
* #ORM\CustomIdGenerator(class="My\Bundle\Generator\OrderCodeGenerator")
*/
private $id;
And my Generator is :
<?php
namespace My\Bundle\Generator;
use Doctrine\ORM\Id\AbstractIdGenerator;
use Doctrine\ORM\EntityManager;
use My\Bundle\Entity\Order;
class OrderCodeGenerator extends AbstractIdGenerator
{
/**
* Format :
* $prefix - string
* $year - take 2 first letters (17)
* $increment - Take the last code + 1
*
* #param EntityManager $em
* #param \Doctrine\ORM\Mapping\Entity $entity
* #return bool|string
*/
public function generate(EntityManager $em, $entity)
{
if ($entity instanceof Order) {
$now = new \DateTime();
$year = $now->format('y');
$prefix = 'OR';
$maxCode = $em->getRepository('MyRepo:Order')->findMaxCode($year, $prefix);
if ($maxCode) {
$increment = substr($maxCode[1], -4);
$increment = (int)$increment + 1;
} else
$increment = 0;
$code = $prefix . $year . sprintf('%04d', $increment);
return $code;
}
return false;
}
}
Without forget the method findMaxCode :
public function findMaxCode($year, $prefix)
{
$qb = $this->createQueryBuilder('entity');
$qb->where($qb->expr()->like('entity.id', ':code'))
->setParameter('code', '%' . $prefix . $year . '%');
$qb->select($qb->expr()->max('entity.id'));
return $qb->getQuery()->getOneOrNullResult();
}
That's work fine =)
My problem is when i try to add some entities in same time.
My case is :
Order entity with some items (its a form collection)
Item entity
So i need to custom id of Items Order with this strategy. And the problem is for found the max code. I have this error :
SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicata du
champ 'IT170000001' pour la clef 'PRIMARY'
The generator can't found the max code for generate the second item, because there is no flush.
How can i save the increment value between 2 id generation before the flush ??
Solution :
I keep numeric id for my Item. Its useful for my Order entity, its more readable than an simple int. But i don't care for Item.
Thx to Honza Rydrych
Querying DB for last inserted ID and then inserting "+one" isn't reliable solution.
My solution for this case would be let doctrine generate ID's by the standard way and add the prefix "OR/Year/" when you need to present the data.
(Optionaly you can write custom Twig extension for presenting the ID http://symfony.com/doc/current/templating/twig_extension.html)

TYPO3: Set more than one storage pid for one extension

I builded an extension that has a 'details' table that holds details with a title and a description that be included inline to another object. Right now new details are stored in the same pid as the object, but I'd like to change that.
this question was answered by Merec and in the comments he points to a solution (add the column "pid" to your model, this is the first the model looks at) but asked to formulate a separate question for it ...
I took his suggestion but could not get it to work, so here is the separate question, in addition I would like to know how to get a value from the configuration to be used as pid for this.
update: René Pflamm pointed out that I should underline that I'm trying to set this Pid for saving in the backend, not in the frontend ... I basically recognized this destinction later on
my constants.ts :
plugin.tx_myext {
persistence {
# cat=plugin.tx_myext/storage/a; type=string; label=Default storage PID
defaultStoragePid =
# cat=plugin.tx_myext/storage/a; type=string; label=Details storage PID
detailsStoragePid =
}
}
my setup.ts
plugin.tx_myext {
persistence {
storagePid = {$plugin.tx_myext.persistence.defaultStoragePid}
detailPid = {$plugin.tx_myext.persistence.detailsStoragePid}
}
}
I am not sure if I understood you correctly but you can tell extbase to look in multiple pids for your records and state for each record where it should be stored:
plugin.tx_myext {
persistence {
storagePid = {$plugin.tx_myext.persistence.defaultStoragePid},{$plugin.tx_myext.persistence.detailStoragePid}
classes {
Vendor\MyExt\Domain\Model\Detail {
newRecordStoragePid = {$plugin.tx_myext.persistence.detailStoragePid}
}
}
}
}
Models inherits from TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject which has getter and setter for $pid. If you set the field, all automation to set the field (i.e. newRecordStoragePid in typoscript) are not used.
With this, you can set all storage locations you want.
$myModel = $this->objectManager->create('Vendor\\Namespace\\Domain\\Model\\MyModel');
$myModel->setPid(4321);
Part from TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject:
/**
* #var int The id of the page the record is "stored".
*/
protected $pid;
/**
* Setter for the pid.
*
* #param int|NULL $pid
* #return void
*/
public function setPid($pid)
{
if ($pid === null) {
$this->pid = null;
} else {
$this->pid = (int)$pid;
}
}
/**
* Getter for the pid.
*
* #return int The pid or NULL if none set yet.
*/
public function getPid()
{
if ($this->pid === null) {
return null;
} else {
return (int)$this->pid;
}
}
You can, when create elements in your extension, say the model which pid should be use.
In your TS:
plugin.tx_myext.settings {
detailPid = {$plugin.tx_myext.persistence.detailsStoragePid}
}
In your code above it can look like:
public function createDetailsAction(Detail $detail) {
$detail->setPid($this->settings['detailPid']);
$this->detailRepository->add($detail);
}

How to dynamically change serialized groups in symfony jms fosrestbundle?

Hello I'd like to dynamically change the groups of my serialization context.
The code :
/**
* #Rest\Get("", name="bap_api_space_query")
* #Rest\View(serializerGroups={"Default", "space_dashboard", "dashboard_resource"})
*
* #ApiDoc(resource=true,description="List all spaces this user has access to")
*/
public function queryAction(Request $request)
{
$user = $this->getUser()->reload();
$organization = $user->getOrganization();
// depending the request, remove or add serialized group
// for example $view->setSerializationGroups('dashboard');
return $organization->getSpaces();
}
As commented in the code, i'd like to remove or add group in the controller .
Is there a way to do it ?
The solution is pretty easy after 5hours of research :
public function queryAction(Request $request)
{
$user = $this->getUser()->reload();
$organization = $user->getOrganization();
// filter spaces where org has an active contract
$context = new Context();
$context->setGroups(array('Default'));
$spaces = $organization->getSpaces();
$view = $this->view($spaces, 200);
$view->setContext($context);
return $this->handleView($view);
}

How do I get the "converted" action name for Zend Framework MVC?

I know update-profile-picture translates to the updateProfilePictureAction() function.
Where does the conversion of the action param take place?
I'd like to get updateProfilePicture as a value, I could write the function but it must already be in the library somewhere.
When using $this->_getParam('action') it returns update-profile-picture;
/**
* Auto call scripts
* #see Zend_Controller_Action::postDispatch()
*/
public function postDispatch(){
$action = $this->_getParam('action',false);
$method = $action.'Scripts';
if ($action && method_exists($this, $method))
$this->$method();
}
this works fine for indexAction - indexScripts but not for updateProfilePictureScripts (looking for update-profile-pictureScripts)
Get it with
$this->getFrontController()->getDispatcher()->formatActionName($this->_getParam('action',null));
It is happening in
/Zend/Controller/Dispatcher/Abstract.php
/**
* Formats a string into an action name. This is used to take a raw
* action name, such as one that would be stored inside a Zend_Controller_Request_Abstract
* object, and reformat into a proper method name that would be found
* inside a class extending Zend_Controller_Action.
*
* #param string $unformatted
* #return string
*/
public function formatActionName($unformatted)
{
$formatted = $this->_formatName($unformatted, true);
return strtolower(substr($formatted, 0, 1)) . substr($formatted, 1) . 'Action';
}
/**
* Formats a string from a URI into a PHP-friendly name.
*
* By default, replaces words separated by the word separator character(s)
* with camelCaps. If $isAction is false, it also preserves replaces words
* separated by the path separation character with an underscore, making
* the following word Title cased. All non-alphanumeric characters are
* removed.
*
* #param string $unformatted
* #param boolean $isAction Defaults to false
* #return string
*/
protected function _formatName($unformatted, $isAction = false)
{
// preserve directories
if (!$isAction) {
$segments = explode($this->getPathDelimiter(), $unformatted);
} else {
$segments = (array) $unformatted;
}
foreach ($segments as $key => $segment) {
$segment = str_replace($this->getWordDelimiter(), ' ', strtolower($segment));
$segment = preg_replace('/[^a-z0-9 ]/', '', $segment);
$segments[$key] = str_replace(' ', '', ucwords($segment));
}
return implode('_', $segments);
}
Have a look at Zend_Filter_Inflector : http://framework.zend.com/manual/en/zend.filter.inflector.html