Beispiel #1
0
 /**
  * Builds a data map by adding column maps for all the configured columns in the $TCA.
  * It also resolves the type of values the column is holding and the typo of relation the column
  * represents.
  *
  * @param string $className The class name you want to fetch the Data Map for
  * @return \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMap The data map
  */
 public function buildDataMap($className)
 {
     $dataMap = $this->dataMapCache->get(str_replace('\\', '%', $className));
     if ($dataMap === FALSE) {
         $dataMap = $this->buildDataMapInternal($className);
         $this->dataMapCache->set(str_replace('\\', '%', $className), $dataMap);
     }
     return $dataMap;
 }
 /**
  * Clears cache of pages where an object with the given identifier is shown
  * 
  * @param string $classIdentifier
  * @return int|mixed
  */
 public function getAutoId($classIdentifier)
 {
     $exclusiveLock = null;
     $objectIdentifier = 'autoid-' . $classIdentifier;
     $exclusiveLockAcquired = $this->acquireLock($exclusiveLock, $objectIdentifier, TRUE);
     $autoId = 0;
     if ($exclusiveLockAcquired) {
         if ($this->trackingCache->has($objectIdentifier)) {
             $autoId = $this->trackingCache->get($objectIdentifier);
         }
         $autoId++;
         $this->trackingCache->set($objectIdentifier, $autoId);
         $this->releaseLock($exclusiveLock);
     }
     return $autoId;
 }
 /**
  * Gets the page title of the given page id
  *
  * @param int $pageId
  * @return string
  */
 protected function getPageTitle($pageId)
 {
     $cacheId = 'recycler-pagetitle-' . $pageId;
     if ($this->runtimeCache->has($cacheId)) {
         $pageTitle = $this->runtimeCache->get($cacheId);
     } else {
         if ($pageId === 0) {
             $pageTitle = $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'];
         } else {
             $recordInfo = $this->tce->recordInfo('pages', $pageId, 'title');
             $pageTitle = $recordInfo['title'];
         }
         $this->runtimeCache->set($cacheId, $pageTitle);
     }
     return $pageTitle;
 }
Beispiel #4
0
 /**
  * Exports the internal reflection data into the ReflectionData cache.
  *
  * @throws Exception
  * @return void
  */
 protected function saveToCache()
 {
     if (!is_object($this->dataCache)) {
         throw new Exception('A cache must be injected before initializing the Reflection Service.', 1232044697);
     }
     $data = [];
     $propertyNames = ['reflectedClassNames', 'classPropertyNames', 'classTagsValues', 'methodTagsValues', 'methodParameters', 'methodReflections', 'propertyTagsValues', 'taggedClasses', 'classSchemata'];
     foreach ($propertyNames as $propertyName) {
         $data[$propertyName] = $this->{$propertyName};
     }
     $this->dataCache->set($this->cacheIdentifier, $data);
 }
 /**
  * @param string $id
  * @return object
  */
 public function findById($id)
 {
     $fullId = 'serialized-' . str_replace('\\', '_', get_class($this)) . '-' . $id;
     $object = null;
     if ($this->objectCache[$fullId]) {
         $object = $this->objectCache[$fullId];
     } elseif ($this->storage->has($fullId)) {
         $object = $this->unserialize($this->storage->get($fullId));
         $this->objectCache[$fullId] = $object;
     }
     return $object;
 }
    /**
     * @param array $parameters
     * @param PageLayoutView|DatabaseRecordList $caller
     * @return string
     */
    public function addSubIcon(array $parameters, $caller = NULL)
    {
        $this->attachAssets();
        list($table, $uid, $record) = $parameters;
        $icon = NULL;
        if (NULL !== $caller) {
            $record = NULL === $record && 0 < $uid ? BackendUtility::getRecord($table, $uid) : $record;
            $cacheIdentity = $table . $uid . sha1(serialize($record));
            // filter 1: icon must not already be cached and both record and caller must be provided.
            if (TRUE === $this->cache->has($cacheIdentity)) {
                $icon = $this->cache->get($cacheIdentity);
            } elseif (NULL !== $record) {
                $field = $this->detectFirstFlexTypeFieldInTableFromPossibilities($table, array_keys($record));
                // filter 2: table must have one field defined as "flex" and record must include it.
                if (NULL !== $field && TRUE === isset($record[$field])) {
                    // we check the cache here because at this point, the cache key is decidedly
                    // unique and we have not yet consulted the (potentially costly) Provider.
                    $provider = $this->fluxService->resolvePrimaryConfigurationProvider($table, $field, $record);
                    // filter 3: a Provider must be resolved for the record.
                    if (NULL !== $provider) {
                        $form = $provider->getForm((array) $record);
                        if (NULL !== $form) {
                            $icon = MiscellaneousUtility::getIconForTemplate($form);
                            if (NULL !== $icon) {
                                $label = trim($form->getLabel());
                                $icon = '<img width="16" height="16" src="' . $icon . '" alt="' . $label . '"
									title="' . $label . '" class="" />';
                                $icon = sprintf($this->templates['iconWrapper'], $icon);
                            }
                        }
                    }
                }
                $this->cache->set($cacheIdentity, $icon);
            }
        }
        return $icon;
    }
Beispiel #7
0
 /**
  * Hook for generating dynamic FlexForm source code.
  *
  * NOTE: patches data structure resolving in a way that solves
  * a regression in the TYPO3 core when dealing with IRRE AJAX
  * requests (in which the database record is no longer fetched
  * by the controller). This patches not only data structure
  * resolving for Flux data structures but indeed any data
  * structure built using hooks or involving user functions which
  * require the entire record (but when using hooks, supports
  * only extensions which are loaded AFTER or depend on Flux).
  *
  * @param array $dataStructArray
  * @param array $conf
  * @param array $row
  * @param string $table
  * @param string $fieldName
  * @return void
  */
 public function getFlexFormDS_postProcessDS(&$dataStructArray, $conf, &$row, $table, $fieldName)
 {
     if (empty($fieldName) === TRUE) {
         // Cast NULL if an empty but not-NULL field name was passed. This has significance to the Flux internals in
         // respect to which ConfigurationProvider(s) are returned.
         $fieldName = NULL;
     }
     if (!empty($fieldName) && !isset($row[$fieldName])) {
         // Patch required (possibly temporary). Due to changes in TYPO3 in the new FormEngine we must fetch the
         // database record at this point when the record is incomplete, which happens when attempting to render
         // IRRE records. The reason is that the controller that creates the HTML does not fetch the record any
         // more - and that the AJAX request contains only the UID. So, we fetch the record here to ensure it
         // contains the necessary fields. DOES NOT WORK FOR NEW RECORDS - SEE COMMENTS BELOW.
         $row = $this->recordService->getSingle($table, '*', $row['uid']);
     }
     $defaultDataSourceCacheIdentifier = $table . '_' . $fieldName . '_' . sha1(serialize($conf));
     if (!$row) {
         // In the case that the database record cannot be fetched we are dealing with a new or otherwise deleted
         // or unidentifiable record. This happens primarily when AJAX requests are made to render IRRE records
         // without the parent record having been saved first. To accommodate this case we have to be slightly
         // creative and store a "default" data source definition which is identified based on a checksum of the
         // configuration provided. Whenever we are then unable to fetch a record, we can at least attempt to
         // locate a default data source in previously cached content. NB: we enforce a VERY high cache lifetime
         // and continually refresh it every time it is possible to render a new DS that can serve as default.
         $dataStructArray = (array) $this->cache->get($defaultDataSourceCacheIdentifier);
     } else {
         if (FALSE === is_array($dataStructArray)) {
             $dataStructArray = array();
         }
         $providers = $this->configurationService->resolveConfigurationProviders($table, $fieldName, $row);
         foreach ($providers as $provider) {
             $provider->postProcessDataStructure($row, $dataStructArray, $conf);
         }
         if (empty($dataStructArray)) {
             $dataStructArray = array('ROOT' => array('el' => array()));
         }
         $evaluationParameters = array();
         $this->cache->set($defaultDataSourceCacheIdentifier, $this->recursivelyEvaluateClosures($dataStructArray, $evaluationParameters), array(), time() + 31536000);
     }
     // Trigger TCEforms dimension patching only if required by TYPO3 version according to CompatibilityRegistry.
     if (CompatibilityRegistry::get('FluidTYPO3\\Flux\\Backend\\DynamicFlexForm::NEEDS_TCEFORMS_WRAPPER')) {
         $dataStructArray = $this->patchTceformsWrapper($dataStructArray);
     }
 }
 /**
  * Builds the page ID checking statement
  *
  * @param string $tableName The database table name
  * @param array &$sql The query parts
  * @param array $storagePageIds list of storage page ids
  * @throws \TYPO3\CMS\Extbase\Persistence\Generic\Exception\InconsistentQuerySettingsException
  * @return void
  */
 protected function addPageIdStatement($tableName, array &$sql, array $storagePageIds)
 {
     $tableColumns = $this->tableColumnCache->get($tableName);
     if ($tableColumns === FALSE) {
         $tableColumns = $this->databaseHandle->admin_get_fields($tableName);
         $this->tableColumnCache->set($tableName, $tableColumns);
     }
     if (is_array($GLOBALS['TCA'][$tableName]['ctrl']) && array_key_exists('pid', $tableColumns)) {
         $rootLevel = (int) $GLOBALS['TCA'][$tableName]['ctrl']['rootLevel'];
         if ($rootLevel) {
             if ($rootLevel === 1) {
                 $sql['additionalWhereClause'][] = $tableName . '.pid = 0';
             }
         } else {
             if (empty($storagePageIds)) {
                 throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception\InconsistentQuerySettingsException('Missing storage page ids.', 1365779762);
             }
             $sql['additionalWhereClause'][] = $tableName . '.pid IN (' . implode(', ', $storagePageIds) . ')';
         }
     }
 }
 /**
  * Builds the page ID checking statement
  *
  * @param string $tableName The database table name
  * @param string $tableAlias The table alias used in the query.
  * @param array $storagePageIds list of storage page ids
  * @throws InconsistentQuerySettingsException
  * @return string
  */
 protected function getPageIdStatement($tableName, $tableAlias, array $storagePageIds)
 {
     $pageIdStatement = '';
     $tableColumns = $this->tableColumnCache->get($tableName);
     if ($tableColumns === false) {
         $tableColumns = $this->databaseHandle->admin_get_fields($tableName);
         $this->tableColumnCache->set($tableName, $tableColumns);
     }
     if (is_array($GLOBALS['TCA'][$tableName]['ctrl']) && array_key_exists('pid', $tableColumns)) {
         $rootLevel = (int) $GLOBALS['TCA'][$tableName]['ctrl']['rootLevel'];
         switch ($rootLevel) {
             // Only in pid 0
             case 1:
                 return $tableAlias . '.pid = 0';
                 // Pid 0 and pagetree
             // Pid 0 and pagetree
             case -1:
                 if (empty($storagePageIds)) {
                     return $tableAlias . '.pid = 0';
                 }
                 $storagePageIds[] = 0;
                 break;
                 // Only pagetree or not set
             // Only pagetree or not set
             case 0:
                 if (empty($storagePageIds)) {
                     throw new InconsistentQuerySettingsException('Missing storage page ids.', 1365779762);
                 }
                 break;
                 // Invalid configuration
             // Invalid configuration
             default:
                 return '';
         }
         $pageIdStatement = $tableAlias . '.pid IN (' . implode(',', $this->databaseHandle->cleanIntArray($storagePageIds)) . ')';
     }
     return $pageIdStatement;
 }
Beispiel #10
0
 /**
  * Returns array of arrays with an index of all references found in record from table/uid
  * If the result is used to update the sys_refindex table then ->WSOL must NOT be TRUE (no workspace overlay anywhere!)
  *
  * @param string $tableName Table name from $GLOBALS['TCA']
  * @param int $uid Record UID
  * @return array|NULL Index Rows
  * @todo Define visibility
  */
 public function generateRefIndexData($tableName, $uid)
 {
     if (!isset($GLOBALS['TCA'][$tableName])) {
         return NULL;
     }
     $this->relations = array();
     // Fetch tableRelationFields and save them in cache if not there yet
     $cacheId = static::$cachePrefixTableRelationFields . $tableName;
     if (!$this->runtimeCache->has($cacheId)) {
         $tableRelationFields = $this->fetchTableRelationFields($tableName);
         $this->runtimeCache->set($cacheId, $tableRelationFields);
     } else {
         $tableRelationFields = $this->runtimeCache->get($cacheId);
     }
     // Return if there are no fields which could contain relations
     if ($tableRelationFields === '') {
         return $this->relations;
     }
     $deleteField = $GLOBALS['TCA'][$tableName]['ctrl']['delete'];
     if ($tableRelationFields === '*') {
         // If one field of a record is of type flex, all fields have to be fetched to be passed to BackendUtility::getFlexFormDS
         $selectFields = '*';
     } else {
         // otherwise only fields that might contain relations are fetched
         $selectFields = 'uid,' . $tableRelationFields . ($deleteField ? ',' . $deleteField : '');
     }
     // Get raw record from DB:
     $record = $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow($selectFields, $tableName, 'uid=' . (int) $uid);
     if (!is_array($record)) {
         return NULL;
     }
     // Initialize:
     $this->words_strings = array();
     $this->words = array();
     // Deleted:
     $deleted = $deleteField && $record[$deleteField] ? 1 : 0;
     // Get all relations from record:
     $recordRelations = $this->getRelations($tableName, $record);
     // Traverse those relations, compile records to insert in table:
     foreach ($recordRelations as $fieldName => $fieldRelations) {
         // Based on type,
         switch ((string) $fieldRelations['type']) {
             case 'db':
                 $this->createEntryData_dbRels($tableName, $uid, $fieldName, '', $deleted, $fieldRelations['itemArray']);
                 break;
             case 'file_reference':
                 // not used (see getRelations()), but fallback to file
             // not used (see getRelations()), but fallback to file
             case 'file':
                 $this->createEntryData_fileRels($tableName, $uid, $fieldName, '', $deleted, $fieldRelations['newValueFiles']);
                 break;
             case 'flex':
                 // DB references:
                 if (is_array($fieldRelations['flexFormRels']['db'])) {
                     foreach ($fieldRelations['flexFormRels']['db'] as $flexPointer => $subList) {
                         $this->createEntryData_dbRels($tableName, $uid, $fieldName, $flexPointer, $deleted, $subList);
                     }
                 }
                 // File references in flexforms
                 // @todo #65463 Test correct handling of file references in flexforms
                 if (is_array($fieldRelations['flexFormRels']['file'])) {
                     foreach ($fieldRelations['flexFormRels']['file'] as $flexPointer => $subList) {
                         $this->createEntryData_fileRels($tableName, $uid, $fieldName, $flexPointer, $deleted, $subList);
                     }
                 }
                 // Soft references in flexforms
                 // @todo #65464 Test correct handling of soft references in flexforms
                 if (is_array($fieldRelations['flexFormRels']['softrefs'])) {
                     foreach ($fieldRelations['flexFormRels']['softrefs'] as $flexPointer => $subList) {
                         $this->createEntryData_softreferences($tableName, $uid, $fieldName, $flexPointer, $deleted, $subList['keys']);
                     }
                 }
                 break;
         }
         // Soft references in the field:
         if (is_array($fieldRelations['softrefs'])) {
             $this->createEntryData_softreferences($tableName, $uid, $fieldName, '', $deleted, $fieldRelations['softrefs']['keys']);
         }
     }
     return $this->relations;
 }
Beispiel #11
0
 /**
  * Saves the value of a PHP variable in the query cache.
  *
  * @param string $entryIdentifier An identifier used for this cache entry
  * @param mixed $variable The query to cache
  * @return void
  */
 protected function setQueryCacheEntry($entryIdentifier, $variable)
 {
     $this->queryRuntimeCache[$entryIdentifier] = $variable;
     $this->queryCache->set($entryIdentifier, $variable, array(), 0);
 }
Beispiel #12
0
 /**
  * Resets the elements to be deleted in the registry.
  *
  * @return void
  * @see process_datamap
  */
 protected function resetElementsToBeDeleted()
 {
     $this->runtimeCache->remove('core-datahandler-elementsToBeDeleted');
 }
 /**
  * @param string $extensionKey
  * @param string $version
  * @param array $segments
  * @return array
  */
 protected function getSchemaData($extensionKey, $version, $segments)
 {
     if (FALSE === ExtensionManagementUtility::isLoaded($extensionKey)) {
         return array();
     }
     $baseCacheKey = $extensionKey . $version;
     $baseCacheKey = preg_replace('/[^a-z0-9]+/i', '-', $baseCacheKey);
     $cacheKey = $baseCacheKey . implode('', $segments);
     if (TRUE === $this->cache->has($cacheKey)) {
         return $this->cache->get($cacheKey);
     }
     $className = implode('/', $segments);
     $url = GeneralUtility::getIndpEnv('TYPO3_REQUEST_URL');
     $schemaFile = $this->getXsdStoragePathSetting() . $extensionKey . '-' . $version . '.xsd';
     $schemaFile = GeneralUtility::getFileAbsFileName($schemaFile);
     $schemaSource = shell_exec('cat ' . $schemaFile . ' | tr -cd \'[:print:]\\r\\n\\t\'');
     $document = new \DOMDocument();
     $document->validateOnParse = TRUE;
     $document->strictErrorChecking = TRUE;
     $document->loadXML($schemaSource);
     if (TRUE === $this->cache->has($baseCacheKey . 'tree')) {
         $tree = $this->cache->get($baseCacheKey . 'tree');
     } else {
         $tree = $this->buildTreeFromSchema($document);
         $this->cache->set($baseCacheKey . 'tree', $tree);
     }
     $node = $this->findCurrentViewHelperNode($document, $segments);
     $targetNamespaceUrl = $document->documentElement->getAttribute('targetNamespace');
     if (0 < count($segments)) {
         $viewHelperArguments = $this->makeArgumentDefinitions($node, $extensionKey, $className);
         $docComment = $node->getElementsByTagName('documentation')->item(0)->nodeValue;
         $additionalDocumentationFile = ExtensionManagementUtility::extPath($extensionKey, 'Documentation/Classes/ViewHelpers/' . $className . '/README.md');
         $nextDiv = FALSE;
         if (TRUE === file_exists($additionalDocumentationFile)) {
             $alerts = array('warning', 'danger', 'success', 'info');
             $additionalDocumentation = file_get_contents($additionalDocumentationFile);
             $parts = explode('```', $additionalDocumentation);
             foreach ($parts as $index => &$part) {
                 $firstText = substr($part, 0, strpos($part, LF));
                 if (TRUE === in_array($firstText, $alerts)) {
                     $part = '<span class="alert alert-' . $firstText . '"><span class="lead">' . ucfirst($firstText) . '</span><br />' . substr($part, strlen($firstText));
                     $nextDiv = TRUE;
                 } else {
                     if (TRUE === $nextDiv) {
                         $part = '</span>' . $part;
                         $nextDiv = FALSE;
                     } elseif (0 < $index) {
                         $part = '```' . $part;
                     }
                 }
             }
             $additionalDocumentation = implode('', $parts);
             $additionalDocumentation = preg_replace('/Arguments\\/([a-z0-9^\\s\\/]+)\\.md/i', $url . '#argument-$1', $additionalDocumentation);
             $additionalDocumentation = preg_replace('/(```)([a-z\\s]+)(.[\\`]{3})(```)/i', $url . '<div class="alert alert-$1">$2</div>', $additionalDocumentation);
             $docComment .= LF . LF . $additionalDocumentation;
         }
     }
     $data = array($tree, $node, $viewHelperArguments, $docComment, $targetNamespaceUrl);
     $this->cache->set($cacheKey, $data);
     return $data;
 }
Beispiel #14
0
 /**
  * sets the cache for the id
  *
  * @param string $id
  * @param mixed $value
  */
 public function set($id, $value)
 {
     $this->level1Cache[$id] = $value;
     $this->level2Cache->set($id, $value);
 }
 /**
  * Creates a SELECT prepared SQL statement.
  *
  * @param string $select_fields See exec_SELECTquery()
  * @param string $from_table See exec_SELECTquery()
  * @param string $where_clause See exec_SELECTquery()
  * @param string $groupBy See exec_SELECTquery()
  * @param string $orderBy See exec_SELECTquery()
  * @param string $limit See exec_SELECTquery()
  * @param array $input_parameters An array of values with as many elements as there are bound parameters in the SQL statement being executed. All values are treated as \TYPO3\CMS\Core\Database\PreparedStatement::PARAM_AUTOTYPE.
  * @return \TYPO3\CMS\Core\Database\PreparedStatement Prepared statement
  */
 public function prepare_SELECTquery($select_fields, $from_table, $where_clause, $groupBy = '', $orderBy = '', $limit = '', array $input_parameters = array())
 {
     $pt = $this->debug ? GeneralUtility::milliseconds() : 0;
     $precompiledParts = array();
     if ($this->queryCache) {
         $cacheKey = 'prepare_SELECTquery-' . \TYPO3\CMS\Dbal\QueryCache::getCacheKey(array('selectFields' => $select_fields, 'fromTable' => $from_table, 'whereClause' => $where_clause, 'groupBy' => $groupBy, 'orderBy' => $orderBy, 'limit' => $limit));
         if ($this->queryCache->has($cacheKey)) {
             $precompiledParts = $this->queryCache->get($cacheKey);
             if ($this->debug) {
                 $data = array('args' => array($from_table, $select_fields, $where_clause, $groupBy, $orderBy, $limit, $input_parameters), 'precompiledParts' => $precompiledParts);
                 $this->debugHandler('prepare_SELECTquery (cache hit)', GeneralUtility::milliseconds() - $pt, $data);
             }
         }
     }
     $ORIG_tableName = '';
     if (empty($precompiledParts)) {
         // Map table / field names if needed:
         $ORIG_tableName = $from_table;
         // Saving table names in $ORIG_from_table since $from_table is transformed beneath:
         $parsedFromTable = array();
         $queryComponents = array();
         if ($tableArray = $this->map_needMapping($ORIG_tableName, FALSE, $parsedFromTable)) {
             $from = $parsedFromTable ? $parsedFromTable : $from_table;
             $components = $this->map_remapSELECTQueryParts($select_fields, $from, $where_clause, $groupBy, $orderBy);
             $queryComponents['SELECT'] = $components[0];
             $queryComponents['FROM'] = $components[1];
             $queryComponents['WHERE'] = $components[2];
             $queryComponents['GROUPBY'] = $components[3];
             $queryComponents['ORDERBY'] = $components[4];
             $queryComponents['parameters'] = $components[5];
         } else {
             $queryComponents = $this->getQueryComponents($select_fields, $from_table, $where_clause, $groupBy, $orderBy, $limit);
         }
         $queryComponents['ORIG_tableName'] = $ORIG_tableName;
         if (!$this->runningNative()) {
             // Quotes all fields
             $queryComponents['SELECT'] = $this->_quoteFieldNames($queryComponents['SELECT']);
             $queryComponents['FROM'] = $this->_quoteFromTables($queryComponents['FROM']);
             $queryComponents['WHERE'] = $this->_quoteWhereClause($queryComponents['WHERE']);
             $queryComponents['GROUPBY'] = $this->_quoteGroupBy($queryComponents['GROUPBY']);
             $queryComponents['ORDERBY'] = $this->_quoteOrderBy($queryComponents['ORDERBY']);
         }
         $precompiledParts = $this->precompileSELECTquery($queryComponents);
         if ($this->queryCache) {
             try {
                 $this->queryCache->set($cacheKey, $precompiledParts);
             } catch (\TYPO3\CMS\Core\Cache\Exception $e) {
                 if ($this->debug) {
                     GeneralUtility::devLog($e->getMessage(), 'dbal', 1);
                 }
             }
         }
     }
     $preparedStatement = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Database\PreparedStatement::class, '', $from_table, $precompiledParts);
     /* @var $preparedStatement \TYPO3\CMS\Core\Database\PreparedStatement */
     // Bind values to parameters
     foreach ($input_parameters as $key => $value) {
         $preparedStatement->bindValue($key, $value, \TYPO3\CMS\Core\Database\PreparedStatement::PARAM_AUTOTYPE);
     }
     if ($this->debug) {
         $data = array('args' => array($from_table, $select_fields, $where_clause, $groupBy, $orderBy, $limit, $input_parameters), 'ORIG_from_table' => $ORIG_tableName);
         $this->debugHandler('prepare_SELECTquery', GeneralUtility::milliseconds() - $pt, $data);
     }
     // Return prepared statement
     return $preparedStatement;
 }
 /**
  * Flush the complete tracking info 
  */
 public function flushTrackingInfo()
 {
     $this->trackingCache->flush();
 }
 /**
  * @return void
  */
 public function flushCache()
 {
     $this->cache->flush();
 }