first commit
This commit is contained in:
commit
1218dd1517
12716 files changed
+989233
No files matched your search
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* A generic Persistence exception
|
||||
*/
|
||||
class Exception extends \TYPO3\CMS\Extbase\Exception
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Exception;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* An "Invalid Object Type" exception
|
||||
*/
|
||||
class IllegalObjectTypeException extends \TYPO3\CMS\Extbase\Persistence\Exception
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Exception;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* An "Illegal Relation Type" exception
|
||||
*/
|
||||
class IllegalRelationTypeException extends \TYPO3\CMS\Extbase\Persistence\Exception
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Exception;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* An "Invalid Query" Exception
|
||||
*/
|
||||
class InvalidQueryException extends \TYPO3\CMS\Extbase\Exception
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Exception;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* An "Unknown Object" exception
|
||||
*/
|
||||
class UnknownObjectException extends \TYPO3\CMS\Extbase\Persistence\Exception
|
||||
{
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* A persistence backend interface
|
||||
*/
|
||||
interface BackendInterface
|
||||
{
|
||||
/**
|
||||
* Set a PersistenceManager instance.
|
||||
*
|
||||
* @param \TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface $persistenceManager
|
||||
*/
|
||||
public function setPersistenceManager(\TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface $persistenceManager);
|
||||
|
||||
/**
|
||||
* Sets the aggregate root objects
|
||||
*
|
||||
* @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage $objects
|
||||
*/
|
||||
public function setAggregateRootObjects(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $objects);
|
||||
|
||||
/**
|
||||
* Sets the deleted entities
|
||||
*
|
||||
* @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage $entities
|
||||
*/
|
||||
public function setDeletedEntities(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $entities);
|
||||
|
||||
/**
|
||||
* Sets the changed objects
|
||||
*
|
||||
* @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage $entities
|
||||
*/
|
||||
public function setChangedEntities(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $entities);
|
||||
|
||||
/**
|
||||
* Commits the current persistence session
|
||||
*/
|
||||
public function commit();
|
||||
|
||||
// @todo refactor towards being closer to the Flow backend interface again
|
||||
|
||||
/**
|
||||
* Returns the (internal) identifier for the object, if it is known to the
|
||||
* backend. Otherwise NULL is returned.
|
||||
*
|
||||
* @param object $object
|
||||
* @return string|null The identifier for the object if it is known, or NULL
|
||||
*/
|
||||
public function getIdentifierByObject($object);
|
||||
|
||||
/**
|
||||
* Returns the object with the (internal) identifier, if it is known to the
|
||||
* backend. Otherwise NULL is returned.
|
||||
*
|
||||
* @param string $identifier
|
||||
* @param string $className
|
||||
* @return object|null The object for the identifier if it is known, or NULL
|
||||
*/
|
||||
public function getObjectByIdentifier($identifier, $className);
|
||||
|
||||
/**
|
||||
* Checks if the given object has ever been persisted.
|
||||
*
|
||||
* @param object $object The object to check
|
||||
* @return bool TRUE if the object is new, FALSE if the object exists in the repository
|
||||
*/
|
||||
public function isNewObject($object);
|
||||
|
||||
/**
|
||||
* Returns the number of records matching the query.
|
||||
*
|
||||
* @param \TYPO3\CMS\Extbase\Persistence\QueryInterface $query
|
||||
* @return int
|
||||
*/
|
||||
public function getObjectCountByQuery(\TYPO3\CMS\Extbase\Persistence\QueryInterface $query);
|
||||
|
||||
/**
|
||||
* Returns the object data matching the $query.
|
||||
*
|
||||
* @param \TYPO3\CMS\Extbase\Persistence\QueryInterface $query
|
||||
* @return array
|
||||
*/
|
||||
public function getObjectDataByQuery(\TYPO3\CMS\Extbase\Persistence\QueryInterface $query);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* A generic Persistence exception
|
||||
*/
|
||||
class Exception extends \TYPO3\CMS\Extbase\Persistence\Exception
|
||||
{
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic\Exception;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* Thrown if a setting set is not available in the current context.
|
||||
*/
|
||||
class InconsistentQuerySettingsException extends \TYPO3\CMS\Extbase\Persistence\Generic\Exception
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic\Exception;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* An "Invalid Class" exception
|
||||
*/
|
||||
class InvalidClassException extends \TYPO3\CMS\Extbase\Persistence\Generic\Exception
|
||||
{
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic\Exception;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* An "Invalid Number of Constraints" exception.
|
||||
*/
|
||||
class InvalidNumberOfConstraintsException extends \TYPO3\CMS\Extbase\Persistence\Generic\Exception
|
||||
{
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic\Exception;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* An "InvalidRelationConfigurationException" exception
|
||||
*/
|
||||
class InvalidRelationConfigurationException extends \TYPO3\CMS\Extbase\Persistence\Generic\Exception
|
||||
{
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic\Exception;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* A "Missing ColumnMap" exception
|
||||
*/
|
||||
class MissingColumnMapException extends \TYPO3\CMS\Extbase\Persistence\Generic\Exception
|
||||
{
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic\Exception;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* An "NotImplementedException" exception
|
||||
*/
|
||||
class NotImplementedException extends \TYPO3\CMS\Extbase\Persistence\Exception
|
||||
{
|
||||
/**
|
||||
* @param string $method
|
||||
* @param int $exceptionCode
|
||||
*/
|
||||
public function __construct($method, int $exceptionCode = null)
|
||||
{
|
||||
parent::__construct(sprintf('Method %s is not supported by generic persistence"', $method), $exceptionCode ?? 1350213237);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic\Exception;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* Main exception thrown by classes in this package. May contain an error
|
||||
* message and/or another nested exception.
|
||||
*/
|
||||
class RepositoryException extends \RuntimeException
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic\Exception;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* A "Too Dirty" exception
|
||||
*/
|
||||
class TooDirtyException extends \TYPO3\CMS\Extbase\Persistence\Generic\Exception
|
||||
{
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic\Exception;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* An "Unexpected Type" exception.
|
||||
*/
|
||||
class UnexpectedTypeException extends \TYPO3\CMS\Extbase\Persistence\Generic\Exception
|
||||
{
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic\Exception;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* An "Unsupported Method" exception
|
||||
*/
|
||||
class UnsupportedMethodException extends \TYPO3\CMS\Extbase\Persistence\Generic\Exception
|
||||
{
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic\Exception;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* An "Unsupported Order" exception: The order you specified in the query is not supported by now.
|
||||
*/
|
||||
class UnsupportedOrderException extends \TYPO3\CMS\Extbase\Persistence\Generic\Exception
|
||||
{
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic\Exception;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* An "Unsupported Order" exception: The order you specified in the query is not supported by now.
|
||||
*/
|
||||
class UnsupportedRelationException extends \TYPO3\CMS\Extbase\Persistence\Generic\Exception
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,249 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
use TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject;
|
||||
use TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface;
|
||||
use TYPO3\CMS\Extbase\Object\ObjectManagerInterface;
|
||||
use TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapper;
|
||||
|
||||
/**
|
||||
* A proxy that can replace any object and replaces itself in it's parent on
|
||||
* first access (call, get, set, isset, unset).
|
||||
* @internal only to be used within Extbase, not part of TYPO3 Core API.
|
||||
*/
|
||||
class LazyLoadingProxy implements \Iterator, LoadingStrategyInterface
|
||||
{
|
||||
/**
|
||||
* @var ?DataMapper
|
||||
*/
|
||||
protected $dataMapper;
|
||||
|
||||
/**
|
||||
* The object this property is contained in.
|
||||
*
|
||||
* @var DomainObjectInterface
|
||||
*/
|
||||
private $parentObject;
|
||||
|
||||
/**
|
||||
* The name of the property represented by this proxy.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $propertyName;
|
||||
|
||||
/**
|
||||
* The raw field value.
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
private $fieldValue;
|
||||
|
||||
/**
|
||||
* @var ObjectManagerInterface
|
||||
*/
|
||||
protected $objectManager;
|
||||
|
||||
/**
|
||||
* @param ObjectManagerInterface $objectManager
|
||||
*/
|
||||
public function injectObjectManager(ObjectManagerInterface $objectManager)
|
||||
{
|
||||
$this->objectManager = $objectManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs this proxy instance.
|
||||
*
|
||||
* @param DomainObjectInterface $parentObject The object instance this proxy is part of
|
||||
* @param string $propertyName The name of the proxied property in it's parent
|
||||
* @param mixed $fieldValue The raw field value.
|
||||
* @param ?DataMapper $dataMapper
|
||||
*/
|
||||
public function __construct($parentObject, $propertyName, $fieldValue, ?DataMapper $dataMapper = null)
|
||||
{
|
||||
$this->parentObject = $parentObject;
|
||||
$this->propertyName = $propertyName;
|
||||
$this->fieldValue = $fieldValue;
|
||||
$this->dataMapper = $dataMapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Object initialization called when object is created with ObjectManager, after constructor
|
||||
*/
|
||||
public function initializeObject()
|
||||
{
|
||||
if (!$this->dataMapper) {
|
||||
$this->dataMapper = $this->objectManager->get(DataMapper::class);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate this proxy by asking the $population closure.
|
||||
*
|
||||
* @return object The instance (hopefully) returned
|
||||
*/
|
||||
public function _loadRealInstance()
|
||||
{
|
||||
// this check safeguards against a proxy being activated multiple times
|
||||
// usually that does not happen, but if the proxy is held from outside
|
||||
// its parent ... the result would be weird.
|
||||
if ($this->parentObject instanceof AbstractDomainObject
|
||||
&& $this->parentObject->_getProperty($this->propertyName) instanceof LazyLoadingProxy
|
||||
&& $this->dataMapper
|
||||
) {
|
||||
$objects = $this->dataMapper->fetchRelated($this->parentObject, $this->propertyName, $this->fieldValue, false);
|
||||
$propertyValue = $this->dataMapper->mapResultToPropertyValue($this->parentObject, $this->propertyName, $objects);
|
||||
$this->parentObject->_setProperty($this->propertyName, $propertyValue);
|
||||
$this->parentObject->_memorizeCleanState($this->propertyName);
|
||||
return $propertyValue;
|
||||
}
|
||||
return $this->parentObject->_getProperty($this->propertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function _getTypeAndUidString()
|
||||
{
|
||||
$type = $this->dataMapper->getType(get_class($this->parentObject), $this->propertyName);
|
||||
return $type . ':' . $this->fieldValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic method call implementation.
|
||||
*
|
||||
* @param string $methodName The name of the property to get
|
||||
* @param array $arguments The arguments given to the call
|
||||
* @return mixed
|
||||
*/
|
||||
public function __call($methodName, $arguments)
|
||||
{
|
||||
$realInstance = $this->_loadRealInstance();
|
||||
if (!is_object($realInstance)) {
|
||||
return null;
|
||||
}
|
||||
return call_user_func_array([$realInstance, $methodName], $arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic get call implementation.
|
||||
*
|
||||
* @param string $propertyName The name of the property to get
|
||||
* @return mixed
|
||||
*/
|
||||
public function __get($propertyName)
|
||||
{
|
||||
$realInstance = $this->_loadRealInstance();
|
||||
return $realInstance->{$propertyName};
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic set call implementation.
|
||||
*
|
||||
* @param string $propertyName The name of the property to set
|
||||
* @param mixed $value The value for the property to set
|
||||
*/
|
||||
public function __set($propertyName, $value)
|
||||
{
|
||||
$realInstance = $this->_loadRealInstance();
|
||||
$realInstance->{$propertyName} = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic isset call implementation.
|
||||
*
|
||||
* @param string $propertyName The name of the property to check
|
||||
* @return bool
|
||||
*/
|
||||
public function __isset($propertyName)
|
||||
{
|
||||
$realInstance = $this->_loadRealInstance();
|
||||
return isset($realInstance->{$propertyName});
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic unset call implementation.
|
||||
*
|
||||
* @param string $propertyName The name of the property to unset
|
||||
*/
|
||||
public function __unset($propertyName)
|
||||
{
|
||||
$realInstance = $this->_loadRealInstance();
|
||||
unset($realInstance->{$propertyName});
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic toString call implementation.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
$realInstance = $this->_loadRealInstance();
|
||||
return $realInstance->__toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current value of the storage array
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function current()
|
||||
{
|
||||
$realInstance = $this->_loadRealInstance();
|
||||
return current($realInstance);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current key storage array
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function key()
|
||||
{
|
||||
$realInstance = $this->_loadRealInstance();
|
||||
return key($realInstance);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next position of the storage array
|
||||
*/
|
||||
public function next()
|
||||
{
|
||||
$realInstance = $this->_loadRealInstance();
|
||||
next($realInstance);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the array pointer of the storage
|
||||
*/
|
||||
public function rewind()
|
||||
{
|
||||
$realInstance = $this->_loadRealInstance();
|
||||
reset($realInstance);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the array pointer of the storage points to a valid position
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function valid()
|
||||
{
|
||||
return $this->current() !== false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,343 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
use TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface;
|
||||
use TYPO3\CMS\Extbase\Object\ObjectManagerInterface;
|
||||
use TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapper;
|
||||
|
||||
/**
|
||||
* A proxy that can replace any object and replaces itself in it's parent on
|
||||
* first access (call, get, set, isset, unset).
|
||||
* @internal only to be used within Extbase, not part of TYPO3 Core API.
|
||||
*/
|
||||
class LazyObjectStorage extends \TYPO3\CMS\Extbase\Persistence\ObjectStorage implements \TYPO3\CMS\Extbase\Persistence\Generic\LoadingStrategyInterface
|
||||
{
|
||||
/**
|
||||
* This field is only needed to make debugging easier:
|
||||
* If you call current() on a class that implements Iterator, PHP will return the first field of the object
|
||||
* instead of calling the current() method of the interface.
|
||||
* We use this unusual behavior of PHP to return the warning below in this case.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $warning = 'You should never see this warning. If you do, you probably used PHP array functions like current() on the TYPO3\\CMS\\Extbase\\Persistence\\Generic\\LazyObjectStorage. To retrieve the first result, you can use the rewind() and current() methods.';
|
||||
|
||||
/**
|
||||
* @var ?DataMapper
|
||||
*/
|
||||
protected $dataMapper;
|
||||
|
||||
/**
|
||||
* The object this property is contained in.
|
||||
*
|
||||
* @var \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface
|
||||
*/
|
||||
protected $parentObject;
|
||||
|
||||
/**
|
||||
* The name of the property represented by this proxy.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $propertyName;
|
||||
|
||||
/**
|
||||
* The raw field value.
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
protected $fieldValue;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $isInitialized = false;
|
||||
|
||||
/**
|
||||
* @var ObjectManagerInterface
|
||||
*/
|
||||
protected $objectManager;
|
||||
|
||||
/**
|
||||
* @param ObjectManagerInterface $objectManager
|
||||
*/
|
||||
public function injectObjectManager(ObjectManagerInterface $objectManager)
|
||||
{
|
||||
$this->objectManager = $objectManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the state of the initialization
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isInitialized()
|
||||
{
|
||||
return $this->isInitialized;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs this proxy instance.
|
||||
*
|
||||
* @param DomainObjectInterface $parentObject The object instance this proxy is part of
|
||||
* @param string $propertyName The name of the proxied property in it's parent
|
||||
* @param mixed $fieldValue The raw field value.
|
||||
* @param ?DataMapper $dataMapper
|
||||
*/
|
||||
public function __construct($parentObject, $propertyName, $fieldValue, ?DataMapper $dataMapper = null)
|
||||
{
|
||||
$this->parentObject = $parentObject;
|
||||
$this->propertyName = $propertyName;
|
||||
$this->fieldValue = $fieldValue;
|
||||
reset($this->storage);
|
||||
$this->dataMapper = $dataMapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Object initialization called when object is created with ObjectManager, after constructor
|
||||
*/
|
||||
public function initializeObject()
|
||||
{
|
||||
if (!$this->dataMapper) {
|
||||
$this->dataMapper = $this->objectManager->get(DataMapper::class);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a function lazy load implementation.
|
||||
*/
|
||||
protected function initialize()
|
||||
{
|
||||
if (!$this->isInitialized) {
|
||||
$this->isInitialized = true;
|
||||
$objects = $this->dataMapper->fetchRelated($this->parentObject, $this->propertyName, $this->fieldValue, false);
|
||||
foreach ($objects as $object) {
|
||||
parent::attach($object);
|
||||
}
|
||||
$this->_memorizeCleanState();
|
||||
if (!$this->isStorageAlreadyMemorizedInParentCleanState()) {
|
||||
$this->parentObject->_memorizeCleanState($this->propertyName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
protected function isStorageAlreadyMemorizedInParentCleanState()
|
||||
{
|
||||
return $this->parentObject->_getCleanProperty($this->propertyName) === $this;
|
||||
}
|
||||
|
||||
// Delegation to the ObjectStorage methods below
|
||||
/**
|
||||
* @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage $storage
|
||||
*
|
||||
* @see \TYPO3\CMS\Extbase\Persistence\ObjectStorage::addAll
|
||||
*/
|
||||
public function addAll(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $storage)
|
||||
{
|
||||
$this->initialize();
|
||||
parent::addAll($storage);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param object $object The object to add.
|
||||
* @param mixed $data The data to associate with the object.
|
||||
*
|
||||
* @see \TYPO3\CMS\Extbase\Persistence\ObjectStorage::attach
|
||||
*/
|
||||
public function attach($object, $data = null)
|
||||
{
|
||||
$this->initialize();
|
||||
parent::attach($object, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param object $object The object to look for.
|
||||
* @return bool
|
||||
*
|
||||
* @see \TYPO3\CMS\Extbase\Persistence\ObjectStorage::contains
|
||||
*/
|
||||
public function contains($object)
|
||||
{
|
||||
$this->initialize();
|
||||
return parent::contains($object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts the elements in the storage array
|
||||
*
|
||||
* @throws Exception
|
||||
* @return int The number of elements in the ObjectStorage
|
||||
*/
|
||||
public function count()
|
||||
{
|
||||
$columnMap = $this->dataMapper->getDataMap(get_class($this->parentObject))->getColumnMap($this->propertyName);
|
||||
$numberOfElements = null;
|
||||
if (!$this->isInitialized && $columnMap->getTypeOfRelation() === Mapper\ColumnMap::RELATION_HAS_MANY) {
|
||||
$numberOfElements = $this->dataMapper->countRelated($this->parentObject, $this->propertyName, $this->fieldValue);
|
||||
} else {
|
||||
$this->initialize();
|
||||
$numberOfElements = count($this->storage);
|
||||
}
|
||||
if ($numberOfElements === null) {
|
||||
throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception('The number of elements could not be determined.', 1252514486);
|
||||
}
|
||||
return $numberOfElements;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return object The object at the current iterator position.
|
||||
*
|
||||
* @see \TYPO3\CMS\Extbase\Persistence\ObjectStorage::current
|
||||
*/
|
||||
public function current()
|
||||
{
|
||||
$this->initialize();
|
||||
return parent::current();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param object $object The object to remove.
|
||||
*
|
||||
* @see \TYPO3\CMS\Extbase\Persistence\ObjectStorage::detach
|
||||
*/
|
||||
public function detach($object)
|
||||
{
|
||||
$this->initialize();
|
||||
parent::detach($object);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string The index corresponding to the position of the iterator.
|
||||
*
|
||||
* @see \TYPO3\CMS\Extbase\Persistence\ObjectStorage::key
|
||||
*/
|
||||
public function key()
|
||||
{
|
||||
$this->initialize();
|
||||
return parent::key();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \TYPO3\CMS\Extbase\Persistence\ObjectStorage::next
|
||||
*/
|
||||
public function next()
|
||||
{
|
||||
$this->initialize();
|
||||
parent::next();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param object $value The object to look for, or the key in the storage.
|
||||
* @return bool
|
||||
*
|
||||
* @see \TYPO3\CMS\Extbase\Persistence\ObjectStorage::offsetExists
|
||||
*/
|
||||
public function offsetExists($value)
|
||||
{
|
||||
$this->initialize();
|
||||
return parent::offsetExists($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param object $value The object to look for, or its key in the storage.
|
||||
* @return mixed
|
||||
*
|
||||
* @see \TYPO3\CMS\Extbase\Persistence\ObjectStorage::offsetGet
|
||||
*/
|
||||
public function offsetGet($value)
|
||||
{
|
||||
$this->initialize();
|
||||
return parent::offsetGet($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param object $object The object to add.
|
||||
* @param mixed $info The data to associate with the object.
|
||||
*
|
||||
* @see \TYPO3\CMS\Extbase\Persistence\ObjectStorage::offsetSet
|
||||
*/
|
||||
public function offsetSet($object, $info)
|
||||
{
|
||||
$this->initialize();
|
||||
parent::offsetSet($object, $info);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param object $value The object to remove, or its key in the storage.
|
||||
*
|
||||
* @see \TYPO3\CMS\Extbase\Persistence\ObjectStorage::offsetUnset
|
||||
*/
|
||||
public function offsetUnset($value)
|
||||
{
|
||||
$this->initialize();
|
||||
parent::offsetUnset($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage $storage The storage containing the elements to remove.
|
||||
*
|
||||
* @see \TYPO3\CMS\Extbase\Persistence\ObjectStorage::removeAll
|
||||
*/
|
||||
public function removeAll(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $storage)
|
||||
{
|
||||
$this->initialize();
|
||||
parent::removeAll($storage);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \TYPO3\CMS\Extbase\Persistence\ObjectStorage::rewind
|
||||
*/
|
||||
public function rewind()
|
||||
{
|
||||
$this->initialize();
|
||||
parent::rewind();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*
|
||||
* @see \TYPO3\CMS\Extbase\Persistence\ObjectStorage::valid
|
||||
*/
|
||||
public function valid()
|
||||
{
|
||||
$this->initialize();
|
||||
return parent::valid();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*
|
||||
* @see \TYPO3\CMS\Extbase\Persistence\ObjectStorage::toArray
|
||||
*/
|
||||
public function toArray()
|
||||
{
|
||||
$this->initialize();
|
||||
return parent::toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $object
|
||||
* @return int|null
|
||||
*/
|
||||
public function getPosition($object)
|
||||
{
|
||||
$this->initialize();
|
||||
return parent::getPosition($object);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* An interface for the lazy loading strategies.
|
||||
*/
|
||||
interface LoadingStrategyInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,455 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic\Mapper;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* A column map to map a column configured in $TCA on a property of a domain object.
|
||||
* @internal only to be used within Extbase, not part of TYPO3 Core API.
|
||||
*/
|
||||
class ColumnMap
|
||||
{
|
||||
/**
|
||||
* Constants reflecting the type of relation
|
||||
*/
|
||||
const RELATION_NONE = 'RELATION_NONE';
|
||||
const RELATION_HAS_ONE = 'RELATION_HAS_ONE';
|
||||
const RELATION_HAS_MANY = 'RELATION_HAS_MANY';
|
||||
const RELATION_BELONGS_TO_MANY = 'RELATION_BELONGS_TO_MANY';
|
||||
const RELATION_HAS_AND_BELONGS_TO_MANY = 'RELATION_HAS_AND_BELONGS_TO_MANY';
|
||||
|
||||
/**
|
||||
* Constants reflecting how the relation information is stored
|
||||
*/
|
||||
const RELATION_PARENT_FOREIGN_KEY = 'RELATION_PARENT_FOREIGN_KEY';
|
||||
const RELATION_CHILD_FOREIGN_KEY = 'RELATION_CHILD_FOREIGN_KEY';
|
||||
const RELATION_PARENT_CSV = 'RELATION_PARENT_CSV';
|
||||
const RELATION_INTERMEDIATE_TABLE = 'RELATION_INTERMEDIATE_TABLE';
|
||||
|
||||
/**
|
||||
* Constants reflecting the loading strategy
|
||||
*/
|
||||
const STRATEGY_EAGER = 'eager';
|
||||
const STRATEGY_LAZY_PROXY = 'proxy';
|
||||
const STRATEGY_LAZY_STORAGE = 'storage';
|
||||
|
||||
/**
|
||||
* The property name corresponding to the table name
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $propertyName;
|
||||
|
||||
/**
|
||||
* The column name
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $columnName;
|
||||
|
||||
/**
|
||||
* The type of relation
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $typeOfRelation;
|
||||
|
||||
/**
|
||||
* The name of the child's class
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $childClassName;
|
||||
|
||||
/**
|
||||
* The name of the child's table
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $childTableName;
|
||||
|
||||
/**
|
||||
* The where clause to narrow down the selected child records
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $childTableWhereStatement;
|
||||
|
||||
/**
|
||||
* The name of the field the results from the child's table are sorted by
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $childSortByFieldName;
|
||||
|
||||
/**
|
||||
* The name of the relation table
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $relationTableName;
|
||||
|
||||
/**
|
||||
* The name of the column of the relation table holding the page id
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $relationTablePageIdColumnName;
|
||||
|
||||
/**
|
||||
* An array of field => value pairs to both insert and match against when writing/reading MM relations
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $relationTableMatchFields;
|
||||
|
||||
/**
|
||||
* Array of field=>value pairs to insert when writing new MM relations
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $relationTableInsertFields;
|
||||
|
||||
/**
|
||||
* The where clause to narrow down the selected relation table records
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $relationTableWhereStatement;
|
||||
|
||||
/**
|
||||
* The name of the field holding the parents key
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $parentKeyFieldName;
|
||||
|
||||
/**
|
||||
* The name of the field holding the name of the table of the parent's records
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $parentTableFieldName;
|
||||
|
||||
/**
|
||||
* The name of the field holding the children key
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $childKeyFieldName;
|
||||
|
||||
/**
|
||||
* Alternative format for storing DataTime formats
|
||||
* (instead of using unix-time stamps). Allowed values
|
||||
* are 'date', 'datetime' and 'time'
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $dateTimeStorageFormat;
|
||||
|
||||
/**
|
||||
* @var \TYPO3\CMS\Core\DataHandling\TableColumnType
|
||||
*/
|
||||
protected $type;
|
||||
|
||||
/**
|
||||
* @var \TYPO3\CMS\Core\DataHandling\TableColumnSubType
|
||||
*/
|
||||
protected $internalType;
|
||||
|
||||
/**
|
||||
* Constructs a Column Map
|
||||
*
|
||||
* @param string $columnName The column name
|
||||
* @param string $propertyName The property name
|
||||
*/
|
||||
public function __construct($columnName, $propertyName)
|
||||
{
|
||||
// @todo Enable aliases (tx_anotherextension_addedcolumn -> theAddedColumn)
|
||||
$this->setColumnName($columnName);
|
||||
$this->setPropertyName($propertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $typeOfRelation
|
||||
*/
|
||||
public function setTypeOfRelation($typeOfRelation)
|
||||
{
|
||||
$this->typeOfRelation = $typeOfRelation;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getTypeOfRelation()
|
||||
{
|
||||
return $this->typeOfRelation;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $propertyName
|
||||
*/
|
||||
public function setPropertyName($propertyName)
|
||||
{
|
||||
$this->propertyName = $propertyName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getPropertyName()
|
||||
{
|
||||
return $this->propertyName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $columnName
|
||||
*/
|
||||
public function setColumnName($columnName)
|
||||
{
|
||||
$this->columnName = $columnName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getColumnName()
|
||||
{
|
||||
return $this->columnName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $childTableName
|
||||
*/
|
||||
public function setChildTableName($childTableName)
|
||||
{
|
||||
$this->childTableName = $childTableName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getChildTableName()
|
||||
{
|
||||
return $this->childTableName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $childTableWhereStatement
|
||||
*/
|
||||
public function setChildTableWhereStatement($childTableWhereStatement)
|
||||
{
|
||||
$this->childTableWhereStatement = $childTableWhereStatement;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getChildTableWhereStatement()
|
||||
{
|
||||
return $this->childTableWhereStatement;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $childSortByFieldName
|
||||
*/
|
||||
public function setChildSortByFieldName($childSortByFieldName)
|
||||
{
|
||||
$this->childSortByFieldName = $childSortByFieldName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getChildSortByFieldName()
|
||||
{
|
||||
return $this->childSortByFieldName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $relationTableName
|
||||
*/
|
||||
public function setRelationTableName($relationTableName)
|
||||
{
|
||||
$this->relationTableName = $relationTableName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getRelationTableName()
|
||||
{
|
||||
return $this->relationTableName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $relationTablePageIdColumnName
|
||||
*/
|
||||
public function setRelationTablePageIdColumnName($relationTablePageIdColumnName)
|
||||
{
|
||||
$this->relationTablePageIdColumnName = $relationTablePageIdColumnName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getRelationTablePageIdColumnName()
|
||||
{
|
||||
return $this->relationTablePageIdColumnName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $relationTableMatchFields
|
||||
*/
|
||||
public function setRelationTableMatchFields(array $relationTableMatchFields)
|
||||
{
|
||||
$this->relationTableMatchFields = $relationTableMatchFields;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getRelationTableMatchFields()
|
||||
{
|
||||
return $this->relationTableMatchFields;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $relationTableInsertFields
|
||||
*/
|
||||
public function setRelationTableInsertFields(array $relationTableInsertFields)
|
||||
{
|
||||
$this->relationTableInsertFields = $relationTableInsertFields;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getRelationTableInsertFields()
|
||||
{
|
||||
return $this->relationTableInsertFields;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $relationTableWhereStatement
|
||||
*/
|
||||
public function setRelationTableWhereStatement($relationTableWhereStatement)
|
||||
{
|
||||
$this->relationTableWhereStatement = $relationTableWhereStatement;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getRelationTableWhereStatement()
|
||||
{
|
||||
return $this->relationTableWhereStatement;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $parentKeyFieldName
|
||||
*/
|
||||
public function setParentKeyFieldName($parentKeyFieldName)
|
||||
{
|
||||
$this->parentKeyFieldName = $parentKeyFieldName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getParentKeyFieldName()
|
||||
{
|
||||
return $this->parentKeyFieldName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $parentTableFieldName
|
||||
*/
|
||||
public function setParentTableFieldName($parentTableFieldName)
|
||||
{
|
||||
$this->parentTableFieldName = $parentTableFieldName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getParentTableFieldName()
|
||||
{
|
||||
return $this->parentTableFieldName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $childKeyFieldName
|
||||
*/
|
||||
public function setChildKeyFieldName($childKeyFieldName)
|
||||
{
|
||||
$this->childKeyFieldName = $childKeyFieldName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getChildKeyFieldName()
|
||||
{
|
||||
return $this->childKeyFieldName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $dateTimeStorageFormat
|
||||
*/
|
||||
public function setDateTimeStorageFormat($dateTimeStorageFormat)
|
||||
{
|
||||
$this->dateTimeStorageFormat = $dateTimeStorageFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getDateTimeStorageFormat()
|
||||
{
|
||||
return $this->dateTimeStorageFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \TYPO3\CMS\Core\DataHandling\TableColumnSubType $internalType
|
||||
*/
|
||||
public function setInternalType($internalType)
|
||||
{
|
||||
$this->internalType = $internalType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \TYPO3\CMS\Core\DataHandling\TableColumnSubType
|
||||
*/
|
||||
public function getInternalType()
|
||||
{
|
||||
return $this->internalType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \TYPO3\CMS\Core\DataHandling\TableColumnType $type
|
||||
*/
|
||||
public function setType($type)
|
||||
{
|
||||
$this->type = $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \TYPO3\CMS\Core\DataHandling\TableColumnType
|
||||
*/
|
||||
public function getType()
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,552 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic\Mapper;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* A data map to map a single table configured in $TCA on a domain object.
|
||||
* @internal only to be used within Extbase, not part of TYPO3 Core API.
|
||||
*/
|
||||
class DataMap
|
||||
{
|
||||
/**
|
||||
* The class name
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $className;
|
||||
|
||||
/**
|
||||
* The table name corresponding to the domain class configured in $TCA
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $tableName;
|
||||
|
||||
/**
|
||||
* The record type stored in the "type" field as configured in $TCA
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $recordType;
|
||||
|
||||
/**
|
||||
* The subclasses of the current class
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $subclasses = [];
|
||||
|
||||
/**
|
||||
* An array of column maps configured in $TCA
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $columnMaps = [];
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $pageIdColumnName;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $languageIdColumnName;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $translationOriginColumnName;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $translationOriginDiffSourceName;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $modificationDateColumnName;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $creationDateColumnName;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $creatorColumnName;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $deletedFlagColumnName;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $disabledFlagColumnName;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $startTimeColumnName;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $endTimeColumnName;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $frontendUserGroupColumnName;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $recordTypeColumnName;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $isStatic = false;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $rootLevel = false;
|
||||
|
||||
/**
|
||||
* Constructs this DataMap
|
||||
*
|
||||
* @param string $className The class name
|
||||
* @param string $tableName The table name
|
||||
* @param string $recordType The record type
|
||||
* @param array $subclasses The subclasses
|
||||
*/
|
||||
public function __construct($className, $tableName, $recordType = null, array $subclasses = [])
|
||||
{
|
||||
$this->setClassName($className);
|
||||
$this->setTableName($tableName);
|
||||
$this->setRecordType($recordType);
|
||||
$this->setSubclasses($subclasses);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the class the column map represents
|
||||
*
|
||||
* @param string $className
|
||||
*/
|
||||
public function setClassName($className)
|
||||
{
|
||||
$this->className = $className;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the class the column map represents
|
||||
*
|
||||
* @return string The class name
|
||||
*/
|
||||
public function getClassName()
|
||||
{
|
||||
return $this->className;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the table the column map represents
|
||||
*
|
||||
* @param string $tableName
|
||||
*/
|
||||
public function setTableName($tableName)
|
||||
{
|
||||
$this->tableName = $tableName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the table the column map represents
|
||||
*
|
||||
* @return string The table name
|
||||
*/
|
||||
public function getTableName()
|
||||
{
|
||||
return $this->tableName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the record type
|
||||
*
|
||||
* @param string $recordType The record type
|
||||
*/
|
||||
public function setRecordType($recordType)
|
||||
{
|
||||
$this->recordType = $recordType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the record type
|
||||
*
|
||||
* @return string The record type
|
||||
*/
|
||||
public function getRecordType()
|
||||
{
|
||||
return $this->recordType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the subclasses
|
||||
*
|
||||
* @param array $subclasses An array of subclasses
|
||||
*/
|
||||
public function setSubclasses(array $subclasses)
|
||||
{
|
||||
$this->subclasses = $subclasses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the subclasses
|
||||
*
|
||||
* @return array The subclasses
|
||||
*/
|
||||
public function getSubclasses()
|
||||
{
|
||||
return $this->subclasses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a given column map to the data map.
|
||||
*
|
||||
* @param \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMap $columnMap The column map
|
||||
*/
|
||||
public function addColumnMap(ColumnMap $columnMap)
|
||||
{
|
||||
$this->columnMaps[$columnMap->getPropertyName()] = $columnMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the column map corresponding to the given property name.
|
||||
*
|
||||
* @param string $propertyName
|
||||
* @return \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMap|null The column map or NULL if no corresponding column map was found.
|
||||
*/
|
||||
public function getColumnMap($propertyName)
|
||||
{
|
||||
return $this->columnMaps[$propertyName] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns TRUE if the property is persistable (configured in $TCA)
|
||||
*
|
||||
* @param string $propertyName The property name
|
||||
* @return bool TRUE if the property is persistable (configured in $TCA)
|
||||
*/
|
||||
public function isPersistableProperty($propertyName)
|
||||
{
|
||||
return isset($this->columnMaps[$propertyName]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of a column holding the page id
|
||||
*
|
||||
* @param string $pageIdColumnName The field name
|
||||
*/
|
||||
public function setPageIdColumnName($pageIdColumnName)
|
||||
{
|
||||
$this->pageIdColumnName = $pageIdColumnName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of a column holding the page id
|
||||
*
|
||||
* @return string The field name
|
||||
*/
|
||||
public function getPageIdColumnName()
|
||||
{
|
||||
return $this->pageIdColumnName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of a column holding the language id of the record
|
||||
*
|
||||
* @param string $languageIdColumnName The field name
|
||||
*/
|
||||
public function setLanguageIdColumnName($languageIdColumnName)
|
||||
{
|
||||
$this->languageIdColumnName = $languageIdColumnName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of a column holding the language id of the record.
|
||||
*
|
||||
* @return string The field name
|
||||
*/
|
||||
public function getLanguageIdColumnName()
|
||||
{
|
||||
return $this->languageIdColumnName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of a column holding the the uid of the record which this record is a translation of.
|
||||
*
|
||||
* @param string $translationOriginColumnName The field name
|
||||
*/
|
||||
public function setTranslationOriginColumnName($translationOriginColumnName)
|
||||
{
|
||||
$this->translationOriginColumnName = $translationOriginColumnName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of a column holding the the uid of the record which this record is a translation of.
|
||||
*
|
||||
* @return string The field name
|
||||
*/
|
||||
public function getTranslationOriginColumnName()
|
||||
{
|
||||
return $this->translationOriginColumnName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of a column holding the the diff data for the record which this record is a translation of.
|
||||
*
|
||||
* @param string $translationOriginDiffSourceName The field name
|
||||
*/
|
||||
public function setTranslationOriginDiffSourceName($translationOriginDiffSourceName)
|
||||
{
|
||||
$this->translationOriginDiffSourceName = $translationOriginDiffSourceName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of a column holding the diff data for the record which this record is a translation of.
|
||||
*
|
||||
* @return string The field name
|
||||
*/
|
||||
public function getTranslationOriginDiffSourceName()
|
||||
{
|
||||
return $this->translationOriginDiffSourceName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of a column holding the timestamp the record was modified
|
||||
*
|
||||
* @param string $modificationDateColumnName The field name
|
||||
*/
|
||||
public function setModificationDateColumnName($modificationDateColumnName)
|
||||
{
|
||||
$this->modificationDateColumnName = $modificationDateColumnName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of a column holding the timestamp the record was modified
|
||||
*
|
||||
* @return string The field name
|
||||
*/
|
||||
public function getModificationDateColumnName()
|
||||
{
|
||||
return $this->modificationDateColumnName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of a column holding the creation date timestamp
|
||||
*
|
||||
* @param string $creationDateColumnName The field name
|
||||
*/
|
||||
public function setCreationDateColumnName($creationDateColumnName)
|
||||
{
|
||||
$this->creationDateColumnName = $creationDateColumnName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of a column holding the creation date timestamp
|
||||
*
|
||||
* @return string The field name
|
||||
*/
|
||||
public function getCreationDateColumnName()
|
||||
{
|
||||
return $this->creationDateColumnName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of a column holding the uid of the back-end user who created this record
|
||||
*
|
||||
* @param string $creatorColumnName The field name
|
||||
*/
|
||||
public function setCreatorColumnName($creatorColumnName)
|
||||
{
|
||||
$this->creatorColumnName = $creatorColumnName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of a column holding the uid of the back-end user who created this record
|
||||
*
|
||||
* @return string The field name
|
||||
*/
|
||||
public function getCreatorColumnName()
|
||||
{
|
||||
return $this->creatorColumnName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of a column indicating the 'deleted' state of the row
|
||||
*
|
||||
* @param string $deletedFlagColumnName The field name
|
||||
*/
|
||||
public function setDeletedFlagColumnName($deletedFlagColumnName)
|
||||
{
|
||||
$this->deletedFlagColumnName = $deletedFlagColumnName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of a column indicating the 'deleted' state of the row
|
||||
*
|
||||
* @return string The field name
|
||||
*/
|
||||
public function getDeletedFlagColumnName()
|
||||
{
|
||||
return $this->deletedFlagColumnName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of a column indicating the 'hidden' state of the row
|
||||
*
|
||||
* @param string $disabledFlagColumnName The field name
|
||||
*/
|
||||
public function setDisabledFlagColumnName($disabledFlagColumnName)
|
||||
{
|
||||
$this->disabledFlagColumnName = $disabledFlagColumnName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of a column indicating the 'hidden' state of the row
|
||||
*
|
||||
* @return string The field name
|
||||
*/
|
||||
public function getDisabledFlagColumnName()
|
||||
{
|
||||
return $this->disabledFlagColumnName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of a column holding the timestamp the record should not displayed before
|
||||
*
|
||||
* @param string $startTimeColumnName The field name
|
||||
*/
|
||||
public function setStartTimeColumnName($startTimeColumnName)
|
||||
{
|
||||
$this->startTimeColumnName = $startTimeColumnName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of a column holding the timestamp the record should not displayed before
|
||||
*
|
||||
* @return string The field name
|
||||
*/
|
||||
public function getStartTimeColumnName()
|
||||
{
|
||||
return $this->startTimeColumnName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of a column holding the timestamp the record should not displayed afterwards
|
||||
*
|
||||
* @param string $endTimeColumnName The field name
|
||||
*/
|
||||
public function setEndTimeColumnName($endTimeColumnName)
|
||||
{
|
||||
$this->endTimeColumnName = $endTimeColumnName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of a column holding the timestamp the record should not displayed afterwards
|
||||
*
|
||||
* @return string The field name
|
||||
*/
|
||||
public function getEndTimeColumnName()
|
||||
{
|
||||
return $this->endTimeColumnName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of a column holding the uid of the front-end user group which is allowed to edit this record
|
||||
*
|
||||
* @param string $frontendUserGroupColumnName The field name
|
||||
*/
|
||||
public function setFrontEndUserGroupColumnName($frontendUserGroupColumnName)
|
||||
{
|
||||
$this->frontendUserGroupColumnName = $frontendUserGroupColumnName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of a column holding the uid of the front-end user group which is allowed to edit this record
|
||||
*
|
||||
* @return string The field name
|
||||
*/
|
||||
public function getFrontEndUserGroupColumnName()
|
||||
{
|
||||
return $this->frontendUserGroupColumnName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of a column holding the record type
|
||||
*
|
||||
* @param string $recordTypeColumnName The field name
|
||||
*/
|
||||
public function setRecordTypeColumnName($recordTypeColumnName)
|
||||
{
|
||||
$this->recordTypeColumnName = $recordTypeColumnName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of a column holding the record type
|
||||
*
|
||||
* @return string The field name
|
||||
*/
|
||||
public function getRecordTypeColumnName()
|
||||
{
|
||||
return $this->recordTypeColumnName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $isStatic
|
||||
*/
|
||||
public function setIsStatic($isStatic)
|
||||
{
|
||||
$this->isStatic = $isStatic;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function getIsStatic()
|
||||
{
|
||||
return $this->isStatic;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $rootLevel
|
||||
*/
|
||||
public function setRootLevel($rootLevel)
|
||||
{
|
||||
$this->rootLevel = $rootLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function getRootLevel()
|
||||
{
|
||||
return $this->rootLevel;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,487 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic\Mapper;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
use TYPO3\CMS\Core\Database\Query\QueryHelper;
|
||||
|
||||
/**
|
||||
* A factory for a data map to map a single table configured in $TCA on a domain object.
|
||||
* @internal only to be used within Extbase, not part of TYPO3 Core API.
|
||||
*/
|
||||
class DataMapFactory implements \TYPO3\CMS\Core\SingletonInterface
|
||||
{
|
||||
/**
|
||||
* @var \TYPO3\CMS\Extbase\Reflection\ReflectionService
|
||||
*/
|
||||
protected $reflectionService;
|
||||
|
||||
/**
|
||||
* @var \TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface
|
||||
*/
|
||||
protected $configurationManager;
|
||||
|
||||
/**
|
||||
* @var \TYPO3\CMS\Extbase\Object\ObjectManagerInterface
|
||||
*/
|
||||
protected $objectManager;
|
||||
|
||||
/**
|
||||
* @var \TYPO3\CMS\Core\Cache\CacheManager
|
||||
*/
|
||||
protected $cacheManager;
|
||||
|
||||
/**
|
||||
* @var \TYPO3\CMS\Core\Cache\Frontend\FrontendInterface
|
||||
*/
|
||||
protected $dataMapCache;
|
||||
|
||||
/**
|
||||
* Runtime cache for data maps, to reduce number of calls to cache backend.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $dataMaps = [];
|
||||
|
||||
/**
|
||||
* @param \TYPO3\CMS\Extbase\Reflection\ReflectionService $reflectionService
|
||||
*/
|
||||
public function injectReflectionService(\TYPO3\CMS\Extbase\Reflection\ReflectionService $reflectionService)
|
||||
{
|
||||
$this->reflectionService = $reflectionService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface $configurationManager
|
||||
*/
|
||||
public function injectConfigurationManager(\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface $configurationManager)
|
||||
{
|
||||
$this->configurationManager = $configurationManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager
|
||||
*/
|
||||
public function injectObjectManager(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager)
|
||||
{
|
||||
$this->objectManager = $objectManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \TYPO3\CMS\Core\Cache\CacheManager $cacheManager
|
||||
*/
|
||||
public function injectCacheManager(\TYPO3\CMS\Core\Cache\CacheManager $cacheManager)
|
||||
{
|
||||
$this->cacheManager = $cacheManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lifecycle method
|
||||
*/
|
||||
public function initializeObject()
|
||||
{
|
||||
$this->dataMapCache = $this->cacheManager->getCache('extbase_datamapfactory_datamap');
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
if (isset($this->dataMaps[$className])) {
|
||||
return $this->dataMaps[$className];
|
||||
}
|
||||
$dataMap = $this->dataMapCache->get(str_replace('\\', '%', $className));
|
||||
if ($dataMap === false) {
|
||||
$dataMap = $this->buildDataMapInternal($className);
|
||||
$this->dataMapCache->set(str_replace('\\', '%', $className), $dataMap);
|
||||
}
|
||||
$this->dataMaps[$className] = $dataMap;
|
||||
return $dataMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @throws \TYPO3\CMS\Extbase\Persistence\Generic\Exception\InvalidClassException
|
||||
* @return \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMap The data map
|
||||
*/
|
||||
protected function buildDataMapInternal($className)
|
||||
{
|
||||
if (!class_exists($className)) {
|
||||
throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception\InvalidClassException(
|
||||
'Could not find class definition for name "' . $className . '". This could be caused by a mis-spelling of the class name in the class definition.',
|
||||
1476045117
|
||||
);
|
||||
}
|
||||
$recordType = null;
|
||||
$subclasses = [];
|
||||
$tableName = $this->resolveTableName($className);
|
||||
$columnMapping = [];
|
||||
$frameworkConfiguration = $this->configurationManager->getConfiguration(\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK);
|
||||
$classSettings = $frameworkConfiguration['persistence']['classes'][$className] ?? null;
|
||||
if ($classSettings !== null) {
|
||||
if (isset($classSettings['subclasses']) && is_array($classSettings['subclasses'])) {
|
||||
$subclasses = $this->resolveSubclassesRecursive($frameworkConfiguration['persistence']['classes'], $classSettings['subclasses']);
|
||||
}
|
||||
if (isset($classSettings['mapping']['recordType']) && $classSettings['mapping']['recordType'] !== '') {
|
||||
$recordType = $classSettings['mapping']['recordType'];
|
||||
}
|
||||
if (isset($classSettings['mapping']['tableName']) && $classSettings['mapping']['tableName'] !== '') {
|
||||
$tableName = $classSettings['mapping']['tableName'];
|
||||
}
|
||||
$classHierarchy = array_merge([$className], class_parents($className));
|
||||
foreach ($classHierarchy as $currentClassName) {
|
||||
if (in_array($currentClassName, [\TYPO3\CMS\Extbase\DomainObject\AbstractEntity::class, \TYPO3\CMS\Extbase\DomainObject\AbstractValueObject::class])) {
|
||||
break;
|
||||
}
|
||||
$currentClassSettings = $frameworkConfiguration['persistence']['classes'][$currentClassName];
|
||||
if ($currentClassSettings !== null) {
|
||||
if (isset($currentClassSettings['mapping']['columns']) && is_array($currentClassSettings['mapping']['columns'])) {
|
||||
\TYPO3\CMS\Core\Utility\ArrayUtility::mergeRecursiveWithOverrule($columnMapping, $currentClassSettings['mapping']['columns'], true, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/** @var \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMap $dataMap */
|
||||
$dataMap = $this->objectManager->get(\TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMap::class, $className, $tableName, $recordType, $subclasses);
|
||||
$dataMap = $this->addMetaDataColumnNames($dataMap, $tableName);
|
||||
// $classPropertyNames = $this->reflectionService->getClassPropertyNames($className);
|
||||
$tcaColumnsDefinition = $this->getColumnsDefinition($tableName);
|
||||
\TYPO3\CMS\Core\Utility\ArrayUtility::mergeRecursiveWithOverrule($tcaColumnsDefinition, $columnMapping);
|
||||
// @todo Is this is too powerful?
|
||||
|
||||
foreach ($tcaColumnsDefinition as $columnName => $columnDefinition) {
|
||||
if (isset($columnDefinition['mapOnProperty'])) {
|
||||
$propertyName = $columnDefinition['mapOnProperty'];
|
||||
} else {
|
||||
$propertyName = \TYPO3\CMS\Core\Utility\GeneralUtility::underscoredToLowerCamelCase($columnName);
|
||||
}
|
||||
// if (in_array($propertyName, $classPropertyNames)) {
|
||||
// @todo Enable check for property existence
|
||||
$columnMap = $this->createColumnMap($columnName, $propertyName);
|
||||
$propertyMetaData = $this->reflectionService->getClassSchema($className)->getProperty($propertyName);
|
||||
$columnMap = $this->setType($columnMap, $columnDefinition['config']);
|
||||
$columnMap = $this->setRelations($columnMap, $columnDefinition['config'], $propertyMetaData);
|
||||
$columnMap = $this->setFieldEvaluations($columnMap, $columnDefinition['config']);
|
||||
$dataMap->addColumnMap($columnMap);
|
||||
}
|
||||
return $dataMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the table name for the given class name
|
||||
*
|
||||
* @param string $className
|
||||
* @return string The table name
|
||||
*/
|
||||
protected function resolveTableName($className)
|
||||
{
|
||||
$className = ltrim($className, '\\');
|
||||
$classNameParts = explode('\\', $className);
|
||||
// Skip vendor and product name for core classes
|
||||
if (strpos($className, 'TYPO3\\CMS\\') === 0) {
|
||||
$classPartsToSkip = 2;
|
||||
} else {
|
||||
$classPartsToSkip = 1;
|
||||
}
|
||||
$tableName = 'tx_' . strtolower(implode('_', array_slice($classNameParts, $classPartsToSkip)));
|
||||
|
||||
return $tableName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves all subclasses for the given set of (sub-)classes.
|
||||
* The whole classes configuration is used to determine all subclasses recursively.
|
||||
*
|
||||
* @param array $classesConfiguration The framework configuration part [persistence][classes].
|
||||
* @param array $subclasses An array of subclasses defined via TypoScript
|
||||
* @return array An numeric array that contains all available subclasses-strings as values.
|
||||
*/
|
||||
protected function resolveSubclassesRecursive(array $classesConfiguration, array $subclasses)
|
||||
{
|
||||
$allSubclasses = [];
|
||||
foreach ($subclasses as $subclass) {
|
||||
$allSubclasses[] = $subclass;
|
||||
if (isset($classesConfiguration[$subclass]['subclasses']) && is_array($classesConfiguration[$subclass]['subclasses'])) {
|
||||
$childSubclasses = $this->resolveSubclassesRecursive($classesConfiguration, $classesConfiguration[$subclass]['subclasses']);
|
||||
$allSubclasses = array_merge($allSubclasses, $childSubclasses);
|
||||
}
|
||||
}
|
||||
return $allSubclasses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the TCA ctrl section of the specified table; or NULL if not set
|
||||
*
|
||||
* @param string $tableName An optional table name to fetch the columns definition from
|
||||
* @return array The TCA columns definition
|
||||
*/
|
||||
protected function getControlSection($tableName)
|
||||
{
|
||||
return (isset($GLOBALS['TCA'][$tableName]['ctrl']) && is_array($GLOBALS['TCA'][$tableName]['ctrl']))
|
||||
? $GLOBALS['TCA'][$tableName]['ctrl']
|
||||
: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the TCA columns array of the specified table
|
||||
*
|
||||
* @param string $tableName An optional table name to fetch the columns definition from
|
||||
* @return array The TCA columns definition
|
||||
*/
|
||||
protected function getColumnsDefinition($tableName)
|
||||
{
|
||||
return is_array($GLOBALS['TCA'][$tableName]['columns']) ? $GLOBALS['TCA'][$tableName]['columns'] : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DataMap $dataMap
|
||||
* @param string $tableName
|
||||
* @return DataMap
|
||||
*/
|
||||
protected function addMetaDataColumnNames(\TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMap $dataMap, $tableName)
|
||||
{
|
||||
$controlSection = $GLOBALS['TCA'][$tableName]['ctrl'];
|
||||
$dataMap->setPageIdColumnName('pid');
|
||||
if (isset($controlSection['tstamp'])) {
|
||||
$dataMap->setModificationDateColumnName($controlSection['tstamp']);
|
||||
}
|
||||
if (isset($controlSection['crdate'])) {
|
||||
$dataMap->setCreationDateColumnName($controlSection['crdate']);
|
||||
}
|
||||
if (isset($controlSection['cruser_id'])) {
|
||||
$dataMap->setCreatorColumnName($controlSection['cruser_id']);
|
||||
}
|
||||
if (isset($controlSection['delete'])) {
|
||||
$dataMap->setDeletedFlagColumnName($controlSection['delete']);
|
||||
}
|
||||
if (isset($controlSection['languageField'])) {
|
||||
$dataMap->setLanguageIdColumnName($controlSection['languageField']);
|
||||
}
|
||||
if (isset($controlSection['transOrigPointerField'])) {
|
||||
$dataMap->setTranslationOriginColumnName($controlSection['transOrigPointerField']);
|
||||
}
|
||||
if (isset($controlSection['transOrigDiffSourceField'])) {
|
||||
$dataMap->setTranslationOriginDiffSourceName($controlSection['transOrigDiffSourceField']);
|
||||
}
|
||||
if (isset($controlSection['type'])) {
|
||||
$dataMap->setRecordTypeColumnName($controlSection['type']);
|
||||
}
|
||||
if (isset($controlSection['rootLevel'])) {
|
||||
$dataMap->setRootLevel($controlSection['rootLevel']);
|
||||
}
|
||||
if (isset($controlSection['is_static'])) {
|
||||
$dataMap->setIsStatic($controlSection['is_static']);
|
||||
}
|
||||
if (isset($controlSection['enablecolumns']['disabled'])) {
|
||||
$dataMap->setDisabledFlagColumnName($controlSection['enablecolumns']['disabled']);
|
||||
}
|
||||
if (isset($controlSection['enablecolumns']['starttime'])) {
|
||||
$dataMap->setStartTimeColumnName($controlSection['enablecolumns']['starttime']);
|
||||
}
|
||||
if (isset($controlSection['enablecolumns']['endtime'])) {
|
||||
$dataMap->setEndTimeColumnName($controlSection['enablecolumns']['endtime']);
|
||||
}
|
||||
if (isset($controlSection['enablecolumns']['fe_group'])) {
|
||||
$dataMap->setFrontEndUserGroupColumnName($controlSection['enablecolumns']['fe_group']);
|
||||
}
|
||||
return $dataMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the table column type
|
||||
*
|
||||
* @param ColumnMap $columnMap
|
||||
* @param array $columnConfiguration
|
||||
* @return ColumnMap
|
||||
*/
|
||||
protected function setType(ColumnMap $columnMap, $columnConfiguration)
|
||||
{
|
||||
$tableColumnType = $columnConfiguration['type'] ?? null;
|
||||
$columnMap->setType(\TYPO3\CMS\Core\DataHandling\TableColumnType::cast($tableColumnType));
|
||||
$tableColumnSubType = $columnConfiguration['internal_type'] ?? null;
|
||||
$columnMap->setInternalType(\TYPO3\CMS\Core\DataHandling\TableColumnSubType::cast($tableColumnSubType));
|
||||
|
||||
return $columnMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method tries to determine the type of type of relation to other tables and sets it based on
|
||||
* the $TCA column configuration
|
||||
*
|
||||
* @param ColumnMap $columnMap The column map
|
||||
* @param array|null $columnConfiguration The column configuration from $TCA
|
||||
* @param array $propertyMetaData The property metadata as delivered by the reflection service
|
||||
* @return ColumnMap
|
||||
*/
|
||||
protected function setRelations(ColumnMap $columnMap, $columnConfiguration, $propertyMetaData)
|
||||
{
|
||||
if (isset($columnConfiguration)) {
|
||||
if (isset($columnConfiguration['MM'])) {
|
||||
$columnMap = $this->setManyToManyRelation($columnMap, $columnConfiguration);
|
||||
} elseif (isset($propertyMetaData['elementType'])) {
|
||||
$columnMap = $this->setOneToManyRelation($columnMap, $columnConfiguration);
|
||||
} elseif (isset($propertyMetaData['type']) && strpbrk($propertyMetaData['type'], '_\\') !== false) {
|
||||
$columnMap = $this->setOneToOneRelation($columnMap, $columnConfiguration);
|
||||
} elseif (
|
||||
isset($columnConfiguration['type'], $columnConfiguration['renderType'])
|
||||
&& $columnConfiguration['type'] === 'select'
|
||||
&& (
|
||||
$columnConfiguration['renderType'] !== 'selectSingle'
|
||||
|| (isset($columnConfiguration['maxitems']) && $columnConfiguration['maxitems'] > 1)
|
||||
)
|
||||
) {
|
||||
$columnMap->setTypeOfRelation(ColumnMap::RELATION_HAS_MANY);
|
||||
} elseif (
|
||||
isset($columnConfiguration['type']) && $columnConfiguration['type'] === 'group'
|
||||
&& (!isset($columnConfiguration['maxitems']) || $columnConfiguration['maxitems'] > 1)
|
||||
) {
|
||||
$columnMap->setTypeOfRelation(ColumnMap::RELATION_HAS_MANY);
|
||||
} else {
|
||||
$columnMap->setTypeOfRelation(ColumnMap::RELATION_NONE);
|
||||
}
|
||||
} else {
|
||||
$columnMap->setTypeOfRelation(ColumnMap::RELATION_NONE);
|
||||
}
|
||||
return $columnMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets field evaluations based on $TCA column configuration.
|
||||
*
|
||||
* @param ColumnMap $columnMap The column map
|
||||
* @param array|null $columnConfiguration The column configuration from $TCA
|
||||
* @return ColumnMap
|
||||
*/
|
||||
protected function setFieldEvaluations(ColumnMap $columnMap, array $columnConfiguration = null)
|
||||
{
|
||||
if (!empty($columnConfiguration['eval'])) {
|
||||
$fieldEvaluations = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $columnConfiguration['eval'], true);
|
||||
$dateTimeTypes = QueryHelper::getDateTimeTypes();
|
||||
|
||||
if (!empty(array_intersect($dateTimeTypes, $fieldEvaluations)) && !empty($columnConfiguration['dbType'])) {
|
||||
$columnMap->setDateTimeStorageFormat($columnConfiguration['dbType']);
|
||||
}
|
||||
}
|
||||
|
||||
return $columnMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method sets the configuration for a 1:1 relation based on
|
||||
* the $TCA column configuration
|
||||
*
|
||||
* @param ColumnMap $columnMap The column map
|
||||
* @param array|null $columnConfiguration The column configuration from $TCA
|
||||
* @return ColumnMap
|
||||
*/
|
||||
protected function setOneToOneRelation(ColumnMap $columnMap, array $columnConfiguration = null)
|
||||
{
|
||||
$columnMap->setTypeOfRelation(ColumnMap::RELATION_HAS_ONE);
|
||||
$columnMap->setChildTableName($columnConfiguration['foreign_table']);
|
||||
$columnMap->setChildTableWhereStatement($columnConfiguration['foreign_table_where'] ?? null);
|
||||
$columnMap->setChildSortByFieldName($columnConfiguration['foreign_sortby'] ?? null);
|
||||
$columnMap->setParentKeyFieldName($columnConfiguration['foreign_field'] ?? null);
|
||||
$columnMap->setParentTableFieldName($columnConfiguration['foreign_table_field'] ?? null);
|
||||
if (is_array($columnConfiguration['foreign_match_fields'])) {
|
||||
$columnMap->setRelationTableMatchFields($columnConfiguration['foreign_match_fields']);
|
||||
}
|
||||
return $columnMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method sets the configuration for a 1:n relation based on
|
||||
* the $TCA column configuration
|
||||
*
|
||||
* @param ColumnMap $columnMap The column map
|
||||
* @param array|null $columnConfiguration The column configuration from $TCA
|
||||
* @return ColumnMap
|
||||
*/
|
||||
protected function setOneToManyRelation(ColumnMap $columnMap, array $columnConfiguration = null)
|
||||
{
|
||||
$columnMap->setTypeOfRelation(ColumnMap::RELATION_HAS_MANY);
|
||||
$columnMap->setChildTableName($columnConfiguration['foreign_table']);
|
||||
$columnMap->setChildTableWhereStatement($columnConfiguration['foreign_table_where'] ?? null);
|
||||
$columnMap->setChildSortByFieldName($columnConfiguration['foreign_sortby'] ?? null);
|
||||
$columnMap->setParentKeyFieldName($columnConfiguration['foreign_field'] ?? null);
|
||||
$columnMap->setParentTableFieldName($columnConfiguration['foreign_table_field'] ?? null);
|
||||
if (is_array($columnConfiguration['foreign_match_fields'] ?? null)) {
|
||||
$columnMap->setRelationTableMatchFields($columnConfiguration['foreign_match_fields']);
|
||||
}
|
||||
return $columnMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method sets the configuration for a m:n relation based on
|
||||
* the $TCA column configuration
|
||||
*
|
||||
* @param ColumnMap $columnMap The column map
|
||||
* @param array|null $columnConfiguration The column configuration from $TCA
|
||||
* @throws \TYPO3\CMS\Extbase\Persistence\Generic\Exception\UnsupportedRelationException
|
||||
* @return ColumnMap
|
||||
*/
|
||||
protected function setManyToManyRelation(ColumnMap $columnMap, array $columnConfiguration = null)
|
||||
{
|
||||
if (isset($columnConfiguration['MM'])) {
|
||||
$columnMap->setTypeOfRelation(ColumnMap::RELATION_HAS_AND_BELONGS_TO_MANY);
|
||||
$columnMap->setChildTableName($columnConfiguration['foreign_table']);
|
||||
$columnMap->setChildTableWhereStatement($columnConfiguration['foreign_table_where'] ?? null);
|
||||
$columnMap->setRelationTableName($columnConfiguration['MM']);
|
||||
if (isset($columnConfiguration['MM_match_fields']) && is_array($columnConfiguration['MM_match_fields'])) {
|
||||
$columnMap->setRelationTableMatchFields($columnConfiguration['MM_match_fields']);
|
||||
}
|
||||
if (isset($columnConfiguration['MM_insert_fields']) && is_array($columnConfiguration['MM_insert_fields'])) {
|
||||
$columnMap->setRelationTableInsertFields($columnConfiguration['MM_insert_fields']);
|
||||
}
|
||||
$columnMap->setRelationTableWhereStatement($columnConfiguration['MM_table_where'] ?? null);
|
||||
if (!empty($columnConfiguration['MM_opposite_field'])) {
|
||||
$columnMap->setParentKeyFieldName('uid_foreign');
|
||||
$columnMap->setChildKeyFieldName('uid_local');
|
||||
$columnMap->setChildSortByFieldName('sorting_foreign');
|
||||
} else {
|
||||
$columnMap->setParentKeyFieldName('uid_local');
|
||||
$columnMap->setChildKeyFieldName('uid_foreign');
|
||||
$columnMap->setChildSortByFieldName('sorting');
|
||||
}
|
||||
} else {
|
||||
throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception\UnsupportedRelationException('The given information to build a many-to-many-relation was not sufficient. Check your TCA definitions. mm-relations with IRRE must have at least a defined "MM" or "foreign_selector".', 1268817963);
|
||||
}
|
||||
if ($this->getControlSection($columnMap->getRelationTableName()) !== null) {
|
||||
$columnMap->setRelationTablePageIdColumnName('pid');
|
||||
}
|
||||
return $columnMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the ColumnMap object for the given columnName and propertyName
|
||||
*
|
||||
* @param string $columnName
|
||||
* @param string $propertyName
|
||||
*
|
||||
* @return ColumnMap
|
||||
*/
|
||||
protected function createColumnMap($columnName, $propertyName)
|
||||
{
|
||||
return $this->objectManager->get(\TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMap::class, $columnName, $propertyName);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,810 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic\Mapper;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
use TYPO3\CMS\Core\Database\Query\QueryHelper;
|
||||
use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
|
||||
use TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface;
|
||||
use TYPO3\CMS\Extbase\Object\Exception\CannotReconstituteObjectException;
|
||||
use TYPO3\CMS\Extbase\Persistence;
|
||||
use TYPO3\CMS\Extbase\Persistence\Generic\Exception\UnexpectedTypeException;
|
||||
use TYPO3\CMS\Extbase\Persistence\QueryInterface;
|
||||
use TYPO3\CMS\Extbase\Reflection\ClassSchema;
|
||||
use TYPO3\CMS\Extbase\Utility\TypeHandlingUtility;
|
||||
|
||||
/**
|
||||
* A mapper to map database tables configured in $TCA on domain objects.
|
||||
* @internal only to be used within Extbase, not part of TYPO3 Core API.
|
||||
*/
|
||||
class DataMapper
|
||||
{
|
||||
/**
|
||||
* @var \TYPO3\CMS\Extbase\Reflection\ReflectionService
|
||||
*/
|
||||
protected $reflectionService;
|
||||
|
||||
/**
|
||||
* @var \TYPO3\CMS\Extbase\Persistence\Generic\Qom\QueryObjectModelFactory
|
||||
*/
|
||||
protected $qomFactory;
|
||||
|
||||
/**
|
||||
* @var \TYPO3\CMS\Extbase\Persistence\Generic\Session
|
||||
*/
|
||||
protected $persistenceSession;
|
||||
|
||||
/**
|
||||
* A reference to the page select object providing methods to perform language and work space overlays
|
||||
*
|
||||
* @var \TYPO3\CMS\Frontend\Page\PageRepository
|
||||
*/
|
||||
protected $pageSelectObject;
|
||||
|
||||
/**
|
||||
* @var \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapFactory
|
||||
*/
|
||||
protected $dataMapFactory;
|
||||
|
||||
/**
|
||||
* @var \TYPO3\CMS\Extbase\Persistence\Generic\QueryFactoryInterface
|
||||
*/
|
||||
protected $queryFactory;
|
||||
|
||||
/**
|
||||
* @var \TYPO3\CMS\Extbase\Object\ObjectManagerInterface
|
||||
*/
|
||||
protected $objectManager;
|
||||
|
||||
/**
|
||||
* @var \TYPO3\CMS\Extbase\SignalSlot\Dispatcher
|
||||
*/
|
||||
protected $signalSlotDispatcher;
|
||||
|
||||
/**
|
||||
* @var ConfigurationManagerInterface
|
||||
*/
|
||||
protected $configurationManager;
|
||||
|
||||
/**
|
||||
* @var ?QueryInterface
|
||||
*/
|
||||
protected $query;
|
||||
|
||||
/**
|
||||
* DataMapper constructor.
|
||||
* @param ?QueryInterface $query
|
||||
*/
|
||||
public function __construct(?QueryInterface $query = null)
|
||||
{
|
||||
$this->query = $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \TYPO3\CMS\Extbase\Reflection\ReflectionService $reflectionService
|
||||
*/
|
||||
public function injectReflectionService(\TYPO3\CMS\Extbase\Reflection\ReflectionService $reflectionService)
|
||||
{
|
||||
$this->reflectionService = $reflectionService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \TYPO3\CMS\Extbase\Persistence\Generic\Qom\QueryObjectModelFactory $qomFactory
|
||||
*/
|
||||
public function injectQomFactory(\TYPO3\CMS\Extbase\Persistence\Generic\Qom\QueryObjectModelFactory $qomFactory)
|
||||
{
|
||||
$this->qomFactory = $qomFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \TYPO3\CMS\Extbase\Persistence\Generic\Session $persistenceSession
|
||||
*/
|
||||
public function injectPersistenceSession(\TYPO3\CMS\Extbase\Persistence\Generic\Session $persistenceSession)
|
||||
{
|
||||
$this->persistenceSession = $persistenceSession;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapFactory $dataMapFactory
|
||||
*/
|
||||
public function injectDataMapFactory(\TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapFactory $dataMapFactory)
|
||||
{
|
||||
$this->dataMapFactory = $dataMapFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \TYPO3\CMS\Extbase\Persistence\Generic\QueryFactoryInterface $queryFactory
|
||||
*/
|
||||
public function injectQueryFactory(\TYPO3\CMS\Extbase\Persistence\Generic\QueryFactoryInterface $queryFactory)
|
||||
{
|
||||
$this->queryFactory = $queryFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager
|
||||
*/
|
||||
public function injectObjectManager(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager)
|
||||
{
|
||||
$this->objectManager = $objectManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \TYPO3\CMS\Extbase\SignalSlot\Dispatcher $signalSlotDispatcher
|
||||
*/
|
||||
public function injectSignalSlotDispatcher(\TYPO3\CMS\Extbase\SignalSlot\Dispatcher $signalSlotDispatcher)
|
||||
{
|
||||
$this->signalSlotDispatcher = $signalSlotDispatcher;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface $configurationManager
|
||||
*/
|
||||
public function injectConfigurationManager(ConfigurationManagerInterface $configurationManager)
|
||||
{
|
||||
$this->configurationManager = $configurationManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps the given rows on objects
|
||||
*
|
||||
* @param string $className The name of the class
|
||||
* @param array $rows An array of arrays with field_name => value pairs
|
||||
* @return array An array of objects of the given class
|
||||
*/
|
||||
public function map($className, array $rows)
|
||||
{
|
||||
$objects = [];
|
||||
foreach ($rows as $row) {
|
||||
$objects[] = $this->mapSingleRow($this->getTargetType($className, $row), $row);
|
||||
}
|
||||
return $objects;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the target type for the given row.
|
||||
*
|
||||
* @param string $className The name of the class
|
||||
* @param array $row A single array with field_name => value pairs
|
||||
* @return string The target type (a class name)
|
||||
*/
|
||||
public function getTargetType($className, array $row)
|
||||
{
|
||||
$dataMap = $this->getDataMap($className);
|
||||
$targetType = $className;
|
||||
if ($dataMap->getRecordTypeColumnName() !== null) {
|
||||
foreach ($dataMap->getSubclasses() as $subclassName) {
|
||||
$recordSubtype = $this->getDataMap($subclassName)->getRecordType();
|
||||
if ((string)$row[$dataMap->getRecordTypeColumnName()] === (string)$recordSubtype) {
|
||||
$targetType = $subclassName;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $targetType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a single row on an object of the given class
|
||||
*
|
||||
* @param string $className The name of the target class
|
||||
* @param array $row A single array with field_name => value pairs
|
||||
* @return object An object of the given class
|
||||
*/
|
||||
protected function mapSingleRow($className, array $row)
|
||||
{
|
||||
if ($this->persistenceSession->hasIdentifier($row['uid'], $className)) {
|
||||
$object = $this->persistenceSession->getObjectByIdentifier($row['uid'], $className);
|
||||
} else {
|
||||
$object = $this->createEmptyObject($className);
|
||||
$this->persistenceSession->registerObject($object, $row['uid']);
|
||||
$this->thawProperties($object, $row);
|
||||
$this->emitAfterMappingSingleRow($object);
|
||||
$object->_memorizeCleanState();
|
||||
$this->persistenceSession->registerReconstitutedEntity($object);
|
||||
}
|
||||
return $object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Emits a signal after mapping a single row.
|
||||
*
|
||||
* @param DomainObjectInterface $object The mapped object
|
||||
*/
|
||||
protected function emitAfterMappingSingleRow(DomainObjectInterface $object)
|
||||
{
|
||||
$this->signalSlotDispatcher->dispatch(__CLASS__, 'afterMappingSingleRow', [$object]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a skeleton of the specified object
|
||||
*
|
||||
* @param string $className Name of the class to create a skeleton for
|
||||
* @throws CannotReconstituteObjectException
|
||||
* @return object The object skeleton
|
||||
*/
|
||||
protected function createEmptyObject($className)
|
||||
{
|
||||
// Note: The class_implements() function also invokes autoload to assure that the interfaces
|
||||
// and the class are loaded. Would end up with __PHP_Incomplete_Class without it.
|
||||
if (!in_array(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface::class, class_implements($className))) {
|
||||
throw new CannotReconstituteObjectException('Cannot create empty instance of the class "' . $className
|
||||
. '" because it does not implement the TYPO3\\CMS\\Extbase\\DomainObject\\DomainObjectInterface.', 1234386924);
|
||||
}
|
||||
$object = $this->objectManager->getEmptyObject($className);
|
||||
return $object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the given properties on the object.
|
||||
*
|
||||
* @param DomainObjectInterface $object The object to set properties on
|
||||
* @param array $row
|
||||
* @throws Exception\NonExistentPropertyException
|
||||
* @throws Exception\UnknownPropertyTypeException
|
||||
*/
|
||||
protected function thawProperties(DomainObjectInterface $object, array $row)
|
||||
{
|
||||
$className = get_class($object);
|
||||
$classSchema = $this->reflectionService->getClassSchema($className);
|
||||
$dataMap = $this->getDataMap($className);
|
||||
$object->_setProperty('uid', (int)$row['uid']);
|
||||
$object->_setProperty('pid', (int)($row['pid'] ?? 0));
|
||||
$object->_setProperty('_localizedUid', (int)$row['uid']);
|
||||
$object->_setProperty('_versionedUid', (int)$row['uid']);
|
||||
if ($dataMap->getLanguageIdColumnName() !== null) {
|
||||
$object->_setProperty('_languageUid', (int)$row[$dataMap->getLanguageIdColumnName()]);
|
||||
if (isset($row['_LOCALIZED_UID'])) {
|
||||
$object->_setProperty('_localizedUid', (int)$row['_LOCALIZED_UID']);
|
||||
}
|
||||
}
|
||||
if (!empty($row['_ORIG_uid']) && !empty($GLOBALS['TCA'][$dataMap->getTableName()]['ctrl']['versioningWS'])) {
|
||||
$object->_setProperty('_versionedUid', (int)$row['_ORIG_uid']);
|
||||
}
|
||||
$properties = $object->_getProperties();
|
||||
foreach ($properties as $propertyName => $propertyValue) {
|
||||
if (!$dataMap->isPersistableProperty($propertyName)) {
|
||||
continue;
|
||||
}
|
||||
$columnMap = $dataMap->getColumnMap($propertyName);
|
||||
$columnName = $columnMap->getColumnName();
|
||||
|
||||
$property = $classSchema->getProperty($propertyName);
|
||||
if (empty($property)) {
|
||||
throw new Exception\NonExistentPropertyException(
|
||||
'The type of property ' . $className . '::' . $propertyName . ' could not be identified, ' .
|
||||
'as property ' . $propertyName . ' is unknown to the ' . ClassSchema::class . ' instance of class ' .
|
||||
$className . '. Please make sure said property exists and that you cleared all caches to trigger ' .
|
||||
'a new build of said ' . ClassSchema::class . ' instance.',
|
||||
1580056272
|
||||
);
|
||||
}
|
||||
|
||||
$propertyType = $property['type'] ?? null;
|
||||
if ($propertyType === null) {
|
||||
throw new Exception\UnknownPropertyTypeException(
|
||||
'The type of property ' . $className . '::' . $propertyName . ' could not be identified, therefore the desired value (' .
|
||||
var_export($propertyValue, true) . ') cannot be mapped onto it. The type of a class property is usually defined via php doc blocks. ' .
|
||||
'Make sure the property has a valid @var tag set which defines the type.',
|
||||
1579965021
|
||||
);
|
||||
}
|
||||
$propertyValue = null;
|
||||
if (isset($row[$columnName])) {
|
||||
switch ($propertyType) {
|
||||
case 'integer':
|
||||
$propertyValue = (int)$row[$columnName];
|
||||
break;
|
||||
case 'float':
|
||||
$propertyValue = (double)$row[$columnName];
|
||||
break;
|
||||
case 'boolean':
|
||||
$propertyValue = (bool)$row[$columnName];
|
||||
break;
|
||||
case 'string':
|
||||
$propertyValue = (string)$row[$columnName];
|
||||
break;
|
||||
case 'array':
|
||||
// $propertyValue = $this->mapArray($row[$columnName]); // Not supported, yet!
|
||||
break;
|
||||
case 'SplObjectStorage':
|
||||
case Persistence\ObjectStorage::class:
|
||||
$propertyValue = $this->mapResultToPropertyValue(
|
||||
$object,
|
||||
$propertyName,
|
||||
$this->fetchRelated($object, $propertyName, $row[$columnName])
|
||||
);
|
||||
break;
|
||||
default:
|
||||
if (is_subclass_of($propertyType, \DateTimeInterface::class)) {
|
||||
$propertyValue = $this->mapDateTime(
|
||||
$row[$columnName],
|
||||
$columnMap->getDateTimeStorageFormat(),
|
||||
$propertyType
|
||||
);
|
||||
} elseif (TypeHandlingUtility::isCoreType($propertyType)) {
|
||||
$propertyValue = $this->mapCoreType($propertyType, $row[$columnName]);
|
||||
} else {
|
||||
$propertyValue = $this->mapObjectToClassProperty(
|
||||
$object,
|
||||
$propertyName,
|
||||
$row[$columnName]
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if ($propertyValue !== null) {
|
||||
$object->_setProperty($propertyName, $propertyValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Map value to a core type
|
||||
*
|
||||
* @param string $type
|
||||
* @param mixed $value
|
||||
* @return \TYPO3\CMS\Core\Type\TypeInterface
|
||||
*/
|
||||
protected function mapCoreType($type, $value)
|
||||
{
|
||||
return new $type($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a DateTime from an unix timestamp or date/datetime/time value.
|
||||
* If the input is empty, NULL is returned.
|
||||
*
|
||||
* @param int|string $value Unix timestamp or date/datetime/time value
|
||||
* @param string|null $storageFormat Storage format for native date/datetime/time fields
|
||||
* @param string|null $targetType The object class name to be created
|
||||
* @return \DateTimeInterface
|
||||
*/
|
||||
protected function mapDateTime($value, $storageFormat = null, $targetType = \DateTime::class)
|
||||
{
|
||||
$dateTimeTypes = QueryHelper::getDateTimeTypes();
|
||||
|
||||
if (empty($value) || $value === '0000-00-00' || $value === '0000-00-00 00:00:00' || $value === '00:00:00') {
|
||||
// 0 -> NULL !!!
|
||||
return null;
|
||||
}
|
||||
if (in_array($storageFormat, $dateTimeTypes, true)) {
|
||||
// native date/datetime/time values are stored in UTC
|
||||
$utcTimeZone = new \DateTimeZone('UTC');
|
||||
$utcDateTime = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance($targetType, $value, $utcTimeZone);
|
||||
$currentTimeZone = new \DateTimeZone(date_default_timezone_get());
|
||||
return $utcDateTime->setTimezone($currentTimeZone);
|
||||
}
|
||||
// integer timestamps are local server time
|
||||
return \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance($targetType, date('c', (int)$value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches a collection of objects related to a property of a parent object
|
||||
*
|
||||
* @param DomainObjectInterface $parentObject The object instance this proxy is part of
|
||||
* @param string $propertyName The name of the proxied property in it's parent
|
||||
* @param mixed $fieldValue The raw field value.
|
||||
* @param bool $enableLazyLoading A flag indication if the related objects should be lazy loaded
|
||||
* @return \TYPO3\CMS\Extbase\Persistence\Generic\LazyObjectStorage|Persistence\QueryResultInterface The result
|
||||
*/
|
||||
public function fetchRelated(DomainObjectInterface $parentObject, $propertyName, $fieldValue = '', $enableLazyLoading = true)
|
||||
{
|
||||
$propertyMetaData = $this->reflectionService->getClassSchema(get_class($parentObject))->getProperty($propertyName);
|
||||
if ($enableLazyLoading === true && $propertyMetaData['annotations']['lazy']) {
|
||||
if ($propertyMetaData['type'] === Persistence\ObjectStorage::class) {
|
||||
$result = $this->objectManager->get(\TYPO3\CMS\Extbase\Persistence\Generic\LazyObjectStorage::class, $parentObject, $propertyName, $fieldValue, $this);
|
||||
} else {
|
||||
if (empty($fieldValue)) {
|
||||
$result = null;
|
||||
} else {
|
||||
$result = $this->objectManager->get(\TYPO3\CMS\Extbase\Persistence\Generic\LazyLoadingProxy::class, $parentObject, $propertyName, $fieldValue, $this);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$result = $this->fetchRelatedEager($parentObject, $propertyName, $fieldValue);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the related objects from the storage backend.
|
||||
*
|
||||
* @param DomainObjectInterface $parentObject The object instance this proxy is part of
|
||||
* @param string $propertyName The name of the proxied property in it's parent
|
||||
* @param mixed $fieldValue The raw field value.
|
||||
* @return mixed
|
||||
*/
|
||||
protected function fetchRelatedEager(DomainObjectInterface $parentObject, $propertyName, $fieldValue = '')
|
||||
{
|
||||
return $fieldValue === '' ? $this->getEmptyRelationValue($parentObject, $propertyName) : $this->getNonEmptyRelationValue($parentObject, $propertyName, $fieldValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DomainObjectInterface $parentObject
|
||||
* @param string $propertyName
|
||||
* @return array|null
|
||||
*/
|
||||
protected function getEmptyRelationValue(DomainObjectInterface $parentObject, $propertyName)
|
||||
{
|
||||
$columnMap = $this->getDataMap(get_class($parentObject))->getColumnMap($propertyName);
|
||||
$relatesToOne = $columnMap->getTypeOfRelation() == ColumnMap::RELATION_HAS_ONE;
|
||||
return $relatesToOne ? null : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DomainObjectInterface $parentObject
|
||||
* @param string $propertyName
|
||||
* @param string $fieldValue
|
||||
* @return Persistence\QueryResultInterface
|
||||
*/
|
||||
protected function getNonEmptyRelationValue(DomainObjectInterface $parentObject, $propertyName, $fieldValue)
|
||||
{
|
||||
$query = $this->getPreparedQuery($parentObject, $propertyName, $fieldValue);
|
||||
return $query->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds and returns the prepared query, ready to be executed.
|
||||
*
|
||||
* @param DomainObjectInterface $parentObject
|
||||
* @param string $propertyName
|
||||
* @param string $fieldValue
|
||||
* @return Persistence\QueryInterface
|
||||
*/
|
||||
protected function getPreparedQuery(DomainObjectInterface $parentObject, $propertyName, $fieldValue = '')
|
||||
{
|
||||
$dataMap = $this->getDataMap(get_class($parentObject));
|
||||
$columnMap = $dataMap->getColumnMap($propertyName);
|
||||
$type = $this->getType(get_class($parentObject), $propertyName);
|
||||
$query = $this->queryFactory->create($type);
|
||||
if ($this->query && $query instanceof Persistence\Generic\Query) {
|
||||
$query->setParentQuery($this->query);
|
||||
}
|
||||
$query->getQuerySettings()->setRespectStoragePage(false);
|
||||
$query->getQuerySettings()->setRespectSysLanguage(false);
|
||||
|
||||
if ($this->configurationManager->isFeatureEnabled('consistentTranslationOverlayHandling')) {
|
||||
//we always want to overlay relations as most of the time they are stored in db using default lang uids
|
||||
$query->getQuerySettings()->setLanguageOverlayMode(true);
|
||||
if ($this->query) {
|
||||
$query->getQuerySettings()->setLanguageUid($this->query->getQuerySettings()->getLanguageUid());
|
||||
|
||||
if ($dataMap->getLanguageIdColumnName() !== null && !$this->query->getQuerySettings()->getRespectSysLanguage()) {
|
||||
//pass language of parent record to child objects, so they can be overlaid correctly in case
|
||||
//e.g. findByUid is used.
|
||||
//the languageUid is used for getRecordOverlay later on, despite RespectSysLanguage being false
|
||||
$languageUid = (int)$parentObject->_getProperty('_languageUid');
|
||||
$query->getQuerySettings()->setLanguageUid($languageUid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($columnMap->getTypeOfRelation() === ColumnMap::RELATION_HAS_MANY) {
|
||||
if ($columnMap->getChildSortByFieldName() !== null) {
|
||||
$query->setOrderings([$columnMap->getChildSortByFieldName() => Persistence\QueryInterface::ORDER_ASCENDING]);
|
||||
}
|
||||
} elseif ($columnMap->getTypeOfRelation() === ColumnMap::RELATION_HAS_AND_BELONGS_TO_MANY) {
|
||||
$query->setSource($this->getSource($parentObject, $propertyName));
|
||||
if ($columnMap->getChildSortByFieldName() !== null) {
|
||||
$query->setOrderings([$columnMap->getChildSortByFieldName() => Persistence\QueryInterface::ORDER_ASCENDING]);
|
||||
}
|
||||
}
|
||||
$query->matching($this->getConstraint($query, $parentObject, $propertyName, $fieldValue, $columnMap->getRelationTableMatchFields()));
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds and returns the constraint for multi value properties.
|
||||
*
|
||||
* @param Persistence\QueryInterface $query
|
||||
* @param DomainObjectInterface $parentObject
|
||||
* @param string $propertyName
|
||||
* @param string $fieldValue
|
||||
* @param array $relationTableMatchFields
|
||||
* @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ConstraintInterface $constraint
|
||||
*/
|
||||
protected function getConstraint(Persistence\QueryInterface $query, DomainObjectInterface $parentObject, $propertyName, $fieldValue = '', $relationTableMatchFields = [])
|
||||
{
|
||||
$columnMap = $this->getDataMap(get_class($parentObject))->getColumnMap($propertyName);
|
||||
if ($columnMap->getParentKeyFieldName() !== null) {
|
||||
$constraint = $query->equals($columnMap->getParentKeyFieldName(), $parentObject);
|
||||
if ($columnMap->getParentTableFieldName() !== null) {
|
||||
$constraint = $query->logicalAnd(
|
||||
$constraint,
|
||||
$query->equals($columnMap->getParentTableFieldName(), $this->getDataMap(get_class($parentObject))->getTableName())
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$constraint = $query->in('uid', \TYPO3\CMS\Core\Utility\GeneralUtility::intExplode(',', $fieldValue));
|
||||
}
|
||||
if (!empty($relationTableMatchFields)) {
|
||||
foreach ($relationTableMatchFields as $relationTableMatchFieldName => $relationTableMatchFieldValue) {
|
||||
$constraint = $query->logicalAnd($constraint, $query->equals($relationTableMatchFieldName, $relationTableMatchFieldValue));
|
||||
}
|
||||
}
|
||||
return $constraint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds and returns the source to build a join for a m:n relation.
|
||||
*
|
||||
* @param DomainObjectInterface $parentObject
|
||||
* @param string $propertyName
|
||||
* @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\SourceInterface $source
|
||||
*/
|
||||
protected function getSource(DomainObjectInterface $parentObject, $propertyName)
|
||||
{
|
||||
$columnMap = $this->getDataMap(get_class($parentObject))->getColumnMap($propertyName);
|
||||
$left = $this->qomFactory->selector(null, $columnMap->getRelationTableName());
|
||||
$childClassName = $this->getType(get_class($parentObject), $propertyName);
|
||||
$right = $this->qomFactory->selector($childClassName, $columnMap->getChildTableName());
|
||||
$joinCondition = $this->qomFactory->equiJoinCondition($columnMap->getRelationTableName(), $columnMap->getChildKeyFieldName(), $columnMap->getChildTableName(), 'uid');
|
||||
$source = $this->qomFactory->join($left, $right, Persistence\Generic\Query::JCR_JOIN_TYPE_INNER, $joinCondition);
|
||||
return $source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the mapped classProperty from the identiyMap or
|
||||
* mapResultToPropertyValue()
|
||||
*
|
||||
* If the field value is empty and the column map has no parent key field name,
|
||||
* the relation will be empty. If the persistence session has a registered object of
|
||||
* the correct type and identity (fieldValue), this function returns that object.
|
||||
* Otherwise, it proceeds with mapResultToPropertyValue().
|
||||
*
|
||||
* @param DomainObjectInterface $parentObject
|
||||
* @param string $propertyName
|
||||
* @param mixed $fieldValue the raw field value
|
||||
* @return mixed
|
||||
* @see mapResultToPropertyValue()
|
||||
*/
|
||||
protected function mapObjectToClassProperty(DomainObjectInterface $parentObject, $propertyName, $fieldValue)
|
||||
{
|
||||
if ($this->propertyMapsByForeignKey($parentObject, $propertyName)) {
|
||||
$result = $this->fetchRelated($parentObject, $propertyName, $fieldValue);
|
||||
$propertyValue = $this->mapResultToPropertyValue($parentObject, $propertyName, $result);
|
||||
} else {
|
||||
if ($fieldValue === '') {
|
||||
$propertyValue = $this->getEmptyRelationValue($parentObject, $propertyName);
|
||||
} else {
|
||||
$propertyMetaData = $this->reflectionService->getClassSchema(get_class($parentObject))->getProperty($propertyName);
|
||||
if ($this->persistenceSession->hasIdentifier($fieldValue, $propertyMetaData['type'])) {
|
||||
$propertyValue = $this->persistenceSession->getObjectByIdentifier($fieldValue, $propertyMetaData['type']);
|
||||
} else {
|
||||
$result = $this->fetchRelated($parentObject, $propertyName, $fieldValue);
|
||||
$propertyValue = $this->mapResultToPropertyValue($parentObject, $propertyName, $result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $propertyValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the relation is based on a foreign key.
|
||||
*
|
||||
* @param DomainObjectInterface $parentObject
|
||||
* @param string $propertyName
|
||||
* @return bool TRUE if the property is mapped
|
||||
*/
|
||||
protected function propertyMapsByForeignKey(DomainObjectInterface $parentObject, $propertyName)
|
||||
{
|
||||
$columnMap = $this->getDataMap(get_class($parentObject))->getColumnMap($propertyName);
|
||||
return $columnMap->getParentKeyFieldName() !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the given result as property value of the specified property type.
|
||||
*
|
||||
* @param DomainObjectInterface $parentObject
|
||||
* @param string $propertyName
|
||||
* @param mixed $result The result
|
||||
* @return mixed
|
||||
*/
|
||||
public function mapResultToPropertyValue(DomainObjectInterface $parentObject, $propertyName, $result)
|
||||
{
|
||||
$propertyValue = null;
|
||||
if ($result instanceof Persistence\Generic\LoadingStrategyInterface) {
|
||||
$propertyValue = $result;
|
||||
} else {
|
||||
$propertyMetaData = $this->reflectionService->getClassSchema(get_class($parentObject))->getProperty($propertyName);
|
||||
if (in_array($propertyMetaData['type'], ['array', 'ArrayObject', 'SplObjectStorage', Persistence\ObjectStorage::class], true)) {
|
||||
$objects = [];
|
||||
foreach ($result as $value) {
|
||||
$objects[] = $value;
|
||||
}
|
||||
if ($propertyMetaData['type'] === 'ArrayObject') {
|
||||
$propertyValue = new \ArrayObject($objects);
|
||||
} elseif ($propertyMetaData['type'] === Persistence\ObjectStorage::class) {
|
||||
$propertyValue = new Persistence\ObjectStorage();
|
||||
foreach ($objects as $object) {
|
||||
$propertyValue->attach($object);
|
||||
}
|
||||
$propertyValue->_memorizeCleanState();
|
||||
} else {
|
||||
$propertyValue = $objects;
|
||||
}
|
||||
} elseif (strpbrk($propertyMetaData['type'], '_\\') !== false) {
|
||||
if (is_object($result) && $result instanceof Persistence\QueryResultInterface) {
|
||||
$propertyValue = $result->getFirst();
|
||||
} else {
|
||||
$propertyValue = $result;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $propertyValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts the number of related objects assigned to a property of a parent object
|
||||
*
|
||||
* @param DomainObjectInterface $parentObject The object instance this proxy is part of
|
||||
* @param string $propertyName The name of the proxied property in it's parent
|
||||
* @param mixed $fieldValue The raw field value.
|
||||
* @return int
|
||||
*/
|
||||
public function countRelated(DomainObjectInterface $parentObject, $propertyName, $fieldValue = '')
|
||||
{
|
||||
$query = $this->getPreparedQuery($parentObject, $propertyName, $fieldValue);
|
||||
return $query->execute()->count();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegates the call to the Data Map.
|
||||
* Returns TRUE if the property is persistable (configured in $TCA)
|
||||
*
|
||||
* @param string $className The property name
|
||||
* @param string $propertyName The property name
|
||||
* @return bool TRUE if the property is persistable (configured in $TCA)
|
||||
*/
|
||||
public function isPersistableProperty($className, $propertyName)
|
||||
{
|
||||
$dataMap = $this->getDataMap($className);
|
||||
return $dataMap->isPersistableProperty($propertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a data map for a given class name
|
||||
*
|
||||
* @param string $className The class name you want to fetch the Data Map for
|
||||
* @throws Persistence\Generic\Exception
|
||||
* @return DataMap The data map
|
||||
*/
|
||||
public function getDataMap($className)
|
||||
{
|
||||
if (!is_string($className) || $className === '') {
|
||||
throw new Persistence\Generic\Exception('No class name was given to retrieve the Data Map for.', 1251315965);
|
||||
}
|
||||
return $this->dataMapFactory->buildDataMap($className);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the selector (table) name for a given class name.
|
||||
*
|
||||
* @param string $className
|
||||
* @return string The selector name
|
||||
*/
|
||||
public function convertClassNameToTableName($className)
|
||||
{
|
||||
return $this->getDataMap($className)->getTableName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the column name for a given property name of the specified class.
|
||||
*
|
||||
* @param string $propertyName
|
||||
* @param string $className
|
||||
* @return string The column name
|
||||
*/
|
||||
public function convertPropertyNameToColumnName($propertyName, $className = null)
|
||||
{
|
||||
if (!empty($className)) {
|
||||
$dataMap = $this->getDataMap($className);
|
||||
if ($dataMap !== null) {
|
||||
$columnMap = $dataMap->getColumnMap($propertyName);
|
||||
if ($columnMap !== null) {
|
||||
return $columnMap->getColumnName();
|
||||
}
|
||||
}
|
||||
}
|
||||
return \TYPO3\CMS\Core\Utility\GeneralUtility::camelCaseToLowerCaseUnderscored($propertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of a child object.
|
||||
*
|
||||
* @param string $parentClassName The class name of the object this proxy is part of
|
||||
* @param string $propertyName The name of the proxied property in it's parent
|
||||
* @throws UnexpectedTypeException
|
||||
* @return string The class name of the child object
|
||||
*/
|
||||
public function getType($parentClassName, $propertyName)
|
||||
{
|
||||
$propertyMetaData = $this->reflectionService->getClassSchema($parentClassName)->getProperty($propertyName);
|
||||
if (!empty($propertyMetaData['elementType'])) {
|
||||
$type = $propertyMetaData['elementType'];
|
||||
} elseif (!empty($propertyMetaData['type'])) {
|
||||
$type = $propertyMetaData['type'];
|
||||
} else {
|
||||
throw new UnexpectedTypeException('Could not determine the child object type.', 1251315967);
|
||||
}
|
||||
return $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a plain value, i.e. objects are flattened out if possible.
|
||||
* Multi value objects or arrays will be converted to a comma-separated list for use in IN SQL queries.
|
||||
*
|
||||
* @param mixed $input The value that will be converted.
|
||||
* @param ColumnMap $columnMap Optional column map for retrieving the date storage format.
|
||||
* @throws \InvalidArgumentException
|
||||
* @throws UnexpectedTypeException
|
||||
* @return int|string
|
||||
*/
|
||||
public function getPlainValue($input, $columnMap = null)
|
||||
{
|
||||
if ($input === null) {
|
||||
return 'NULL';
|
||||
}
|
||||
if ($input instanceof Persistence\Generic\LazyLoadingProxy) {
|
||||
$input = $input->_loadRealInstance();
|
||||
}
|
||||
|
||||
if (is_bool($input)) {
|
||||
$parameter = (int)$input;
|
||||
} elseif (is_int($input)) {
|
||||
$parameter = $input;
|
||||
} elseif ($input instanceof \DateTimeInterface) {
|
||||
if ($columnMap !== null && $columnMap->getDateTimeStorageFormat() !== null) {
|
||||
$storageFormat = $columnMap->getDateTimeStorageFormat();
|
||||
$timeZoneToStore = clone $input;
|
||||
// set to UTC to store in database
|
||||
$timeZoneToStore->setTimezone(new \DateTimeZone('UTC'));
|
||||
switch ($storageFormat) {
|
||||
case 'datetime':
|
||||
$parameter = $timeZoneToStore->format('Y-m-d H:i:s');
|
||||
break;
|
||||
case 'date':
|
||||
$parameter = $timeZoneToStore->format('Y-m-d');
|
||||
break;
|
||||
case 'time':
|
||||
$parameter = $timeZoneToStore->format('H:i');
|
||||
break;
|
||||
default:
|
||||
throw new \InvalidArgumentException('Column map DateTime format "' . $storageFormat . '" is unknown. Allowed values are date, datetime or time.', 1395353470);
|
||||
}
|
||||
} else {
|
||||
$parameter = $input->format('U');
|
||||
}
|
||||
} elseif ($input instanceof DomainObjectInterface) {
|
||||
$parameter = (int)$input->getUid();
|
||||
} elseif (TypeHandlingUtility::isValidTypeForMultiValueComparison($input)) {
|
||||
$plainValueArray = [];
|
||||
foreach ($input as $inputElement) {
|
||||
$plainValueArray[] = $this->getPlainValue($inputElement, $columnMap);
|
||||
}
|
||||
$parameter = implode(',', $plainValueArray);
|
||||
} elseif (is_object($input)) {
|
||||
if (TypeHandlingUtility::isCoreType($input)) {
|
||||
$parameter = (string)$input;
|
||||
} else {
|
||||
throw new UnexpectedTypeException('An object of class "' . get_class($input) . '" could not be converted to a plain value.', 1274799934);
|
||||
}
|
||||
} else {
|
||||
$parameter = (string)$input;
|
||||
}
|
||||
return $parameter;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic\Mapper;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
class Exception extends \TYPO3\CMS\Extbase\Persistence\Exception
|
||||
{
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic\Mapper\Exception;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
class NonExistentPropertyException extends \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\Exception
|
||||
{
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic\Mapper\Exception;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
class UnknownPropertyTypeException extends \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\Exception
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,341 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
|
||||
use TYPO3\CMS\Extbase\Persistence\QueryInterface;
|
||||
|
||||
/**
|
||||
* The Extbase Persistence Manager
|
||||
*/
|
||||
class PersistenceManager implements \TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface, \TYPO3\CMS\Core\SingletonInterface
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $newObjects = [];
|
||||
|
||||
/**
|
||||
* @var ObjectStorage
|
||||
*/
|
||||
protected $changedObjects;
|
||||
|
||||
/**
|
||||
* @var ObjectStorage
|
||||
*/
|
||||
protected $addedObjects;
|
||||
|
||||
/**
|
||||
* @var ObjectStorage
|
||||
*/
|
||||
protected $removedObjects;
|
||||
|
||||
/**
|
||||
* @var \TYPO3\CMS\Extbase\Persistence\Generic\QueryFactoryInterface
|
||||
*/
|
||||
protected $queryFactory;
|
||||
|
||||
/**
|
||||
* @var \TYPO3\CMS\Extbase\Persistence\Generic\BackendInterface
|
||||
*/
|
||||
protected $backend;
|
||||
|
||||
/**
|
||||
* @var \TYPO3\CMS\Extbase\Persistence\Generic\Session
|
||||
*/
|
||||
protected $persistenceSession;
|
||||
|
||||
/**
|
||||
* @param \TYPO3\CMS\Extbase\Persistence\Generic\QueryFactoryInterface $queryFactory
|
||||
* @internal only to be used within Extbase, not part of TYPO3 Core API.
|
||||
*/
|
||||
public function injectQueryFactory(\TYPO3\CMS\Extbase\Persistence\Generic\QueryFactoryInterface $queryFactory)
|
||||
{
|
||||
$this->queryFactory = $queryFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \TYPO3\CMS\Extbase\Persistence\Generic\BackendInterface $backend
|
||||
* @internal only to be used within Extbase, not part of TYPO3 Core API.
|
||||
*/
|
||||
public function injectBackend(\TYPO3\CMS\Extbase\Persistence\Generic\BackendInterface $backend)
|
||||
{
|
||||
$this->backend = $backend;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \TYPO3\CMS\Extbase\Persistence\Generic\Session $persistenceSession
|
||||
* @internal only to be used within Extbase, not part of TYPO3 Core API.
|
||||
*/
|
||||
public function injectPersistenceSession(\TYPO3\CMS\Extbase\Persistence\Generic\Session $persistenceSession)
|
||||
{
|
||||
$this->persistenceSession = $persistenceSession;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new instance
|
||||
* @internal only to be used within Extbase, not part of TYPO3 Core API.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->addedObjects = new ObjectStorage();
|
||||
$this->removedObjects = new ObjectStorage();
|
||||
$this->changedObjects = new ObjectStorage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a repository
|
||||
*
|
||||
* @param string $className The class name of the repository to be registered
|
||||
* @internal only to be used within Extbase, not part of TYPO3 Core API.
|
||||
*/
|
||||
public function registerRepositoryClassName($className)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of records matching the query.
|
||||
*
|
||||
* @param QueryInterface $query
|
||||
* @return int
|
||||
*/
|
||||
public function getObjectCountByQuery(QueryInterface $query)
|
||||
{
|
||||
return $this->backend->getObjectCountByQuery($query);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the object data matching the $query.
|
||||
*
|
||||
* @param QueryInterface $query
|
||||
* @return array
|
||||
*/
|
||||
public function getObjectDataByQuery(QueryInterface $query)
|
||||
{
|
||||
return $this->backend->getObjectDataByQuery($query);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the (internal) identifier for the object, if it is known to the
|
||||
* backend. Otherwise NULL is returned.
|
||||
*
|
||||
* Note: this returns an identifier even if the object has not been
|
||||
* persisted in case of AOP-managed entities. Use isNewObject() if you need
|
||||
* to distinguish those cases.
|
||||
*
|
||||
* @param object $object
|
||||
* @return mixed The identifier for the object if it is known, or NULL
|
||||
*/
|
||||
public function getIdentifierByObject($object)
|
||||
{
|
||||
return $this->backend->getIdentifierByObject($object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the object with the (internal) identifier, if it is known to the
|
||||
* backend. Otherwise NULL is returned.
|
||||
*
|
||||
* @param mixed $identifier
|
||||
* @param string $objectType
|
||||
* @param bool $useLazyLoading Set to TRUE if you want to use lazy loading for this object
|
||||
* @return object The object for the identifier if it is known, or NULL
|
||||
*/
|
||||
public function getObjectByIdentifier($identifier, $objectType = null, $useLazyLoading = false)
|
||||
{
|
||||
if (isset($this->newObjects[$identifier])) {
|
||||
return $this->newObjects[$identifier];
|
||||
}
|
||||
if ($this->persistenceSession->hasIdentifier($identifier, $objectType)) {
|
||||
return $this->persistenceSession->getObjectByIdentifier($identifier, $objectType);
|
||||
}
|
||||
return $this->backend->getObjectByIdentifier($identifier, $objectType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Commits new objects and changes to objects in the current persistence
|
||||
* session into the backend.
|
||||
*/
|
||||
public function persistAll()
|
||||
{
|
||||
// hand in only aggregate roots, leaving handling of subobjects to
|
||||
// the underlying storage layer
|
||||
// reconstituted entities must be fetched from the session and checked
|
||||
// for changes by the underlying backend as well!
|
||||
$this->backend->setAggregateRootObjects($this->addedObjects);
|
||||
$this->backend->setChangedEntities($this->changedObjects);
|
||||
$this->backend->setDeletedEntities($this->removedObjects);
|
||||
$this->backend->commit();
|
||||
|
||||
$this->addedObjects = new ObjectStorage();
|
||||
$this->removedObjects = new ObjectStorage();
|
||||
$this->changedObjects = new ObjectStorage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a query object for the given type.
|
||||
*
|
||||
* @param string $type
|
||||
* @return QueryInterface
|
||||
* @internal only to be used within Extbase, not part of TYPO3 Core API.
|
||||
*/
|
||||
public function createQueryForType($type)
|
||||
{
|
||||
return $this->queryFactory->create($type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an object to the persistence.
|
||||
*
|
||||
* @param object $object The object to add
|
||||
*/
|
||||
public function add($object)
|
||||
{
|
||||
$this->addedObjects->attach($object);
|
||||
$this->removedObjects->detach($object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an object to the persistence.
|
||||
*
|
||||
* @param object $object The object to remove
|
||||
*/
|
||||
public function remove($object)
|
||||
{
|
||||
if ($this->addedObjects->contains($object)) {
|
||||
$this->addedObjects->detach($object);
|
||||
} else {
|
||||
$this->removedObjects->attach($object);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update an object in the persistence.
|
||||
*
|
||||
* @param object $object The modified object
|
||||
* @throws \TYPO3\CMS\Extbase\Persistence\Exception\UnknownObjectException
|
||||
*/
|
||||
public function update($object)
|
||||
{
|
||||
if ($this->isNewObject($object)) {
|
||||
throw new \TYPO3\CMS\Extbase\Persistence\Exception\UnknownObjectException('The object of type "' . get_class($object) . '" given to update must be persisted already, but is new.', 1249479819);
|
||||
}
|
||||
$this->changedObjects->attach($object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Injects the Extbase settings, called by Extbase.
|
||||
*
|
||||
* @param array $settings
|
||||
* @throws \TYPO3\CMS\Extbase\Persistence\Generic\Exception\NotImplementedException
|
||||
*/
|
||||
public function injectSettings(array $settings)
|
||||
{
|
||||
throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception\NotImplementedException(__METHOD__, 1476108078);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the persistence manager, called by Extbase.
|
||||
* @internal only to be used within Extbase, not part of TYPO3 Core API.
|
||||
*/
|
||||
public function initializeObject()
|
||||
{
|
||||
$this->backend->setPersistenceManager($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the in-memory state of the persistence.
|
||||
*
|
||||
* Managed instances become detached, any fetches will
|
||||
* return data directly from the persistence "backend".
|
||||
*
|
||||
* @throws \TYPO3\CMS\Extbase\Persistence\Generic\Exception\NotImplementedException
|
||||
* @internal only to be used within Extbase, not part of TYPO3 Core API.
|
||||
*/
|
||||
public function clearState()
|
||||
{
|
||||
$this->newObjects = [];
|
||||
$this->addedObjects = new ObjectStorage();
|
||||
$this->removedObjects = new ObjectStorage();
|
||||
$this->changedObjects = new ObjectStorage();
|
||||
$this->persistenceSession->destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given object has ever been persisted.
|
||||
*
|
||||
* @param object $object The object to check
|
||||
* @return bool TRUE if the object is new, FALSE if the object exists in the persistence session
|
||||
*/
|
||||
public function isNewObject($object)
|
||||
{
|
||||
return $this->persistenceSession->hasObject($object) === false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers an object which has been created or cloned during this request.
|
||||
*
|
||||
* A "new" object does not necessarily
|
||||
* have to be known by any repository or be persisted in the end.
|
||||
*
|
||||
* Objects registered with this method must be known to the getObjectByIdentifier()
|
||||
* method.
|
||||
*
|
||||
* @param object $object The new object to register
|
||||
* @internal only to be used within Extbase, not part of TYPO3 Core API.
|
||||
*/
|
||||
public function registerNewObject($object)
|
||||
{
|
||||
$identifier = $this->getIdentifierByObject($object);
|
||||
$this->newObjects[$identifier] = $object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the given object into an array containing the identity of the domain object.
|
||||
*
|
||||
* @param object $object The object to be converted
|
||||
* @throws Exception\NotImplementedException
|
||||
*/
|
||||
public function convertObjectToIdentityArray($object)
|
||||
{
|
||||
throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception\NotImplementedException(__METHOD__, 1476108103);
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively iterates through the given array and turns objects
|
||||
* into arrays containing the identity of the domain object.
|
||||
*
|
||||
* @throws \TYPO3\CMS\Extbase\Persistence\Generic\Exception\NotImplementedException
|
||||
* @param array $array The array to be iterated over
|
||||
* @see convertObjectToIdentityArray()
|
||||
*/
|
||||
public function convertObjectsToIdentityArrays(array $array)
|
||||
{
|
||||
throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception\NotImplementedException(__METHOD__, 1476108111);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tear down the persistence
|
||||
*
|
||||
* This method is called in functional tests to reset the storage between tests.
|
||||
* The implementation is optional and depends on the underlying persistence backend.
|
||||
* @internal only to be used within Extbase, not part of TYPO3 Core API.
|
||||
*/
|
||||
public function tearDown()
|
||||
{
|
||||
if (method_exists($this->backend, 'tearDown')) {
|
||||
$this->backend->tearDown();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,360 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* The property types supported by the JCR standard.
|
||||
*
|
||||
* The STRING property type is used to store strings.
|
||||
* BINARY properties are used to store binary data.
|
||||
* The LONG property type is used to store integers.
|
||||
* The DECIMAL property type is used to store precise decimal numbers.
|
||||
* The DOUBLE property type is used to store floating point numbers.
|
||||
* The DATE property type is used to store time and date information. See 4.2.6.1 Date in the specification.
|
||||
* The BOOLEAN property type is used to store boolean values.
|
||||
* A NAME is a pairing of a namespace and a local name. When read, the namespace is mapped to the current prefix. See 4.2.6.2 Name in the specification.
|
||||
* A PATH property is an ordered list of path elements. A path element is a NAME with an optional index. When read, the NAMEs within the path are mapped to their current prefix. A path may be absolute or relative. See 4.2.6.3 Path in the specification.
|
||||
* A REFERENCE property stores the identifier of a referenceable node (one having type mix:referenceable), which must exist within the same workspace or session as the REFERENCE property. A REFERENCE property enforces this referential integrity by preventing (in level 2 implementations) the removal of its target node. See 4.2.6.4 Reference in the specification.
|
||||
* A WEAKREFERENCE property stores the identifier of a referenceable node (one having type mix:referenceable). A WEAKREFERENCE property does not enforce referential integrity. See 4.2.6.5 Weak Reference in the specification.
|
||||
* A URI property is identical to STRING property except that it only accepts values that conform to the syntax of a URI-reference as defined in RFC 3986. See also 4.2.6.6 URI in the specification.
|
||||
* UNDEFINED can be used within a property definition (see 4.7.5 Property Definitions) to specify that the property in question may be of any type. However, it cannot be the actual type of any property instance. For example it will never be returned by Property.getType() and (in level 2 implementations) it cannot be assigned as the type when creating a new property.
|
||||
*
|
||||
* @internal only to be used within Extbase, not part of TYPO3 Core API.
|
||||
*/
|
||||
class PropertyType
|
||||
{
|
||||
/**
|
||||
* This constant can be used within a property definition to specify that
|
||||
* the property in question may be of any type.
|
||||
* However, it cannot be the actual type of any property instance. For
|
||||
* example, it will never be returned by Property#getType and it cannot be
|
||||
* assigned as the type when creating a new property.
|
||||
*/
|
||||
const UNDEFINED = 0;
|
||||
|
||||
/**
|
||||
* The STRING property type is used to store strings.
|
||||
*/
|
||||
const STRING = 1;
|
||||
|
||||
/**
|
||||
* BINARY properties are used to store binary data.
|
||||
*/
|
||||
const BINARY = 2;
|
||||
|
||||
/**
|
||||
* The LONG property type is used to store integers.
|
||||
*/
|
||||
const LONG = 3;
|
||||
|
||||
/**
|
||||
* The DOUBLE property type is used to store floating point numbers.
|
||||
*/
|
||||
const DOUBLE = 4;
|
||||
|
||||
/**
|
||||
* The DATE property type is used to store time and date information.
|
||||
*/
|
||||
const DATE = 5;
|
||||
|
||||
/**
|
||||
* The BOOLEAN property type is used to store boolean values.
|
||||
*/
|
||||
const BOOLEAN = 6;
|
||||
|
||||
/**
|
||||
* A NAME is a pairing of a namespace and a local name. When read, the
|
||||
* namespace is mapped to the current prefix.
|
||||
*
|
||||
* WE DO NOT USE THIS IN EXTBASE!
|
||||
*/
|
||||
const NAME = 7;
|
||||
|
||||
/**
|
||||
* A PATH property is an ordered list of path elements. A path element is a
|
||||
* NAME with an optional index. When read, the NAMEs within the path are
|
||||
* mapped to their current prefix. A path may be absolute or relative.
|
||||
*
|
||||
* WE DO NOT USE THIS IN EXTBASE!
|
||||
*/
|
||||
const PATH = 8;
|
||||
|
||||
/**
|
||||
* A REFERENCE property stores the identifier of a referenceable node (one
|
||||
* having type mix:referenceable), which must exist within the same
|
||||
* workspace or session as the REFERENCE property. A REFERENCE property
|
||||
* enforces this referential integrity by preventing the removal of its
|
||||
* target node.
|
||||
*/
|
||||
const REFERENCE = 9;
|
||||
|
||||
/**
|
||||
* A WEAKREFERENCE property stores the identifier of a referenceable node
|
||||
* (one having type mix:referenceable). A WEAKREFERENCE property does not
|
||||
* enforce referential integrity.
|
||||
*
|
||||
* WE DO NOT USE THIS IN EXTBASE!
|
||||
*/
|
||||
const WEAKREFERENCE = 10;
|
||||
|
||||
/**
|
||||
* A URI property is identical to STRING property except that it only
|
||||
* accepts values that conform to the syntax of a URI-reference as defined
|
||||
* in RFC 3986.
|
||||
*
|
||||
* WE DO NOT USE THIS IN EXTBASE!
|
||||
*/
|
||||
const URI = 11;
|
||||
|
||||
/**
|
||||
* The DECIMAL property type is used to store precise decimal numbers.
|
||||
*
|
||||
* WE DO NOT USE THIS IN EXTBASE!
|
||||
*/
|
||||
const DECIMAL = 12;
|
||||
|
||||
/**
|
||||
* The INTEGER property type is used to store precise decimal numbers.
|
||||
*
|
||||
* WE DO NOT USE THIS IN EXTBASE!
|
||||
*/
|
||||
const INTEGER = 13;
|
||||
|
||||
/**
|
||||
* String constant for type name as used in serialization.
|
||||
*/
|
||||
const TYPENAME_UNDEFINED = 'undefined';
|
||||
|
||||
/**
|
||||
* String constant for type name as used in serialization.
|
||||
*/
|
||||
const TYPENAME_STRING = 'String';
|
||||
|
||||
/**
|
||||
* String constant for type name as used in serialization.
|
||||
*/
|
||||
const TYPENAME_BINARY = 'Binary';
|
||||
|
||||
/**
|
||||
* String constant for type name as used in serialization.
|
||||
*/
|
||||
const TYPENAME_LONG = 'Long';
|
||||
|
||||
/**
|
||||
* String constant for type name as used in serialization.
|
||||
*/
|
||||
const TYPENAME_DOUBLE = 'Double';
|
||||
|
||||
/**
|
||||
* String constant for type name as used in serialization.
|
||||
*/
|
||||
const TYPENAME_DATE = 'Date';
|
||||
|
||||
/**
|
||||
* String constant for type name as used in serialization.
|
||||
*/
|
||||
const TYPENAME_BOOLEAN = 'Boolean';
|
||||
|
||||
/**
|
||||
* String constant for type name as used in serialization.
|
||||
*/
|
||||
const TYPENAME_NAME = 'Name';
|
||||
|
||||
/**
|
||||
* String constant for type name as used in serialization.
|
||||
*/
|
||||
const TYPENAME_PATH = 'Path';
|
||||
|
||||
/**
|
||||
* String constant for type name as used in serialization.
|
||||
*/
|
||||
const TYPENAME_REFERENCE = 'Reference';
|
||||
|
||||
/**
|
||||
* String constant for type name as used in serialization.
|
||||
*/
|
||||
const TYPENAME_WEAKREFERENCE = 'WeakReference';
|
||||
|
||||
/**
|
||||
* String constant for type name as used in serialization.
|
||||
*/
|
||||
const TYPENAME_URI = 'URI';
|
||||
|
||||
/**
|
||||
* String constant for type name as used in serialization.
|
||||
*/
|
||||
const TYPENAME_DECIMAL = 'Decimal';
|
||||
|
||||
/**
|
||||
* String constant for type name as used in serialization.
|
||||
*/
|
||||
const TYPENAME_INTEGER = 'Integer';
|
||||
|
||||
/**
|
||||
* Make instantiation impossible...
|
||||
*/
|
||||
private function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the specified type, as used in serialization.
|
||||
*
|
||||
* @param int $type type the property type
|
||||
* @return string name of the specified type
|
||||
*/
|
||||
public static function nameFromValue($type)
|
||||
{
|
||||
switch ((int)$type) {
|
||||
case self::STRING:
|
||||
$name = self::TYPENAME_STRING;
|
||||
break;
|
||||
case self::BINARY:
|
||||
$name = self::TYPENAME_BINARY;
|
||||
break;
|
||||
case self::BOOLEAN:
|
||||
$name = self::TYPENAME_BOOLEAN;
|
||||
break;
|
||||
case self::LONG:
|
||||
$name = self::TYPENAME_LONG;
|
||||
break;
|
||||
case self::DOUBLE:
|
||||
$name = self::TYPENAME_DOUBLE;
|
||||
break;
|
||||
case self::DECIMAL:
|
||||
$name = self::TYPENAME_DECIMAL;
|
||||
break;
|
||||
case self::INTEGER:
|
||||
$name = self::TYPENAME_INTEGER;
|
||||
break;
|
||||
case self::DATE:
|
||||
$name = self::TYPENAME_DATE;
|
||||
break;
|
||||
case self::NAME:
|
||||
$name = self::TYPENAME_NAME;
|
||||
break;
|
||||
case self::PATH:
|
||||
$name = self::TYPENAME_PATH;
|
||||
break;
|
||||
case self::REFERENCE:
|
||||
$name = self::TYPENAME_REFERENCE;
|
||||
break;
|
||||
case self::WEAKREFERENCE:
|
||||
$name = self::TYPENAME_WEAKREFERENCE;
|
||||
break;
|
||||
case self::URI:
|
||||
$name = self::TYPENAME_URI;
|
||||
break;
|
||||
default:
|
||||
// case self::UNDEFINED:
|
||||
$name = self::TYPENAME_UNDEFINED;
|
||||
}
|
||||
|
||||
return $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the numeric constant value of the type with the specified name.
|
||||
*
|
||||
* @param string $name The name of the property type
|
||||
* @return int The numeric constant value
|
||||
*/
|
||||
public static function valueFromName($name)
|
||||
{
|
||||
switch ($name) {
|
||||
case self::TYPENAME_STRING:
|
||||
$value = self::STRING;
|
||||
break;
|
||||
case self::TYPENAME_BINARY:
|
||||
$value = self::BINARY;
|
||||
break;
|
||||
case self::TYPENAME_LONG:
|
||||
$value = self::LONG;
|
||||
break;
|
||||
case self::TYPENAME_DOUBLE:
|
||||
$value = self::DOUBLE;
|
||||
break;
|
||||
case self::TYPENAME_DECIMAL:
|
||||
$value = self::DECIMAL;
|
||||
break;
|
||||
case self::TYPENAME_INTEGER:
|
||||
$value = self::INTEGER;
|
||||
break;
|
||||
case self::TYPENAME_DATE:
|
||||
$value = self::DATE;
|
||||
break;
|
||||
case self::TYPENAME_BOOLEAN:
|
||||
$value = self::BOOLEAN;
|
||||
break;
|
||||
case self::TYPENAME_NAME:
|
||||
$value = self::NAME;
|
||||
break;
|
||||
case self::TYPENAME_PATH:
|
||||
$value = self::PATH;
|
||||
break;
|
||||
case self::TYPENAME_REFERENCE:
|
||||
$value = self::REFERENCE;
|
||||
break;
|
||||
case self::TYPENAME_WEAKREFERENCE:
|
||||
$value = self::WEAKREFERENCE;
|
||||
break;
|
||||
case self::TYPENAME_URI:
|
||||
$value = self::URI;
|
||||
break;
|
||||
default:
|
||||
// case self::TYPENAME_UNDEFINED:
|
||||
$value = self::UNDEFINED;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the numeric constant value of the type for the given PHP type
|
||||
* name as returned by gettype().
|
||||
*
|
||||
* @param string $type
|
||||
* @return int
|
||||
*/
|
||||
public static function valueFromType($type)
|
||||
{
|
||||
switch (strtolower($type)) {
|
||||
case 'string':
|
||||
$value = \TYPO3\CMS\Extbase\Persistence\Generic\PropertyType::STRING;
|
||||
break;
|
||||
case 'boolean':
|
||||
$value = \TYPO3\CMS\Extbase\Persistence\Generic\PropertyType::BOOLEAN;
|
||||
break;
|
||||
case 'integer':
|
||||
$value = \TYPO3\CMS\Extbase\Persistence\Generic\PropertyType::LONG;
|
||||
break;
|
||||
case 'float':
|
||||
|
||||
case 'double':
|
||||
$value = \TYPO3\CMS\Extbase\Persistence\Generic\PropertyType::DOUBLE;
|
||||
break;
|
||||
case 'int':
|
||||
$value = \TYPO3\CMS\Extbase\Persistence\Generic\PropertyType::INTEGER;
|
||||
break;
|
||||
case 'datetime':
|
||||
$value = \TYPO3\CMS\Extbase\Persistence\Generic\PropertyType::DATE;
|
||||
break;
|
||||
default:
|
||||
$value = \TYPO3\CMS\Extbase\Persistence\Generic\PropertyType::UNDEFINED;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic\Qom;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* Performs a logical conjunction of two other constraints.
|
||||
*
|
||||
* To satisfy the And constraint, a node-tuple must satisfy both constraint1 and
|
||||
* constraint2.
|
||||
*/
|
||||
interface AndInterface extends \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ConstraintInterface
|
||||
{
|
||||
/**
|
||||
* Gets the first constraint.
|
||||
*
|
||||
* @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ConstraintInterface the constraint; non-null
|
||||
*/
|
||||
public function getConstraint1();
|
||||
|
||||
/**
|
||||
* Gets the second constraint.
|
||||
*
|
||||
* @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ConstraintInterface the constraint; non-null
|
||||
*/
|
||||
public function getConstraint2();
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic\Qom;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* Evaluates to the value of a bind variable.
|
||||
* @internal only to be used within Extbase, not part of TYPO3 Core API.
|
||||
*/
|
||||
class BindVariableValue implements \TYPO3\CMS\Extbase\Persistence\Generic\Qom\BindVariableValueInterface
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $variableName;
|
||||
|
||||
/**
|
||||
* Constructs this BindVariableValue instance
|
||||
*
|
||||
* @param string $variableName
|
||||
*/
|
||||
public function __construct($variableName)
|
||||
{
|
||||
$this->variableName = $variableName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills an array with the names of all bound variables in the operand
|
||||
*
|
||||
* @param array &$boundVariables
|
||||
*/
|
||||
public function collectBoundVariableNames(&$boundVariables)
|
||||
{
|
||||
$boundVariables[$this->variableName] = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the bind variable.
|
||||
*
|
||||
* @return string the bind variable name; non-null
|
||||
*/
|
||||
public function getBindVariableName()
|
||||
{
|
||||
return $this->variableName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic\Qom;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* Evaluates to the value of a bind variable.
|
||||
*/
|
||||
interface BindVariableValueInterface extends \TYPO3\CMS\Extbase\Persistence\Generic\Qom\StaticOperandInterface
|
||||
{
|
||||
/**
|
||||
* Gets the name of the bind variable.
|
||||
*
|
||||
* @return string the bind variable name; non-null
|
||||
*/
|
||||
public function getBindVariableName();
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic\Qom;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
use TYPO3\CMS\Extbase\Persistence\QueryInterface;
|
||||
|
||||
/**
|
||||
* Filters node-tuples based on the outcome of a binary operation.
|
||||
*
|
||||
* For any comparison, operand2 always evaluates to a scalar value. In contrast,
|
||||
* operand1 may evaluate to an array of values (for example, the value of a multi-valued
|
||||
* property), in which case the comparison is separately performed for each element
|
||||
* of the array, and the Comparison constraint is satisfied as a whole if the
|
||||
* comparison against any element of the array is satisfied.
|
||||
*
|
||||
* If operand1 and operand2 evaluate to values of different property types, the
|
||||
* value of operand2 is converted to the property type of the value of operand1.
|
||||
* If the type conversion fails, the query is invalid.
|
||||
*
|
||||
* If operator is not supported for the property type of operand1, the query is invalid.
|
||||
*
|
||||
* If operand1 evaluates to null (for example, if the operand evaluates the value
|
||||
* of a property which does not exist), the constraint is not satisfied.
|
||||
*
|
||||
* The OPERATOR_EQUAL_TO operator is satisfied only if the value of operand1
|
||||
* equals the value of operand2.
|
||||
*
|
||||
* The OPERATOR_NOT_EQUAL_TO operator is satisfied unless the value of
|
||||
* operand1 equals the value of operand2.
|
||||
*
|
||||
* The OPERATOR_LESSS_THAN operator is satisfied only if the value of
|
||||
* operand1 is ordered before the value of operand2.
|
||||
*
|
||||
* The OPERATOR_LESS_THAN_OR_EQUAL_TO operator is satisfied unless the value
|
||||
* of operand1 is ordered after the value of operand2.
|
||||
*
|
||||
* The OPERATOR_GREATER_THAN operator is satisfied only if the value of
|
||||
* operand1 is ordered after the value of operand2.
|
||||
*
|
||||
* The OPERATOR_GREATER_THAN_OR_EQUAL_TO operator is satisfied unless the
|
||||
* value of operand1 is ordered before the value of operand2.
|
||||
*
|
||||
* The OPERATOR_LIKE operator is satisfied only if the value of operand1
|
||||
* matches the pattern specified by the value of operand2, where in the pattern:
|
||||
* the character "%" matches zero or more characters, and
|
||||
* the character "_" (underscore) matches exactly one character, and
|
||||
* the string "\x" matches the character "x", and
|
||||
* all other characters match themselves.
|
||||
* @internal only to be used within Extbase, not part of TYPO3 Core API.
|
||||
*/
|
||||
class Comparison implements ComparisonInterface
|
||||
{
|
||||
/**
|
||||
* @var PropertyValueInterface
|
||||
*/
|
||||
protected $operand1;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $operator;
|
||||
|
||||
/**
|
||||
* @var mixed
|
||||
*/
|
||||
protected $operand2;
|
||||
|
||||
/**
|
||||
* Constructs this Comparison instance
|
||||
*
|
||||
* @param PropertyValueInterface $operand1
|
||||
* @param int $operator one of QueryInterface::OPERATOR_*
|
||||
* @param mixed $operand2
|
||||
*/
|
||||
public function __construct(PropertyValueInterface $operand1, $operator, $operand2)
|
||||
{
|
||||
$this->operand1 = $operand1;
|
||||
$this->operator = $operator;
|
||||
$this->operand2 = $operand2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the first operand.
|
||||
*
|
||||
* @return PropertyValueInterface the operand; non-null
|
||||
*/
|
||||
public function getOperand1()
|
||||
{
|
||||
return $this->operand1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the operator.
|
||||
*
|
||||
* @return string One of QueryInterface::OPERATOR_*
|
||||
*/
|
||||
public function getOperator()
|
||||
{
|
||||
$operator = $this->operator;
|
||||
|
||||
if ($this->getOperand2() === null) {
|
||||
if ($operator === QueryInterface::OPERATOR_EQUAL_TO) {
|
||||
$operator = QueryInterface::OPERATOR_EQUAL_TO_NULL;
|
||||
} elseif ($operator === QueryInterface::OPERATOR_NOT_EQUAL_TO) {
|
||||
$operator = QueryInterface::OPERATOR_NOT_EQUAL_TO_NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return $operator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the second operand.
|
||||
*
|
||||
* @return mixed the operand; non-null
|
||||
*/
|
||||
public function getOperand2()
|
||||
{
|
||||
return $this->operand2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills an array with the names of all bound variables in the constraints
|
||||
*
|
||||
* @param array &$boundVariables
|
||||
*/
|
||||
public function collectBoundVariableNames(&$boundVariables)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic\Qom;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* Filters node-tuples based on the outcome of a binary operation.
|
||||
*
|
||||
* For any comparison, operand2 always evaluates to a scalar value. In contrast,
|
||||
* operand1 may evaluate to an array of values (for example, the value of a multi-valued
|
||||
* property), in which case the comparison is separately performed for each element
|
||||
* of the array, and the Comparison constraint is satisfied as a whole if the
|
||||
* comparison against any element of the array is satisfied.
|
||||
*
|
||||
* If operand1 and operand2 evaluate to values of different property types, the
|
||||
* value of operand2 is converted to the property type of the value of operand1.
|
||||
* If the type conversion fails, the query is invalid.
|
||||
*
|
||||
* If operator is not supported for the property type of operand1, the query is invalid.
|
||||
*
|
||||
* If operand1 evaluates to null (for example, if the operand evaluates the value
|
||||
* of a property which does not exist), the constraint is not satisfied.
|
||||
*
|
||||
* The JCR_OPERATOR_EQUAL_TO operator is satisfied only if the value of operand1
|
||||
* equals the value of operand2.
|
||||
*
|
||||
* The JCR_OPERATOR_NOT_EQUAL_TO operator is satisfied unless the value of
|
||||
* operand1 equals the value of operand2.
|
||||
*
|
||||
* The JCR_OPERATOR_LESSS_THAN operator is satisfied only if the value of
|
||||
* operand1 is ordered before the value of operand2.
|
||||
*
|
||||
* The JCR_OPERATOR_LESS_THAN_OR_EQUAL_TO operator is satisfied unless the value
|
||||
* of operand1 is ordered after the value of operand2.
|
||||
*
|
||||
* The JCR_OPERATOR_GREATER_THAN operator is satisfied only if the value of
|
||||
* operand1 is ordered after the value of operand2.
|
||||
*
|
||||
* The JCR_OPERATOR_GREATER_THAN_OR_EQUAL_TO operator is satisfied unless the
|
||||
* value of operand1 is ordered before the value of operand2.
|
||||
*
|
||||
* The JCR_OPERATOR_LIKE operator is satisfied only if the value of operand1
|
||||
* matches the pattern specified by the value of operand2, where in the pattern:
|
||||
* the character "%" matches zero or more characters, and
|
||||
* the character "_" (underscore) matches exactly one character, and
|
||||
* the string "\x" matches the character "x", and
|
||||
* all other characters match themselves.
|
||||
*/
|
||||
interface ComparisonInterface extends ConstraintInterface
|
||||
{
|
||||
/**
|
||||
* Gets the first operand.
|
||||
*
|
||||
* @return PropertyValueInterface the operand; non-null
|
||||
*/
|
||||
public function getOperand1();
|
||||
|
||||
/**
|
||||
* Gets the operator.
|
||||
*
|
||||
* @return string one of \TYPO3\CMS\Extbase\Persistence\QueryInterface::*
|
||||
*/
|
||||
public function getOperator();
|
||||
|
||||
/**
|
||||
* Gets the second operand.
|
||||
*
|
||||
* @return StaticOperandInterface the operand; non-null
|
||||
*/
|
||||
public function getOperand2();
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic\Qom;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* Filters the set of tuples formed by evaluating the query's sources and
|
||||
* the joins between them.
|
||||
*
|
||||
* To be included in the query results, a tuple must satisfy the constraint.
|
||||
*/
|
||||
interface ConstraintInterface
|
||||
{
|
||||
/**
|
||||
* Fills an array with the names of all bound variables in the constraints
|
||||
*
|
||||
* @param array &$boundVariables
|
||||
*/
|
||||
public function collectBoundVariableNames(&$boundVariables);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic\Qom;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* An operand whose value can only be determined in evaluating the query.
|
||||
*/
|
||||
interface DynamicOperandInterface extends OperandInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic\Qom;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* Tests whether the value of a property in a first selector is equal to the value of a
|
||||
* property in a second selector.
|
||||
* A node-tuple satisfies the constraint only if: the selector1Name node has a property named property1Name, and
|
||||
* the selector2Name node has a property named property2Name, and
|
||||
* the value of property property1Name is equal to the value of property property2Name.
|
||||
* @internal only to be used within Extbase, not part of TYPO3 Core API.
|
||||
*/
|
||||
class EquiJoinCondition implements EquiJoinConditionInterface
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $selector1Name;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $property1Name;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $selector2Name;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $property2Name;
|
||||
|
||||
/**
|
||||
* Constructs this EquiJoinCondition instance
|
||||
*
|
||||
* @param string $selector1Name the name of the first selector; non-null
|
||||
* @param string $property1Name the property name in the first selector; non-null
|
||||
* @param string $selector2Name the name of the second selector; non-null
|
||||
* @param string $property2Name the property name in the second selector; non-null
|
||||
*/
|
||||
public function __construct($selector1Name, $property1Name, $selector2Name, $property2Name)
|
||||
{
|
||||
// @todo Test for selector1Name = selector2Name -> exception
|
||||
$this->selector1Name = $selector1Name;
|
||||
$this->property1Name = $property1Name;
|
||||
$this->selector2Name = $selector2Name;
|
||||
$this->property2Name = $property2Name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the first selector.
|
||||
*
|
||||
* @return string the selector name; non-null
|
||||
*/
|
||||
public function getSelector1Name()
|
||||
{
|
||||
return $this->selector1Name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the first property.
|
||||
*
|
||||
* @return string the property name; non-null
|
||||
*/
|
||||
public function getProperty1Name()
|
||||
{
|
||||
return $this->property1Name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the second selector.
|
||||
*
|
||||
* @return string the selector name; non-null
|
||||
*/
|
||||
public function getSelector2Name()
|
||||
{
|
||||
return $this->selector2Name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the second property.
|
||||
*
|
||||
* @return string the property name; non-null
|
||||
*/
|
||||
public function getProperty2Name()
|
||||
{
|
||||
return $this->property2Name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the child selector.
|
||||
*
|
||||
* @return string the selector name; non-null
|
||||
*/
|
||||
public function getChildSelectorName()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the parent selector.
|
||||
*
|
||||
* @return string the selector name; non-null
|
||||
*/
|
||||
public function getParentSelectorName()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic\Qom;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* Tests whether the childSelector node is a child of the parentSelector node. A
|
||||
* node-tuple satisfies the constraint only if:
|
||||
* childSelectorNode.getParent().isSame(parentSelectorNode)
|
||||
* would return true, where childSelectorNode is the node for childSelector and
|
||||
* parentSelectorNode is the node for parentSelector.
|
||||
*/
|
||||
interface EquiJoinConditionInterface extends JoinConditionInterface
|
||||
{
|
||||
/**
|
||||
* Gets the name of the child selector.
|
||||
*
|
||||
* @return string the selector name; non-null
|
||||
*/
|
||||
public function getChildSelectorName();
|
||||
|
||||
/**
|
||||
* Gets the name of the parent selector.
|
||||
*
|
||||
* @return string the selector name; non-null
|
||||
*/
|
||||
public function getParentSelectorName();
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic\Qom;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* Performs a join between two node-tuple sources.
|
||||
* @internal only to be used within Extbase, not part of TYPO3 Core API.
|
||||
*/
|
||||
class Join implements JoinInterface
|
||||
{
|
||||
/**
|
||||
* @var SourceInterface
|
||||
*/
|
||||
protected $left;
|
||||
|
||||
/**
|
||||
* @var SourceInterface
|
||||
*/
|
||||
protected $right;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $joinType;
|
||||
|
||||
/**
|
||||
* @var JoinConditionInterface
|
||||
*/
|
||||
protected $joinCondition;
|
||||
|
||||
/**
|
||||
* Constructs the Join instance
|
||||
*
|
||||
* @param SourceInterface $left the left node-tuple source; non-null
|
||||
* @param SourceInterface $right the right node-tuple source; non-null
|
||||
* @param string $joinType One of Query::JCR_JOIN_TYPE_*
|
||||
* @param JoinConditionInterface $joinCondition
|
||||
*/
|
||||
public function __construct(SourceInterface $left, SourceInterface $right, $joinType, JoinConditionInterface $joinCondition)
|
||||
{
|
||||
$this->left = $left;
|
||||
$this->right = $right;
|
||||
$this->joinType = $joinType;
|
||||
$this->joinCondition = $joinCondition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the left node-tuple source.
|
||||
*
|
||||
* @return SourceInterface the left source; non-null
|
||||
*/
|
||||
public function getLeft()
|
||||
{
|
||||
return $this->left;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the right node-tuple source.
|
||||
*
|
||||
* @return SourceInterface the right source; non-null
|
||||
*/
|
||||
public function getRight()
|
||||
{
|
||||
return $this->right;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the join type.
|
||||
*
|
||||
* @return string one of QueryObjectModelConstants.JCR_JOIN_TYPE_*
|
||||
*/
|
||||
public function getJoinType()
|
||||
{
|
||||
return $this->joinType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the join condition.
|
||||
*
|
||||
* @return JoinConditionInterface the join condition; non-null
|
||||
*/
|
||||
public function getJoinCondition()
|
||||
{
|
||||
return $this->joinCondition;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic\Qom;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* Filters the set of node-tuples formed from a join.
|
||||
*/
|
||||
interface JoinConditionInterface
|
||||
{
|
||||
/**
|
||||
* Gets the name of the first selector.
|
||||
*
|
||||
* @return string the selector name; non-null
|
||||
*/
|
||||
public function getSelector1Name();
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic\Qom;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* Performs a join between two node-tuple sources.
|
||||
*/
|
||||
interface JoinInterface extends SourceInterface
|
||||
{
|
||||
/**
|
||||
* Gets the left node-tuple source.
|
||||
*
|
||||
* @return SelectorInterface the left source; non-null
|
||||
*/
|
||||
public function getLeft();
|
||||
|
||||
/**
|
||||
* Gets the right node-tuple source.
|
||||
*
|
||||
* @return SelectorInterface the right source; non-null
|
||||
*/
|
||||
public function getRight();
|
||||
|
||||
/**
|
||||
* Gets the join type.
|
||||
*
|
||||
* @return string one of QueryObjectModelConstants.JCR_JOIN_TYPE_*
|
||||
*/
|
||||
public function getJoinType();
|
||||
|
||||
/**
|
||||
* Gets the join condition.
|
||||
*
|
||||
* @return JoinConditionInterface the join condition; non-null
|
||||
*/
|
||||
public function getJoinCondition();
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic\Qom;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* Performs a logical conjunction of two other constraints.
|
||||
*
|
||||
* To satisfy the And constraint, a node-tuple must satisfy both constraint1 and
|
||||
* constraint2.
|
||||
* @internal only to be used within Extbase, not part of TYPO3 Core API.
|
||||
*/
|
||||
class LogicalAnd implements AndInterface
|
||||
{
|
||||
/**
|
||||
* @var ConstraintInterface
|
||||
*/
|
||||
protected $constraint1;
|
||||
|
||||
/**
|
||||
* @var ConstraintInterface
|
||||
*/
|
||||
protected $constraint2;
|
||||
|
||||
/**
|
||||
* @param ConstraintInterface $constraint1
|
||||
* @param ConstraintInterface $constraint2
|
||||
*/
|
||||
public function __construct(ConstraintInterface $constraint1, ConstraintInterface $constraint2)
|
||||
{
|
||||
$this->constraint1 = $constraint1;
|
||||
$this->constraint2 = $constraint2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills an array with the names of all bound variables in the constraints
|
||||
*
|
||||
* @param array &$boundVariables
|
||||
*/
|
||||
public function collectBoundVariableNames(&$boundVariables)
|
||||
{
|
||||
$this->constraint1->collectBoundVariableNames($boundVariables);
|
||||
$this->constraint2->collectBoundVariableNames($boundVariables);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the first constraint.
|
||||
*
|
||||
* @return ConstraintInterface the constraint; non-null
|
||||
*/
|
||||
public function getConstraint1()
|
||||
{
|
||||
return $this->constraint1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the second constraint.
|
||||
*
|
||||
* @return ConstraintInterface the constraint; non-null
|
||||
*/
|
||||
public function getConstraint2()
|
||||
{
|
||||
return $this->constraint2;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic\Qom;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* Performs a logical negation of another constraint.
|
||||
*
|
||||
* To satisfy the Not constraint, the node-tuple must not satisfy constraint.
|
||||
* @internal only to be used within Extbase, not part of TYPO3 Core API.
|
||||
*/
|
||||
class LogicalNot implements NotInterface
|
||||
{
|
||||
/**
|
||||
* @var ConstraintInterface
|
||||
*/
|
||||
protected $constraint;
|
||||
|
||||
/**
|
||||
* @param ConstraintInterface $constraint
|
||||
*/
|
||||
public function __construct(ConstraintInterface $constraint)
|
||||
{
|
||||
$this->constraint = $constraint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills an array with the names of all bound variables in the constraint
|
||||
*
|
||||
* @param array &$boundVariables
|
||||
*/
|
||||
public function collectBoundVariableNames(&$boundVariables)
|
||||
{
|
||||
$this->constraint->collectBoundVariableNames($boundVariables);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the constraint negated by this Not constraint.
|
||||
*
|
||||
* @return ConstraintInterface the constraint; non-null
|
||||
*/
|
||||
public function getConstraint()
|
||||
{
|
||||
return $this->constraint;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic\Qom;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* Performs a logical disjunction of two other constraints.
|
||||
*
|
||||
* To satisfy the Or constraint, the node-tuple must either:
|
||||
* satisfy constraint1 but not constraint2, or
|
||||
* satisfy constraint2 but not constraint1, or
|
||||
* satisfy both constraint1 and constraint2.
|
||||
* @internal only to be used within Extbase, not part of TYPO3 Core API.
|
||||
*/
|
||||
class LogicalOr implements OrInterface
|
||||
{
|
||||
/**
|
||||
* @var ConstraintInterface
|
||||
*/
|
||||
protected $constraint1;
|
||||
|
||||
/**
|
||||
* @var ConstraintInterface
|
||||
*/
|
||||
protected $constraint2;
|
||||
|
||||
/**
|
||||
* @param ConstraintInterface $constraint1
|
||||
* @param ConstraintInterface $constraint2
|
||||
*/
|
||||
public function __construct(ConstraintInterface $constraint1, ConstraintInterface $constraint2)
|
||||
{
|
||||
$this->constraint1 = $constraint1;
|
||||
$this->constraint2 = $constraint2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills an array with the names of all bound variables in the constraints
|
||||
*
|
||||
* @param array &$boundVariables
|
||||
*/
|
||||
public function collectBoundVariableNames(&$boundVariables)
|
||||
{
|
||||
$this->constraint1->collectBoundVariableNames($boundVariables);
|
||||
$this->constraint2->collectBoundVariableNames($boundVariables);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the first constraint.
|
||||
*
|
||||
* @return ConstraintInterface the constraint; non-null
|
||||
*/
|
||||
public function getConstraint1()
|
||||
{
|
||||
return $this->constraint1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the second constraint.
|
||||
*
|
||||
* @return ConstraintInterface the constraint; non-null
|
||||
*/
|
||||
public function getConstraint2()
|
||||
{
|
||||
return $this->constraint2;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic\Qom;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* Evaluates to the lower-case string value (or values, if multi-valued) of
|
||||
* operand.
|
||||
*
|
||||
* If operand does not evaluate to a string value, its value is first converted
|
||||
* to a string.
|
||||
*
|
||||
* If operand evaluates to null, the LowerCase operand also evaluates to null.
|
||||
* @internal only to be used within Extbase, not part of TYPO3 Core API.
|
||||
*/
|
||||
class LowerCase implements LowerCaseInterface
|
||||
{
|
||||
/**
|
||||
* @var PropertyValueInterface
|
||||
*/
|
||||
protected $operand;
|
||||
|
||||
/**
|
||||
* Constructs this LowerCase instance
|
||||
*
|
||||
* @param PropertyValueInterface $operand
|
||||
*/
|
||||
public function __construct(PropertyValueInterface $operand)
|
||||
{
|
||||
$this->operand = $operand;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the operand whose value is converted to a lower-case string.
|
||||
*
|
||||
* @return PropertyValueInterface the operand; non-null
|
||||
*/
|
||||
public function getOperand()
|
||||
{
|
||||
return $this->operand;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the selector against which to evaluate this operand.
|
||||
*
|
||||
* @return string the selector name; non-null
|
||||
*/
|
||||
public function getSelectorName()
|
||||
{
|
||||
return $this->operand->getSelectorName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the property.
|
||||
*
|
||||
* @return string the property name; non-null
|
||||
*/
|
||||
public function getPropertyName()
|
||||
{
|
||||
return 'LOWER' . $this->operand->getPropertyName();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic\Qom;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* Evaluates to the lower-case string value (or values, if multi-valued) of
|
||||
* operand.
|
||||
*
|
||||
* If operand does not evaluate to a string value, its value is first converted
|
||||
* to a string.
|
||||
*
|
||||
* If operand evaluates to null, the LowerCase operand also evaluates to null.
|
||||
*/
|
||||
interface LowerCaseInterface extends PropertyValueInterface
|
||||
{
|
||||
/**
|
||||
* Gets the operand whose value is converted to a lower-case string.
|
||||
*
|
||||
* @return PropertyValueInterface the operand; non-null
|
||||
*/
|
||||
public function getOperand();
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic\Qom;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* Performs a logical negation of another constraint.
|
||||
*
|
||||
* To satisfy the Not constraint, the node-tuple must not satisfy constraint.
|
||||
*/
|
||||
interface NotInterface extends ConstraintInterface
|
||||
{
|
||||
/**
|
||||
* Gets the constraint negated by this Not constraint.
|
||||
*
|
||||
* @return ConstraintInterface the constraint; non-null
|
||||
*/
|
||||
public function getConstraint();
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic\Qom;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* An operand to a binary operation specified by a Comparison.
|
||||
*/
|
||||
interface OperandInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic\Qom;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* Performs a logical disjunction of two other constraints.
|
||||
*
|
||||
* To satisfy the Or constraint, the node-tuple must either:
|
||||
* satisfy constraint1 but not constraint2, or
|
||||
* satisfy constraint2 but not constraint1, or
|
||||
* satisfy both constraint1 and constraint2.
|
||||
*/
|
||||
interface OrInterface extends ConstraintInterface
|
||||
{
|
||||
/**
|
||||
* Gets the first constraint.
|
||||
*
|
||||
* @return ConstraintInterface the constraint; non-null
|
||||
*/
|
||||
public function getConstraint1();
|
||||
|
||||
/**
|
||||
* Gets the second constraint.
|
||||
*
|
||||
* @return ConstraintInterface the constraint; non-null
|
||||
*/
|
||||
public function getConstraint2();
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic\Qom;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* Determines the relative order of two rows in the result set by evaluating operand for
|
||||
* each.
|
||||
* @internal only to be used within Extbase, not part of TYPO3 Core API.
|
||||
*/
|
||||
class Ordering implements OrderingInterface
|
||||
{
|
||||
/**
|
||||
* @var DynamicOperandInterface
|
||||
*/
|
||||
protected $operand;
|
||||
|
||||
/**
|
||||
* @var string One of \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_*
|
||||
*/
|
||||
protected $order;
|
||||
|
||||
/**
|
||||
* Constructs the Ordering instance
|
||||
*
|
||||
* @param DynamicOperandInterface $operand The operand; non-null
|
||||
* @param string $order One of \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_*
|
||||
*/
|
||||
public function __construct(DynamicOperandInterface $operand, $order = \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_ASCENDING)
|
||||
{
|
||||
$this->operand = $operand;
|
||||
$this->order = $order;
|
||||
}
|
||||
|
||||
/**
|
||||
* The operand by which to order.
|
||||
*
|
||||
* @return DynamicOperandInterface the operand; non-null
|
||||
*/
|
||||
public function getOperand()
|
||||
{
|
||||
return $this->operand;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the order.
|
||||
*
|
||||
* @return string One of \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_*
|
||||
*/
|
||||
public function getOrder()
|
||||
{
|
||||
return $this->order;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic\Qom;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* Determines the relative order of two rows in the result set by evaluating operand for
|
||||
* each.
|
||||
*/
|
||||
interface OrderingInterface
|
||||
{
|
||||
/**
|
||||
* The operand by which to order.
|
||||
*
|
||||
* @return DynamicOperandInterface the operand; non-null
|
||||
*/
|
||||
public function getOperand();
|
||||
|
||||
/**
|
||||
* Gets the order.
|
||||
*
|
||||
* @return string One of \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_*
|
||||
*/
|
||||
public function getOrder();
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic\Qom;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* Evaluates to the value (or values, if multi-valued) of a property.
|
||||
*
|
||||
* If, for a node-tuple, the selector node does not have a property named property,
|
||||
* the operand evaluates to null.
|
||||
*
|
||||
* The query is invalid if:
|
||||
*
|
||||
* selector is not the name of a selector in the query, or
|
||||
* property is not a syntactically valid JCR name.
|
||||
*
|
||||
* @internal only to be used within Extbase, not part of TYPO3 Core API.
|
||||
*/
|
||||
class PropertyValue implements PropertyValueInterface
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $selectorName;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $propertyName;
|
||||
|
||||
/**
|
||||
* Constructs this PropertyValue instance
|
||||
*
|
||||
* @param string $propertyName
|
||||
* @param string $selectorName
|
||||
*/
|
||||
public function __construct($propertyName, $selectorName = '')
|
||||
{
|
||||
$this->propertyName = $propertyName;
|
||||
$this->selectorName = $selectorName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the selector against which to evaluate this operand.
|
||||
*
|
||||
* @return string the selector name; non-null
|
||||
*/
|
||||
public function getSelectorName()
|
||||
{
|
||||
return $this->selectorName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the property.
|
||||
*
|
||||
* @return string the property name; non-null
|
||||
*/
|
||||
public function getPropertyName()
|
||||
{
|
||||
return $this->propertyName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic\Qom;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* Evaluates to the value (or values, if multi-valued) of a property.
|
||||
*
|
||||
* If, for a node-tuple, the selector node does not have a property named property,
|
||||
* the operand evaluates to null.
|
||||
*
|
||||
* The query is invalid if:
|
||||
*
|
||||
* selector is not the name of a selector in the query, or
|
||||
* property is not a syntactically valid JCR name.
|
||||
*/
|
||||
interface PropertyValueInterface extends DynamicOperandInterface
|
||||
{
|
||||
/**
|
||||
* Gets the name of the selector against which to evaluate this operand.
|
||||
*
|
||||
* @return string the selector name; non-null
|
||||
*/
|
||||
public function getSelectorName();
|
||||
|
||||
/**
|
||||
* Gets the name of the property.
|
||||
*
|
||||
* @return string the property name; non-null
|
||||
*/
|
||||
public function getPropertyName();
|
||||
}
|
||||
@@ -0,0 +1,221 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic\Qom;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* The Query Object Model Factory
|
||||
* @internal only to be used within Extbase, not part of TYPO3 Core API.
|
||||
*/
|
||||
class QueryObjectModelFactory implements \TYPO3\CMS\Core\SingletonInterface
|
||||
{
|
||||
/**
|
||||
* @var \TYPO3\CMS\Extbase\Object\ObjectManagerInterface
|
||||
*/
|
||||
protected $objectManager;
|
||||
|
||||
/**
|
||||
* @param \TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager
|
||||
*/
|
||||
public function injectObjectManager(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager)
|
||||
{
|
||||
$this->objectManager = $objectManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects a subset of the nodes in the repository based on node type.
|
||||
*
|
||||
* @param string $nodeTypeName the name of the required node type; non-null
|
||||
* @param string $selectorName the selector name; optional
|
||||
* @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\SelectorInterface the selector
|
||||
* @throws \TYPO3\CMS\Extbase\Persistence\Generic\Exception\RepositoryException if the operation otherwise fails
|
||||
*/
|
||||
public function selector($nodeTypeName, $selectorName = '')
|
||||
{
|
||||
if ($selectorName === '') {
|
||||
$selectorName = $nodeTypeName;
|
||||
}
|
||||
return $this->objectManager->get(\TYPO3\CMS\Extbase\Persistence\Generic\Qom\Selector::class, $selectorName, $nodeTypeName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a statement as constraint. This is not part of the JCR 2.0 Specification!
|
||||
*
|
||||
* @param string $statement The statement
|
||||
* @param array $boundVariables An array of variables to bind to the statement
|
||||
* @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\Statement
|
||||
*/
|
||||
public function statement($statement, array $boundVariables = [])
|
||||
{
|
||||
return $this->objectManager->get(\TYPO3\CMS\Extbase\Persistence\Generic\Qom\Statement::class, $statement, $boundVariables);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a join between two node-tuple sources.
|
||||
*
|
||||
* @param SourceInterface $left the left node-tuple source; non-null
|
||||
* @param SourceInterface $right the right node-tuple source; non-null
|
||||
* @param string $joinType one of QueryObjectModelConstants.JCR_JOIN_TYPE_*
|
||||
* @param JoinConditionInterface $joinCondition
|
||||
* @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\JoinInterface the join; non-null
|
||||
*/
|
||||
public function join(SourceInterface $left, SourceInterface $right, $joinType, JoinConditionInterface $joinCondition)
|
||||
{
|
||||
return $this->objectManager->get(\TYPO3\CMS\Extbase\Persistence\Generic\Qom\Join::class, $left, $right, $joinType, $joinCondition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether the value of a property in a first selector is equal to the value of a property in a second selector.
|
||||
*
|
||||
* @param string $selector1Name the name of the first selector; non-null
|
||||
* @param string $property1Name the property name in the first selector; non-null
|
||||
* @param string $selector2Name the name of the second selector; non-null
|
||||
* @param string $property2Name the property name in the second selector; non-null
|
||||
* @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\EquiJoinConditionInterface the constraint; non-null
|
||||
* @throws \TYPO3\CMS\Extbase\Persistence\Generic\Exception\RepositoryException if the operation otherwise fails
|
||||
*/
|
||||
public function equiJoinCondition($selector1Name, $property1Name, $selector2Name, $property2Name)
|
||||
{
|
||||
return $this->objectManager->get(\TYPO3\CMS\Extbase\Persistence\Generic\Qom\EquiJoinCondition::class, $selector1Name, $property1Name, $selector2Name, $property2Name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a logical conjunction of two other constraints.
|
||||
*
|
||||
* @param ConstraintInterface $constraint1 the first constraint; non-null
|
||||
* @param ConstraintInterface $constraint2 the second constraint; non-null
|
||||
* @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\AndInterface the And constraint; non-null
|
||||
* @throws \TYPO3\CMS\Extbase\Persistence\Generic\Exception\RepositoryException if the operation otherwise fails
|
||||
*/
|
||||
public function _and(ConstraintInterface $constraint1, ConstraintInterface $constraint2)
|
||||
{
|
||||
return $this->objectManager->get(\TYPO3\CMS\Extbase\Persistence\Generic\Qom\LogicalAnd::class, $constraint1, $constraint2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a logical disjunction of two other constraints.
|
||||
*
|
||||
* @param ConstraintInterface $constraint1 the first constraint; non-null
|
||||
* @param ConstraintInterface $constraint2 the second constraint; non-null
|
||||
* @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\OrInterface the Or constraint; non-null
|
||||
* @throws \TYPO3\CMS\Extbase\Persistence\Generic\Exception\RepositoryException if the operation otherwise fails
|
||||
*/
|
||||
public function _or(ConstraintInterface $constraint1, ConstraintInterface $constraint2)
|
||||
{
|
||||
return $this->objectManager->get(\TYPO3\CMS\Extbase\Persistence\Generic\Qom\LogicalOr::class, $constraint1, $constraint2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a logical negation of another constraint.
|
||||
*
|
||||
* @param ConstraintInterface $constraint the constraint to be negated; non-null
|
||||
* @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\NotInterface the Not constraint; non-null
|
||||
* @throws \TYPO3\CMS\Extbase\Persistence\Generic\Exception\RepositoryException if the operation otherwise fails
|
||||
*/
|
||||
public function not(ConstraintInterface $constraint)
|
||||
{
|
||||
return $this->objectManager->get(\TYPO3\CMS\Extbase\Persistence\Generic\Qom\LogicalNot::class, $constraint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters node-tuples based on the outcome of a binary operation.
|
||||
*
|
||||
* @param PropertyValueInterface $operand1 the first operand; non-null
|
||||
* @param string $operator the operator; one of QueryObjectModelConstants.JCR_OPERATOR_*
|
||||
* @param \TYPO3\CMS\Extbase\Persistence\Generic\Qom\StaticOperandInterface $operand2 the second operand; non-null
|
||||
* @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface the constraint; non-null
|
||||
* @throws \TYPO3\CMS\Extbase\Persistence\Generic\Exception\RepositoryException if the operation otherwise fails
|
||||
*/
|
||||
public function comparison(PropertyValueInterface $operand1, $operator, $operand2)
|
||||
{
|
||||
return $this->objectManager->get(\TYPO3\CMS\Extbase\Persistence\Generic\Qom\Comparison::class, $operand1, $operator, $operand2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates to the value (or values, if multi-valued) of a property in the specified or default selector.
|
||||
*
|
||||
* @param string $propertyName the property name; non-null
|
||||
* @param string $selectorName the selector name; non-null
|
||||
* @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\PropertyValueInterface the operand; non-null
|
||||
* @throws \TYPO3\CMS\Extbase\Persistence\Generic\Exception\RepositoryException if the operation otherwise fails
|
||||
*/
|
||||
public function propertyValue($propertyName, $selectorName = '')
|
||||
{
|
||||
return $this->objectManager->get(\TYPO3\CMS\Extbase\Persistence\Generic\Qom\PropertyValue::class, $propertyName, $selectorName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates to the lower-case string value (or values, if multi-valued) of an operand.
|
||||
*
|
||||
* @param PropertyValueInterface $operand the operand whose value is converted to a lower-case string; non-null
|
||||
* @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\LowerCaseInterface the operand; non-null
|
||||
* @throws \TYPO3\CMS\Extbase\Persistence\Generic\Exception\RepositoryException if the operation otherwise fails
|
||||
*/
|
||||
public function lowerCase(PropertyValueInterface $operand)
|
||||
{
|
||||
return $this->objectManager->get(\TYPO3\CMS\Extbase\Persistence\Generic\Qom\LowerCase::class, $operand);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates to the upper-case string value (or values, if multi-valued) of an operand.
|
||||
*
|
||||
* @param PropertyValueInterface $operand the operand whose value is converted to an upper-case string; non-null
|
||||
* @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\UpperCaseInterface the operand; non-null
|
||||
* @throws \TYPO3\CMS\Extbase\Persistence\Generic\Exception\RepositoryException if the operation otherwise fails
|
||||
*/
|
||||
public function upperCase(PropertyValueInterface $operand)
|
||||
{
|
||||
return $this->objectManager->get(\TYPO3\CMS\Extbase\Persistence\Generic\Qom\UpperCase::class, $operand);
|
||||
}
|
||||
|
||||
/**
|
||||
* Orders by the value of the specified operand, in ascending order.
|
||||
*
|
||||
* The query is invalid if $operand does not evaluate to a scalar value.
|
||||
*
|
||||
* @param DynamicOperandInterface $operand the operand by which to order; non-null
|
||||
* @return OrderingInterface the ordering
|
||||
* @throws \TYPO3\CMS\Extbase\Persistence\Generic\Exception\RepositoryException if the operation otherwise fails
|
||||
*/
|
||||
public function ascending(DynamicOperandInterface $operand)
|
||||
{
|
||||
return $this->objectManager->get(\TYPO3\CMS\Extbase\Persistence\Generic\Qom\Ordering::class, $operand, \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_ASCENDING);
|
||||
}
|
||||
|
||||
/**
|
||||
* Orders by the value of the specified operand, in descending order.
|
||||
*
|
||||
* The query is invalid if $operand does not evaluate to a scalar value.
|
||||
*
|
||||
* @param DynamicOperandInterface $operand the operand by which to order; non-null
|
||||
* @return OrderingInterface the ordering
|
||||
* @throws \TYPO3\CMS\Extbase\Persistence\Generic\Exception\RepositoryException if the operation otherwise fails
|
||||
*/
|
||||
public function descending(DynamicOperandInterface $operand)
|
||||
{
|
||||
return $this->objectManager->get(\TYPO3\CMS\Extbase\Persistence\Generic\Qom\Ordering::class, $operand, \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_DESCENDING);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates to the value of a bind variable.
|
||||
*
|
||||
* @param string $bindVariableName the bind variable name; non-null
|
||||
* @return BindVariableValueInterface the operand; non-null
|
||||
* @throws \TYPO3\CMS\Extbase\Persistence\Generic\Exception\RepositoryException if the operation otherwise fails
|
||||
*/
|
||||
public function bindVariable($bindVariableName)
|
||||
{
|
||||
return $this->objectManager->get(\TYPO3\CMS\Extbase\Persistence\Generic\Qom\BindVariableValue::class, $bindVariableName);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic\Qom;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* Selects a subset of the nodes in the repository based on node type.
|
||||
*
|
||||
* A selector selects every node in the repository, subject to access control
|
||||
* constraints, that satisfies at least one of the following conditions:
|
||||
*
|
||||
* the node's primary node type is nodeType, or
|
||||
* the node's primary node type is a subtype of nodeType, or
|
||||
* the node has a mixin node type that is nodeType, or
|
||||
* the node has a mixin node type that is a subtype of nodeType.
|
||||
* @internal only to be used within Extbase, not part of TYPO3 Core API.
|
||||
*/
|
||||
class Selector implements SelectorInterface
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $nodeTypeName;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $selectorName;
|
||||
|
||||
/**
|
||||
* Constructs the Selector instance
|
||||
*
|
||||
* @param string $selectorName
|
||||
* @param string $nodeTypeName
|
||||
*/
|
||||
public function __construct($selectorName, $nodeTypeName)
|
||||
{
|
||||
$this->selectorName = $selectorName;
|
||||
$this->nodeTypeName = $nodeTypeName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the required node type.
|
||||
*
|
||||
* @return string the node type name; non-null
|
||||
*/
|
||||
public function getNodeTypeName()
|
||||
{
|
||||
return $this->nodeTypeName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the selector name.
|
||||
* A selector's name can be used elsewhere in the query to identify the selector.
|
||||
*
|
||||
* @return string the selector name; non-null
|
||||
*/
|
||||
public function getSelectorName()
|
||||
{
|
||||
return $this->selectorName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic\Qom;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* Selects a subset of the nodes in the repository based on node type.
|
||||
*
|
||||
* A selector selects every node in the repository, subject to access control
|
||||
* constraints, that satisfies at least one of the following conditions:
|
||||
*
|
||||
* the node's primary node type is nodeType, or
|
||||
* the node's primary node type is a subtype of nodeType, or
|
||||
* the node has a mixin node type that is nodeType, or
|
||||
* the node has a mixin node type that is a subtype of nodeType.
|
||||
*/
|
||||
interface SelectorInterface extends SourceInterface
|
||||
{
|
||||
/**
|
||||
* Gets the name of the required node type.
|
||||
*
|
||||
* @return string the node type name; non-null
|
||||
*/
|
||||
public function getNodeTypeName();
|
||||
|
||||
/**
|
||||
* Gets the selector name.
|
||||
* A selector's name can be used elsewhere in the query to identify the selector.
|
||||
*
|
||||
* @return string the selector name; non-null
|
||||
*/
|
||||
public function getSelectorName();
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic\Qom;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* Evaluates to a set of node-tuples.
|
||||
*/
|
||||
interface SourceInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic\Qom;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* A statement acting as a constraint.
|
||||
* @internal only to be used within Extbase, not part of TYPO3 Core API.
|
||||
*/
|
||||
class Statement implements ConstraintInterface
|
||||
{
|
||||
/**
|
||||
* @var string|\Doctrine\DBAL\Statement|\TYPO3\CMS\Core\Database\Query\QueryBuilder
|
||||
*/
|
||||
protected $statement;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $boundVariables = [];
|
||||
|
||||
/**
|
||||
* Constructs the Statement instance
|
||||
*
|
||||
* @param string|\Doctrine\DBAL\Statement|\TYPO3\CMS\Core\Database\Query\QueryBuilder $statement The statement as sql string or an instance of \Doctrine\DBAL\Statement or \TYPO3\CMS\Core\Database\Query\QueryBuilder
|
||||
* @param array $boundVariables An array of variables to bind to the statement, only to be used with prepared statements
|
||||
*/
|
||||
public function __construct($statement, array $boundVariables = [])
|
||||
{
|
||||
$this->statement = $statement;
|
||||
$this->boundVariables = $boundVariables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the statement.
|
||||
*
|
||||
* @return string|\Doctrine\DBAL\Statement|\TYPO3\CMS\Core\Database\Query\QueryBuilder the statement; non-null
|
||||
*/
|
||||
public function getStatement()
|
||||
{
|
||||
return $this->statement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the bound variables
|
||||
*
|
||||
* @return array $boundVariables
|
||||
*/
|
||||
public function getBoundVariables()
|
||||
{
|
||||
return $this->boundVariables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills an array with the names of all bound variables in the constraints
|
||||
*
|
||||
* @param array &$boundVariables
|
||||
*/
|
||||
public function collectBoundVariableNames(&$boundVariables)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic\Qom;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* An operand whose value can be determined from static analysis of the query,
|
||||
* prior to its evaluation.
|
||||
*/
|
||||
interface StaticOperandInterface extends OperandInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic\Qom;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* Evaluates to the upper-case string value (or values, if multi-valued) of
|
||||
* operand.
|
||||
*
|
||||
* If operand does not evaluate to a string value, its value is first converted
|
||||
* to a string.
|
||||
*
|
||||
* If operand evaluates to null, the UpperCase operand also evaluates to null.
|
||||
*
|
||||
* @internal only to be used within Extbase, not part of TYPO3 Core API.
|
||||
*/
|
||||
class UpperCase implements UpperCaseInterface
|
||||
{
|
||||
/**
|
||||
* @var PropertyValueInterface
|
||||
*/
|
||||
protected $operand;
|
||||
|
||||
/**
|
||||
* Constructs this UpperCase instance
|
||||
*
|
||||
* @param PropertyValueInterface $operand
|
||||
*/
|
||||
public function __construct(PropertyValueInterface $operand)
|
||||
{
|
||||
$this->operand = $operand;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the operand whose value is converted to an upper-case string.
|
||||
*
|
||||
* @return PropertyValueInterface the operand; non-null
|
||||
*/
|
||||
public function getOperand()
|
||||
{
|
||||
return $this->operand;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the selector against which to evaluate this operand.
|
||||
*
|
||||
* @return string the selector name; non-null
|
||||
*/
|
||||
public function getSelectorName()
|
||||
{
|
||||
return $this->operand->getSelectorName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the property.
|
||||
*
|
||||
* @return string the property name; non-null
|
||||
*/
|
||||
public function getPropertyName()
|
||||
{
|
||||
return 'UPPER' . $this->operand->getPropertyName();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic\Qom;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* Evaluates to the upper-case string value (or values, if multi-valued) of
|
||||
* operand.
|
||||
*
|
||||
* If operand does not evaluate to a string value, its value is first converted
|
||||
* to a string.
|
||||
*
|
||||
* If operand evaluates to null, the UpperCase operand also evaluates to null.
|
||||
*/
|
||||
interface UpperCaseInterface extends PropertyValueInterface
|
||||
{
|
||||
/**
|
||||
* Gets the operand whose value is converted to an upper-case string.
|
||||
*
|
||||
* @return PropertyValueInterface the operand; non-null
|
||||
*/
|
||||
public function getOperand();
|
||||
}
|
||||
@@ -0,0 +1,644 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
use TYPO3\CMS\Extbase\Persistence\QueryInterface;
|
||||
|
||||
/**
|
||||
* The Query class used to run queries against the database
|
||||
*/
|
||||
class Query implements QueryInterface
|
||||
{
|
||||
/**
|
||||
* An inner join.
|
||||
*/
|
||||
const JCR_JOIN_TYPE_INNER = '{http://www.jcp.org/jcr/1.0}joinTypeInner';
|
||||
|
||||
/**
|
||||
* A left-outer join.
|
||||
*/
|
||||
const JCR_JOIN_TYPE_LEFT_OUTER = '{http://www.jcp.org/jcr/1.0}joinTypeLeftOuter';
|
||||
|
||||
/**
|
||||
* A right-outer join.
|
||||
*/
|
||||
const JCR_JOIN_TYPE_RIGHT_OUTER = '{http://www.jcp.org/jcr/1.0}joinTypeRightOuter';
|
||||
|
||||
/**
|
||||
* Charset of strings in QOM
|
||||
*/
|
||||
const CHARSET = 'utf-8';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $type;
|
||||
|
||||
/**
|
||||
* @var \TYPO3\CMS\Extbase\Object\ObjectManagerInterface
|
||||
*/
|
||||
protected $objectManager;
|
||||
|
||||
/**
|
||||
* @var \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapFactory
|
||||
*/
|
||||
protected $dataMapFactory;
|
||||
|
||||
/**
|
||||
* @var \TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface
|
||||
*/
|
||||
protected $persistenceManager;
|
||||
|
||||
/**
|
||||
* @var \TYPO3\CMS\Extbase\Persistence\Generic\Qom\QueryObjectModelFactory
|
||||
*/
|
||||
protected $qomFactory;
|
||||
|
||||
/**
|
||||
* @var \TYPO3\CMS\Extbase\Persistence\Generic\Qom\SourceInterface
|
||||
*/
|
||||
protected $source;
|
||||
|
||||
/**
|
||||
* @var \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ConstraintInterface
|
||||
*/
|
||||
protected $constraint;
|
||||
|
||||
/**
|
||||
* @var \TYPO3\CMS\Extbase\Persistence\Generic\Qom\Statement
|
||||
*/
|
||||
protected $statement;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $orderings = [];
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $limit;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $offset;
|
||||
|
||||
/**
|
||||
* The query settings.
|
||||
*
|
||||
* @var QuerySettingsInterface
|
||||
*/
|
||||
protected $querySettings;
|
||||
|
||||
/**
|
||||
* @var ?QueryInterface
|
||||
* @internal
|
||||
*/
|
||||
protected $parentQuery;
|
||||
|
||||
/**
|
||||
* @param \TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager
|
||||
*/
|
||||
public function injectObjectManager(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager)
|
||||
{
|
||||
$this->objectManager = $objectManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapFactory $dataMapFactory
|
||||
*/
|
||||
public function injectDataMapFactory(\TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapFactory $dataMapFactory)
|
||||
{
|
||||
$this->dataMapFactory = $dataMapFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface $persistenceManager
|
||||
*/
|
||||
public function injectPersistenceManager(\TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface $persistenceManager)
|
||||
{
|
||||
$this->persistenceManager = $persistenceManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \TYPO3\CMS\Extbase\Persistence\Generic\Qom\QueryObjectModelFactory $qomFactory
|
||||
*/
|
||||
public function injectQomFactory(\TYPO3\CMS\Extbase\Persistence\Generic\Qom\QueryObjectModelFactory $qomFactory)
|
||||
{
|
||||
$this->qomFactory = $qomFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a query object working on the given class name
|
||||
*
|
||||
* @param string $type
|
||||
*/
|
||||
public function __construct($type)
|
||||
{
|
||||
$this->type = $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ?QueryInterface
|
||||
* @internal
|
||||
*/
|
||||
public function getParentQuery(): ?QueryInterface
|
||||
{
|
||||
return $this->parentQuery;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ?QueryInterface $parentQuery
|
||||
* @internal
|
||||
*/
|
||||
public function setParentQuery(?QueryInterface $parentQuery): void
|
||||
{
|
||||
$this->parentQuery = $parentQuery;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Query Settings. These Query settings must match the settings expected by
|
||||
* the specific Storage Backend.
|
||||
*
|
||||
* @param QuerySettingsInterface $querySettings The Query Settings
|
||||
*/
|
||||
public function setQuerySettings(QuerySettingsInterface $querySettings)
|
||||
{
|
||||
$this->querySettings = $querySettings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Query Settings.
|
||||
*
|
||||
* @throws Exception
|
||||
* @return QuerySettingsInterface $querySettings The Query Settings
|
||||
*/
|
||||
public function getQuerySettings()
|
||||
{
|
||||
if (!$this->querySettings instanceof QuerySettingsInterface) {
|
||||
throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception('Tried to get the query settings without seting them before.', 1248689115);
|
||||
}
|
||||
return $this->querySettings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type this query cares for.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType()
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the source to fetch the result from
|
||||
*
|
||||
* @param \TYPO3\CMS\Extbase\Persistence\Generic\Qom\SourceInterface $source
|
||||
*/
|
||||
public function setSource(\TYPO3\CMS\Extbase\Persistence\Generic\Qom\SourceInterface $source)
|
||||
{
|
||||
$this->source = $source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the selectorn name or an empty string, if the source is not a selector
|
||||
* @todo This has to be checked at another place
|
||||
*
|
||||
* @return string The selector name
|
||||
*/
|
||||
protected function getSelectorName()
|
||||
{
|
||||
$source = $this->getSource();
|
||||
if ($source instanceof \TYPO3\CMS\Extbase\Persistence\Generic\Qom\SelectorInterface) {
|
||||
return $source->getSelectorName();
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the node-tuple source for this query.
|
||||
*
|
||||
* @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\SourceInterface the node-tuple source; non-null
|
||||
*/
|
||||
public function getSource()
|
||||
{
|
||||
if ($this->source === null) {
|
||||
$this->source = $this->qomFactory->selector($this->getType(), $this->dataMapFactory->buildDataMap($this->getType())->getTableName());
|
||||
}
|
||||
return $this->source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the query against the database and returns the result
|
||||
*
|
||||
* @param bool $returnRawQueryResult avoids the object mapping by the persistence
|
||||
* @return \TYPO3\CMS\Extbase\Persistence\QueryResultInterface|array The query result object or an array if $returnRawQueryResult is TRUE
|
||||
*/
|
||||
public function execute($returnRawQueryResult = false)
|
||||
{
|
||||
if ($returnRawQueryResult) {
|
||||
return $this->persistenceManager->getObjectDataByQuery($this);
|
||||
}
|
||||
return $this->objectManager->get(\TYPO3\CMS\Extbase\Persistence\QueryResultInterface::class, $this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the property names to order the result by. Expected like this:
|
||||
* array(
|
||||
* 'foo' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_ASCENDING,
|
||||
* 'bar' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_DESCENDING
|
||||
* )
|
||||
* where 'foo' and 'bar' are property names.
|
||||
*
|
||||
* @param array $orderings The property names to order by
|
||||
* @return QueryInterface
|
||||
*/
|
||||
public function setOrderings(array $orderings)
|
||||
{
|
||||
$this->orderings = $orderings;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the property names to order the result by. Like this:
|
||||
* array(
|
||||
* 'foo' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_ASCENDING,
|
||||
* 'bar' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_DESCENDING
|
||||
* )
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getOrderings()
|
||||
{
|
||||
return $this->orderings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum size of the result set to limit. Returns $this to allow
|
||||
* for chaining (fluid interface)
|
||||
*
|
||||
* @param int $limit
|
||||
* @throws \InvalidArgumentException
|
||||
* @return QueryInterface
|
||||
*/
|
||||
public function setLimit($limit)
|
||||
{
|
||||
if (!is_int($limit) || $limit < 1) {
|
||||
throw new \InvalidArgumentException('The limit must be an integer >= 1', 1245071870);
|
||||
}
|
||||
$this->limit = $limit;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets a previously set maximum size of the result set. Returns $this to allow
|
||||
* for chaining (fluid interface)
|
||||
*
|
||||
* @return QueryInterface
|
||||
*/
|
||||
public function unsetLimit()
|
||||
{
|
||||
unset($this->limit);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum size of the result set to limit.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getLimit()
|
||||
{
|
||||
return $this->limit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the start offset of the result set to offset. Returns $this to
|
||||
* allow for chaining (fluid interface)
|
||||
*
|
||||
* @param int $offset
|
||||
* @throws \InvalidArgumentException
|
||||
* @return QueryInterface
|
||||
*/
|
||||
public function setOffset($offset)
|
||||
{
|
||||
if (!is_int($offset) || $offset < 0) {
|
||||
throw new \InvalidArgumentException('The offset must be a positive integer', 1245071872);
|
||||
}
|
||||
$this->offset = $offset;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the start offset of the result set.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getOffset()
|
||||
{
|
||||
return $this->offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* The constraint used to limit the result set. Returns $this to allow
|
||||
* for chaining (fluid interface)
|
||||
*
|
||||
* @param \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ConstraintInterface $constraint
|
||||
* @return QueryInterface
|
||||
*/
|
||||
public function matching($constraint)
|
||||
{
|
||||
$this->constraint = $constraint;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the statement of this query. If you use this, you will lose the abstraction from a concrete storage
|
||||
* backend (database).
|
||||
*
|
||||
* @param string|\TYPO3\CMS\Core\Database\Query\QueryBuilder|\Doctrine\DBAL\Statement $statement The statement
|
||||
* @param array $parameters An array of parameters. These will be bound to placeholders '?' in the $statement.
|
||||
* @return QueryInterface
|
||||
*/
|
||||
public function statement($statement, array $parameters = [])
|
||||
{
|
||||
$this->statement = $this->qomFactory->statement($statement, $parameters);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the statement of this query.
|
||||
*
|
||||
* @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\Statement
|
||||
*/
|
||||
public function getStatement()
|
||||
{
|
||||
return $this->statement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the constraint for this query.
|
||||
*
|
||||
* @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ConstraintInterface|null the constraint, or null if none
|
||||
*/
|
||||
public function getConstraint()
|
||||
{
|
||||
return $this->constraint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a logical conjunction of the given constraints. The method takes one or more constraints and concatenates them with a boolean AND.
|
||||
* It also accepts a single array of constraints to be concatenated.
|
||||
*
|
||||
* @param mixed $constraint1 The first of multiple constraints or an array of constraints.
|
||||
* @throws Exception\InvalidNumberOfConstraintsException
|
||||
* @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\AndInterface
|
||||
*/
|
||||
public function logicalAnd($constraint1)
|
||||
{
|
||||
if (is_array($constraint1)) {
|
||||
$resultingConstraint = array_shift($constraint1);
|
||||
$constraints = $constraint1;
|
||||
} else {
|
||||
$constraints = func_get_args();
|
||||
$resultingConstraint = array_shift($constraints);
|
||||
}
|
||||
if ($resultingConstraint === null) {
|
||||
throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception\InvalidNumberOfConstraintsException('There must be at least one constraint or a non-empty array of constraints given.', 1268056288);
|
||||
}
|
||||
foreach ($constraints as $constraint) {
|
||||
$resultingConstraint = $this->qomFactory->_and($resultingConstraint, $constraint);
|
||||
}
|
||||
return $resultingConstraint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a logical disjunction of the two given constraints
|
||||
*
|
||||
* @param mixed $constraint1 The first of multiple constraints or an array of constraints.
|
||||
* @throws Exception\InvalidNumberOfConstraintsException
|
||||
* @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\OrInterface
|
||||
*/
|
||||
public function logicalOr($constraint1)
|
||||
{
|
||||
if (is_array($constraint1)) {
|
||||
$resultingConstraint = array_shift($constraint1);
|
||||
$constraints = $constraint1;
|
||||
} else {
|
||||
$constraints = func_get_args();
|
||||
$resultingConstraint = array_shift($constraints);
|
||||
}
|
||||
if ($resultingConstraint === null) {
|
||||
throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception\InvalidNumberOfConstraintsException('There must be at least one constraint or a non-empty array of constraints given.', 1268056289);
|
||||
}
|
||||
foreach ($constraints as $constraint) {
|
||||
$resultingConstraint = $this->qomFactory->_or($resultingConstraint, $constraint);
|
||||
}
|
||||
return $resultingConstraint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a logical negation of the given constraint
|
||||
*
|
||||
* @param \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ConstraintInterface $constraint Constraint to negate
|
||||
* @throws \RuntimeException
|
||||
* @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\NotInterface
|
||||
*/
|
||||
public function logicalNot(\TYPO3\CMS\Extbase\Persistence\Generic\Qom\ConstraintInterface $constraint)
|
||||
{
|
||||
return $this->qomFactory->not($constraint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an equals criterion used for matching objects against a query
|
||||
*
|
||||
* @param string $propertyName The name of the property to compare against
|
||||
* @param mixed $operand The value to compare with
|
||||
* @param bool $caseSensitive Whether the equality test should be done case-sensitive
|
||||
* @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
|
||||
*/
|
||||
public function equals($propertyName, $operand, $caseSensitive = true)
|
||||
{
|
||||
if (is_object($operand) || $caseSensitive) {
|
||||
$comparison = $this->qomFactory->comparison(
|
||||
$this->qomFactory->propertyValue($propertyName, $this->getSelectorName()),
|
||||
QueryInterface::OPERATOR_EQUAL_TO,
|
||||
$operand
|
||||
);
|
||||
} else {
|
||||
$comparison = $this->qomFactory->comparison(
|
||||
$this->qomFactory->lowerCase($this->qomFactory->propertyValue($propertyName, $this->getSelectorName())),
|
||||
QueryInterface::OPERATOR_EQUAL_TO,
|
||||
mb_strtolower($operand, \TYPO3\CMS\Extbase\Persistence\Generic\Query::CHARSET)
|
||||
);
|
||||
}
|
||||
return $comparison;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a like criterion used for matching objects against a query
|
||||
*
|
||||
* @param string $propertyName The name of the property to compare against
|
||||
* @param mixed $operand The value to compare with
|
||||
* @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
|
||||
*/
|
||||
public function like($propertyName, $operand)
|
||||
{
|
||||
return $this->qomFactory->comparison(
|
||||
$this->qomFactory->propertyValue($propertyName, $this->getSelectorName()),
|
||||
QueryInterface::OPERATOR_LIKE,
|
||||
$operand
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a "contains" criterion used for matching objects against a query.
|
||||
* It matches if the multivalued property contains the given operand.
|
||||
*
|
||||
* @param string $propertyName The name of the (multivalued) property to compare against
|
||||
* @param mixed $operand The value to compare with
|
||||
* @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
|
||||
*/
|
||||
public function contains($propertyName, $operand)
|
||||
{
|
||||
return $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), QueryInterface::OPERATOR_CONTAINS, $operand);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an "in" criterion used for matching objects against a query. It
|
||||
* matches if the property's value is contained in the multivalued operand.
|
||||
*
|
||||
* @param string $propertyName The name of the property to compare against
|
||||
* @param mixed $operand The value to compare with, multivalued
|
||||
* @throws Exception\UnexpectedTypeException
|
||||
* @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
|
||||
*/
|
||||
public function in($propertyName, $operand)
|
||||
{
|
||||
if (!\TYPO3\CMS\Extbase\Utility\TypeHandlingUtility::isValidTypeForMultiValueComparison($operand)) {
|
||||
throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception\UnexpectedTypeException('The "in" operator must be given a multivalued operand (array, ArrayAccess, Traversable).', 1264678095);
|
||||
}
|
||||
return $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), QueryInterface::OPERATOR_IN, $operand);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a less than criterion used for matching objects against a query
|
||||
*
|
||||
* @param string $propertyName The name of the property to compare against
|
||||
* @param mixed $operand The value to compare with
|
||||
* @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
|
||||
*/
|
||||
public function lessThan($propertyName, $operand)
|
||||
{
|
||||
return $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), QueryInterface::OPERATOR_LESS_THAN, $operand);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a less or equal than criterion used for matching objects against a query
|
||||
*
|
||||
* @param string $propertyName The name of the property to compare against
|
||||
* @param mixed $operand The value to compare with
|
||||
* @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
|
||||
*/
|
||||
public function lessThanOrEqual($propertyName, $operand)
|
||||
{
|
||||
return $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), QueryInterface::OPERATOR_LESS_THAN_OR_EQUAL_TO, $operand);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a greater than criterion used for matching objects against a query
|
||||
*
|
||||
* @param string $propertyName The name of the property to compare against
|
||||
* @param mixed $operand The value to compare with
|
||||
* @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
|
||||
*/
|
||||
public function greaterThan($propertyName, $operand)
|
||||
{
|
||||
return $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), QueryInterface::OPERATOR_GREATER_THAN, $operand);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a greater than or equal criterion used for matching objects against a query
|
||||
*
|
||||
* @param string $propertyName The name of the property to compare against
|
||||
* @param mixed $operand The value to compare with
|
||||
* @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
|
||||
*/
|
||||
public function greaterThanOrEqual($propertyName, $operand)
|
||||
{
|
||||
return $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), QueryInterface::OPERATOR_GREATER_THAN_OR_EQUAL_TO, $operand);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a greater than or equal criterion used for matching objects against a query
|
||||
*
|
||||
* @param string $propertyName The name of the property to compare against
|
||||
* @param mixed $operandLower The value of the lower boundary to compare against
|
||||
* @param mixed $operandUpper The value of the upper boundary to compare against
|
||||
* @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\AndInterface
|
||||
* @throws \TYPO3\CMS\Extbase\Persistence\Generic\Exception\InvalidNumberOfConstraintsException
|
||||
*/
|
||||
public function between($propertyName, $operandLower, $operandUpper)
|
||||
{
|
||||
return $this->logicalAnd(
|
||||
$this->greaterThanOrEqual($propertyName, $operandLower),
|
||||
$this->lessThanOrEqual($propertyName, $operandUpper)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal only to be used within Extbase, not part of TYPO3 Core API.
|
||||
*/
|
||||
public function __wakeup()
|
||||
{
|
||||
$this->objectManager = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\Object\ObjectManager::class);
|
||||
$this->persistenceManager = $this->objectManager->get(\TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface::class);
|
||||
$this->dataMapFactory = $this->objectManager->get(\TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapFactory::class);
|
||||
$this->qomFactory = $this->objectManager->get(\TYPO3\CMS\Extbase\Persistence\Generic\Qom\QueryObjectModelFactory::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @internal only to be used within Extbase, not part of TYPO3 Core API.
|
||||
*/
|
||||
public function __sleep()
|
||||
{
|
||||
return ['type', 'source', 'constraint', 'statement', 'orderings', 'limit', 'offset', 'querySettings'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the query result count.
|
||||
*
|
||||
* @return int The query result count
|
||||
*/
|
||||
public function count()
|
||||
{
|
||||
return $this->execute()->count();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an "isEmpty" criterion used for matching objects against a query.
|
||||
* It matches if the multivalued property contains no values or is NULL.
|
||||
*
|
||||
* @param string $propertyName The name of the multivalued property to compare against
|
||||
* @throws Exception\NotImplementedException
|
||||
*/
|
||||
public function isEmpty($propertyName)
|
||||
{
|
||||
throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception\NotImplementedException(__METHOD__, 1476122265);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* The QueryFactory used to create queries against the storage backend
|
||||
* @internal only to be used within Extbase, not part of TYPO3 Core API.
|
||||
*/
|
||||
class QueryFactory implements QueryFactoryInterface, \TYPO3\CMS\Core\SingletonInterface
|
||||
{
|
||||
/**
|
||||
* @var \TYPO3\CMS\Extbase\Object\ObjectManagerInterface
|
||||
*/
|
||||
protected $objectManager;
|
||||
|
||||
/**
|
||||
* @var \TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface
|
||||
*/
|
||||
protected $configurationManager;
|
||||
|
||||
/**
|
||||
* @var \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapFactory
|
||||
*/
|
||||
protected $dataMapFactory;
|
||||
|
||||
/**
|
||||
* @param \TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager
|
||||
*/
|
||||
public function injectObjectManager(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager)
|
||||
{
|
||||
$this->objectManager = $objectManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface $configurationManager
|
||||
*/
|
||||
public function injectConfigurationManager(\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface $configurationManager)
|
||||
{
|
||||
$this->configurationManager = $configurationManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapFactory $dataMapFactory
|
||||
*/
|
||||
public function injectDataMapFactory(\TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapFactory $dataMapFactory)
|
||||
{
|
||||
$this->dataMapFactory = $dataMapFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a query object working on the given class name
|
||||
*
|
||||
* @param string $className The class name
|
||||
* @return \TYPO3\CMS\Extbase\Persistence\QueryInterface
|
||||
* @throws \TYPO3\CMS\Extbase\Persistence\Generic\Exception
|
||||
*/
|
||||
public function create($className)
|
||||
{
|
||||
$query = $this->objectManager->get(\TYPO3\CMS\Extbase\Persistence\QueryInterface::class, $className);
|
||||
$querySettings = $this->objectManager->get(\TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface::class);
|
||||
|
||||
$dataMap = $this->dataMapFactory->buildDataMap($className);
|
||||
if ($dataMap->getIsStatic() || $dataMap->getRootLevel()) {
|
||||
$querySettings->setRespectStoragePage(false);
|
||||
}
|
||||
|
||||
$frameworkConfiguration = $this->configurationManager->getConfiguration(\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK);
|
||||
$querySettings->setStoragePageIds(\TYPO3\CMS\Core\Utility\GeneralUtility::intExplode(',', $frameworkConfiguration['persistence']['storagePid'] ?? ''));
|
||||
$query->setQuerySettings($querySettings);
|
||||
return $query;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* A persistence query factory interface
|
||||
*/
|
||||
interface QueryFactoryInterface
|
||||
{
|
||||
/**
|
||||
* Creates a query object working on the given class name
|
||||
*
|
||||
* @param string $className The class name
|
||||
* @return \TYPO3\CMS\Extbase\Persistence\QueryInterface
|
||||
*/
|
||||
public function create($className);
|
||||
}
|
||||
@@ -0,0 +1,280 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
use TYPO3\CMS\Extbase\Object\ObjectManagerInterface;
|
||||
use TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapper;
|
||||
use TYPO3\CMS\Extbase\Persistence\QueryResultInterface;
|
||||
|
||||
/**
|
||||
* A lazy result list that is returned by Query::execute()
|
||||
*/
|
||||
class QueryResult implements QueryResultInterface
|
||||
{
|
||||
/**
|
||||
* @var \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapper
|
||||
*/
|
||||
protected $dataMapper;
|
||||
|
||||
/**
|
||||
* @var \TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface
|
||||
*/
|
||||
protected $persistenceManager;
|
||||
|
||||
/**
|
||||
* @var int|null
|
||||
*/
|
||||
protected $numberOfResults;
|
||||
|
||||
/**
|
||||
* @var \TYPO3\CMS\Extbase\Persistence\QueryInterface
|
||||
*/
|
||||
protected $query;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $queryResult;
|
||||
|
||||
/**
|
||||
* @var ObjectManagerInterface
|
||||
*/
|
||||
protected $objectManager;
|
||||
|
||||
/**
|
||||
* @param ObjectManagerInterface $objectManager
|
||||
*/
|
||||
public function injectObjectManager(ObjectManagerInterface $objectManager)
|
||||
{
|
||||
$this->objectManager = $objectManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface $persistenceManager
|
||||
*/
|
||||
public function injectPersistenceManager(\TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface $persistenceManager)
|
||||
{
|
||||
$this->persistenceManager = $persistenceManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param \TYPO3\CMS\Extbase\Persistence\QueryInterface $query
|
||||
*/
|
||||
public function __construct(\TYPO3\CMS\Extbase\Persistence\QueryInterface $query)
|
||||
{
|
||||
$this->query = $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Object initialization called when object is created with ObjectManager, after constructor
|
||||
*/
|
||||
public function initializeObject()
|
||||
{
|
||||
$this->dataMapper = $this->objectManager->get(DataMapper::class, $this->query);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the objects this QueryResult is supposed to hold
|
||||
*/
|
||||
protected function initialize()
|
||||
{
|
||||
if (!is_array($this->queryResult)) {
|
||||
$this->queryResult = $this->dataMapper->map($this->query->getType(), $this->persistenceManager->getObjectDataByQuery($this->query));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a clone of the query object
|
||||
*
|
||||
* @return \TYPO3\CMS\Extbase\Persistence\QueryInterface
|
||||
*/
|
||||
public function getQuery()
|
||||
{
|
||||
return clone $this->query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first object in the result set
|
||||
*
|
||||
* @return object
|
||||
*/
|
||||
public function getFirst()
|
||||
{
|
||||
if (is_array($this->queryResult)) {
|
||||
$queryResult = $this->queryResult;
|
||||
reset($queryResult);
|
||||
} else {
|
||||
$query = $this->getQuery();
|
||||
$query->setLimit(1);
|
||||
$queryResult = $this->dataMapper->map($query->getType(), $this->persistenceManager->getObjectDataByQuery($query));
|
||||
}
|
||||
$firstResult = current($queryResult);
|
||||
if ($firstResult === false) {
|
||||
$firstResult = null;
|
||||
}
|
||||
return $firstResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of objects in the result
|
||||
*
|
||||
* @return int The number of matching objects
|
||||
*/
|
||||
public function count()
|
||||
{
|
||||
if ($this->numberOfResults === null) {
|
||||
if (is_array($this->queryResult)) {
|
||||
$this->numberOfResults = count($this->queryResult);
|
||||
} else {
|
||||
$this->numberOfResults = $this->persistenceManager->getObjectCountByQuery($this->query);
|
||||
}
|
||||
}
|
||||
return $this->numberOfResults;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array with the objects in the result set
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function toArray()
|
||||
{
|
||||
$this->initialize();
|
||||
return iterator_to_array($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is needed to implement the ArrayAccess interface,
|
||||
* but it isn't very useful as the offset has to be an integer
|
||||
*
|
||||
* @param mixed $offset
|
||||
* @return bool
|
||||
* @see ArrayAccess::offsetExists()
|
||||
*/
|
||||
public function offsetExists($offset)
|
||||
{
|
||||
$this->initialize();
|
||||
return isset($this->queryResult[$offset]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $offset
|
||||
* @return mixed
|
||||
* @see ArrayAccess::offsetGet()
|
||||
*/
|
||||
public function offsetGet($offset)
|
||||
{
|
||||
$this->initialize();
|
||||
return $this->queryResult[$offset] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method has no effect on the persisted objects but only on the result set
|
||||
*
|
||||
* @param mixed $offset
|
||||
* @param mixed $value
|
||||
* @see ArrayAccess::offsetSet()
|
||||
*/
|
||||
public function offsetSet($offset, $value)
|
||||
{
|
||||
$this->initialize();
|
||||
$this->numberOfResults = null;
|
||||
$this->queryResult[$offset] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method has no effect on the persisted objects but only on the result set
|
||||
*
|
||||
* @param mixed $offset
|
||||
* @see ArrayAccess::offsetUnset()
|
||||
*/
|
||||
public function offsetUnset($offset)
|
||||
{
|
||||
$this->initialize();
|
||||
$this->numberOfResults = null;
|
||||
unset($this->queryResult[$offset]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
* @see Iterator::current()
|
||||
*/
|
||||
public function current()
|
||||
{
|
||||
$this->initialize();
|
||||
return current($this->queryResult);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
* @see Iterator::key()
|
||||
*/
|
||||
public function key()
|
||||
{
|
||||
$this->initialize();
|
||||
return key($this->queryResult);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Iterator::next()
|
||||
*/
|
||||
public function next()
|
||||
{
|
||||
$this->initialize();
|
||||
next($this->queryResult);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Iterator::rewind()
|
||||
*/
|
||||
public function rewind()
|
||||
{
|
||||
$this->initialize();
|
||||
reset($this->queryResult);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
* @see Iterator::valid()
|
||||
*/
|
||||
public function valid()
|
||||
{
|
||||
$this->initialize();
|
||||
return current($this->queryResult) !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the objectManager, persistenceManager and dataMapper are back when loading the QueryResult
|
||||
* from the cache
|
||||
* @internal only to be used within Extbase, not part of TYPO3 Core API.
|
||||
*/
|
||||
public function __wakeup()
|
||||
{
|
||||
$objectManager = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\Object\ObjectManager::class);
|
||||
$this->persistenceManager = $objectManager->get(\TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface::class);
|
||||
$this->dataMapper = $objectManager->get(DataMapper::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @internal only to be used within Extbase, not part of TYPO3 Core API.
|
||||
*/
|
||||
public function __sleep()
|
||||
{
|
||||
return ['query'];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* A query settings interface. This interface is NOT part of the TYPO3.Flow API.
|
||||
*/
|
||||
interface QuerySettingsInterface
|
||||
{
|
||||
/**
|
||||
* Sets the flag if the storage page should be respected for the query.
|
||||
*
|
||||
* @param bool $respectStoragePage If TRUE the storage page ID will be determined and the statement will be extended accordingly.
|
||||
* @return \TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface instance of $this to allow method chaining
|
||||
*/
|
||||
public function setRespectStoragePage($respectStoragePage);
|
||||
|
||||
/**
|
||||
* Returns the state, if the storage page should be respected for the query.
|
||||
*
|
||||
* @return bool TRUE, if the storage page should be respected; otherwise FALSE.
|
||||
*/
|
||||
public function getRespectStoragePage();
|
||||
|
||||
/**
|
||||
* Sets the pid(s) of the storage page(s) that should be respected for the query.
|
||||
*
|
||||
* @param array $storagePageIds If TRUE the storage page ID will be determined and the statement will be extended accordingly.
|
||||
* @return \TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface instance of $this to allow method chaining
|
||||
*/
|
||||
public function setStoragePageIds(array $storagePageIds);
|
||||
|
||||
/**
|
||||
* Returns the pid(s) of the storage page(s) that should be respected for the query.
|
||||
*
|
||||
* @return array list of integers that each represent a storage page id
|
||||
*/
|
||||
public function getStoragePageIds();
|
||||
|
||||
/**
|
||||
* Sets the flag if record language should be respected when querying.
|
||||
* Other settings defines whether overlay should happen or not.
|
||||
*
|
||||
* @param bool $respectSysLanguage TRUE if only record language should be respected when querying
|
||||
* @return \TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface instance of $this to allow method chaining
|
||||
*/
|
||||
public function setRespectSysLanguage($respectSysLanguage);
|
||||
|
||||
/**
|
||||
* Returns the state, if record language should be checked when querying
|
||||
*
|
||||
* @return bool if TRUE record language is checked.
|
||||
*/
|
||||
public function getRespectSysLanguage();
|
||||
|
||||
/**
|
||||
* @param mixed $languageOverlayMode TRUE, FALSE or "hideNonTranslated"
|
||||
* @return \TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface instance of $this to allow method chaining
|
||||
*/
|
||||
public function setLanguageOverlayMode($languageOverlayMode);
|
||||
|
||||
/**
|
||||
* @return mixed TRUE, FALSE or "hideNonTranslated"
|
||||
*/
|
||||
public function getLanguageOverlayMode();
|
||||
|
||||
/**
|
||||
* Language Mode is NOT used when consistentTranslationOverlayHandling is enabled
|
||||
*
|
||||
* @param string $languageMode NULL, "content_fallback", "strict" or "ignore"
|
||||
* @return \TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface instance of $this to allow method chaining
|
||||
*/
|
||||
public function setLanguageMode($languageMode);
|
||||
|
||||
/**
|
||||
* Language Mode is NOT used when consistentTranslationOverlayHandling is enabled
|
||||
*
|
||||
* @return string NULL, "content_fallback", "strict" or "ignore"
|
||||
*/
|
||||
public function getLanguageMode();
|
||||
|
||||
/**
|
||||
* @param int $languageUid
|
||||
* @return \TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface instance of $this to allow method chaining
|
||||
*/
|
||||
public function setLanguageUid($languageUid);
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getLanguageUid();
|
||||
|
||||
/**
|
||||
* Sets a flag indicating whether all or some enable fields should be ignored. If TRUE, all enable fields are ignored.
|
||||
* If--in addition to this--enableFieldsToBeIgnored is set, only fields specified there are ignored. If FALSE, all
|
||||
* enable fields are taken into account, regardless of the enableFieldsToBeIgnored setting.
|
||||
*
|
||||
* @param bool $ignoreEnableFields
|
||||
* @return \TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface instance of $this to allow method chaining
|
||||
* @see setEnableFieldsToBeIgnored()
|
||||
*/
|
||||
public function setIgnoreEnableFields($ignoreEnableFields);
|
||||
|
||||
/**
|
||||
* The returned value indicates whether all or some enable fields should be ignored.
|
||||
*
|
||||
* If TRUE, all enable fields are ignored. If--in addition to this--enableFieldsToBeIgnored is set, only fields specified there are ignored.
|
||||
* If FALSE, all enable fields are taken into account, regardless of the enableFieldsToBeIgnored setting.
|
||||
*
|
||||
* @return bool
|
||||
* @see getEnableFieldsToBeIgnored()
|
||||
*/
|
||||
public function getIgnoreEnableFields();
|
||||
|
||||
/**
|
||||
* An array of column names in the enable columns array (array keys in $GLOBALS['TCA'][$table]['ctrl']['enablecolumns']),
|
||||
* to be ignored while building the query statement. Adding a column name here effectively switches off filtering
|
||||
* by this column. This setting is only taken into account if $this->ignoreEnableFields = TRUE.
|
||||
*
|
||||
* @param array $enableFieldsToBeIgnored
|
||||
* @return \TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface instance of $this to allow method chaining
|
||||
* @see setIgnoreEnableFields()
|
||||
*/
|
||||
public function setEnableFieldsToBeIgnored($enableFieldsToBeIgnored);
|
||||
|
||||
/**
|
||||
* An array of column names in the enable columns array (array keys in $GLOBALS['TCA'][$table]['ctrl']['enablecolumns']),
|
||||
* to be ignored while building the query statement.
|
||||
*
|
||||
* @return array
|
||||
* @see getIgnoreEnableFields()
|
||||
*/
|
||||
public function getEnableFieldsToBeIgnored();
|
||||
|
||||
/**
|
||||
* Sets the flag if the query should return objects that are deleted.
|
||||
*
|
||||
* @param bool $includeDeleted
|
||||
* @return \TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface instance of $this to allow method chaining
|
||||
*/
|
||||
public function setIncludeDeleted($includeDeleted);
|
||||
|
||||
/**
|
||||
* Returns if the query should return objects that are deleted.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getIncludeDeleted();
|
||||
}
|
||||
@@ -0,0 +1,213 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
|
||||
|
||||
/**
|
||||
* The persistence session - acts as a Unit of Work for Extbase persistence framework.
|
||||
* @internal only to be used within Extbase, not part of TYPO3 Core API.
|
||||
*/
|
||||
class Session implements \TYPO3\CMS\Core\SingletonInterface
|
||||
{
|
||||
/**
|
||||
* @var \TYPO3\CMS\Extbase\Object\Container\Container
|
||||
*/
|
||||
protected $objectContainer;
|
||||
|
||||
/**
|
||||
* Reconstituted objects
|
||||
*
|
||||
* @var ObjectStorage
|
||||
*/
|
||||
protected $reconstitutedEntities;
|
||||
|
||||
/**
|
||||
* @var ObjectStorage
|
||||
*/
|
||||
protected $objectMap;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $identifierMap = [];
|
||||
|
||||
/**
|
||||
* Constructs a new Session
|
||||
*/
|
||||
public function __construct(\TYPO3\CMS\Extbase\Object\Container\Container $container)
|
||||
{
|
||||
$this->objectContainer = $container;
|
||||
$this->reconstitutedEntities = new ObjectStorage();
|
||||
$this->objectMap = new ObjectStorage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers data for a reconstituted object.
|
||||
*
|
||||
* $entityData format is described in
|
||||
* "Documentation/PersistenceFramework object data format.txt"
|
||||
*
|
||||
* @param object $entity
|
||||
*/
|
||||
public function registerReconstitutedEntity($entity)
|
||||
{
|
||||
$this->reconstitutedEntities->attach($entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace a reconstituted object, leaves the clean data unchanged.
|
||||
*
|
||||
* @param object $oldEntity
|
||||
* @param object $newEntity
|
||||
*/
|
||||
public function replaceReconstitutedEntity($oldEntity, $newEntity)
|
||||
{
|
||||
$this->reconstitutedEntities->detach($oldEntity);
|
||||
$this->reconstitutedEntities->attach($newEntity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters data for a reconstituted object
|
||||
*
|
||||
* @param object $entity
|
||||
*/
|
||||
public function unregisterReconstitutedEntity($entity)
|
||||
{
|
||||
if ($this->reconstitutedEntities->contains($entity)) {
|
||||
$this->reconstitutedEntities->detach($entity);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all objects which have been registered as reconstituted
|
||||
*
|
||||
* @return ObjectStorage All reconstituted objects
|
||||
*/
|
||||
public function getReconstitutedEntities()
|
||||
{
|
||||
return $this->reconstitutedEntities;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells whether the given object is a reconstituted entity.
|
||||
*
|
||||
* @param object $entity
|
||||
* @return bool
|
||||
*/
|
||||
public function isReconstitutedEntity($entity)
|
||||
{
|
||||
return $this->reconstitutedEntities->contains($entity);
|
||||
}
|
||||
|
||||
// @todo implement the is dirty checking behaviour of the Flow persistence session here
|
||||
|
||||
/**
|
||||
* Checks whether the given object is known to the identity map
|
||||
*
|
||||
* @param object $object
|
||||
* @return bool
|
||||
*/
|
||||
public function hasObject($object)
|
||||
{
|
||||
return $this->objectMap->contains($object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given identifier is known to the identity map
|
||||
*
|
||||
* @param string $identifier
|
||||
* @param string $className
|
||||
* @return bool
|
||||
*/
|
||||
public function hasIdentifier($identifier, $className)
|
||||
{
|
||||
return isset($this->identifierMap[$this->getClassIdentifier($className)][$identifier]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the object for the given identifier
|
||||
*
|
||||
* @param string $identifier
|
||||
* @param string $className
|
||||
* @return object
|
||||
*/
|
||||
public function getObjectByIdentifier($identifier, $className)
|
||||
{
|
||||
return $this->identifierMap[$this->getClassIdentifier($className)][$identifier];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the identifier for the given object from
|
||||
* the session, if the object was registered.
|
||||
*
|
||||
*
|
||||
* @param object $object
|
||||
* @return string
|
||||
*/
|
||||
public function getIdentifierByObject($object)
|
||||
{
|
||||
if ($this->hasObject($object)) {
|
||||
return $this->objectMap[$object];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register an identifier for an object
|
||||
*
|
||||
* @param object $object
|
||||
* @param string $identifier
|
||||
*/
|
||||
public function registerObject($object, $identifier)
|
||||
{
|
||||
$this->objectMap[$object] = $identifier;
|
||||
$this->identifierMap[$this->getClassIdentifier(get_class($object))][$identifier] = $object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister an object
|
||||
*
|
||||
* @param object $object
|
||||
*/
|
||||
public function unregisterObject($object)
|
||||
{
|
||||
unset($this->identifierMap[$this->getClassIdentifier(get_class($object))][$this->objectMap[$object]]);
|
||||
$this->objectMap->detach($object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy the state of the persistence session and reset
|
||||
* all internal data.
|
||||
*/
|
||||
public function destroy()
|
||||
{
|
||||
$this->identifierMap = [];
|
||||
$this->objectMap = new ObjectStorage();
|
||||
$this->reconstitutedEntities = new ObjectStorage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Objects are stored in the cache with their implementation class name
|
||||
* to allow reusing instances of different classes that point to the same implementation
|
||||
*
|
||||
* @param string $className
|
||||
* @return string a unique class identifier respecting configured implementation class names
|
||||
*/
|
||||
protected function getClassIdentifier($className): string
|
||||
{
|
||||
return strtolower($this->objectContainer->getImplementationClassName($className));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic\Storage;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* Storage backend interface
|
||||
*/
|
||||
interface BackendInterface
|
||||
{
|
||||
/**
|
||||
* Adds a row to the storage
|
||||
*
|
||||
* @param string $tableName The database table name
|
||||
* @param array $fieldValues The fieldValues to insert
|
||||
* @param bool $isRelation TRUE if we are currently inserting into a relation table, FALSE by default
|
||||
* @return int the UID of the inserted row
|
||||
*/
|
||||
public function addRow($tableName, array $fieldValues, $isRelation = false);
|
||||
|
||||
/**
|
||||
* Updates a row in the storage
|
||||
*
|
||||
* @param string $tableName The database table name
|
||||
* @param array $fieldValues The fieldValues to update
|
||||
* @param bool $isRelation TRUE if we are currently inserting into a relation table, FALSE by default
|
||||
* @return mixed|void
|
||||
*/
|
||||
public function updateRow($tableName, array $fieldValues, $isRelation = false);
|
||||
|
||||
/**
|
||||
* Updates a relation row in the storage
|
||||
*
|
||||
* @param string $tableName The database relation table name
|
||||
* @param array $fieldValues The fieldValues to be updated
|
||||
* @return bool
|
||||
*/
|
||||
public function updateRelationTableRow($tableName, array $fieldValues);
|
||||
|
||||
/**
|
||||
* Deletes a row in the storage
|
||||
*
|
||||
* @param string $tableName The database table name
|
||||
* @param array $where An array of where array('fieldname' => value). This array will be transformed to a WHERE clause
|
||||
* @param bool $isRelation TRUE if we are currently inserting into a relation table, FALSE by default
|
||||
* @return mixed|void
|
||||
*/
|
||||
public function removeRow($tableName, array $where, $isRelation = false);
|
||||
|
||||
/**
|
||||
* Fetches maximal value for given table column
|
||||
*
|
||||
* @param string $tableName The database table name
|
||||
* @param array $where An array of where array('fieldname' => value). This array will be transformed to a WHERE clause
|
||||
* @param string $columnName column name to get the max value from
|
||||
* @return mixed the max value
|
||||
*/
|
||||
public function getMaxValueFromTable($tableName, array $where, $columnName);
|
||||
|
||||
/**
|
||||
* Returns the number of items matching the query.
|
||||
*
|
||||
* @param \TYPO3\CMS\Extbase\Persistence\QueryInterface $query
|
||||
* @return int
|
||||
*/
|
||||
public function getObjectCountByQuery(\TYPO3\CMS\Extbase\Persistence\QueryInterface $query);
|
||||
|
||||
/**
|
||||
* Returns the object data matching the $query.
|
||||
*
|
||||
* @param \TYPO3\CMS\Extbase\Persistence\QueryInterface $query
|
||||
* @return array
|
||||
*/
|
||||
public function getObjectDataByQuery(\TYPO3\CMS\Extbase\Persistence\QueryInterface $query);
|
||||
|
||||
/**
|
||||
* Checks if a Value Object equal to the given Object exists in the data base
|
||||
*
|
||||
* @param \TYPO3\CMS\Extbase\DomainObject\AbstractValueObject $object The Value Object
|
||||
* @return mixed The matching uid if an object was found, else FALSE
|
||||
* @todo this is the last monster in this persistence series. refactor!
|
||||
*/
|
||||
public function getUidOfAlreadyPersistedValueObject(\TYPO3\CMS\Extbase\DomainObject\AbstractValueObject $object);
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic\Storage\Exception;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* An Bad Constraint exception
|
||||
*/
|
||||
class BadConstraintException extends \TYPO3\CMS\Extbase\Persistence\Generic\Exception
|
||||
{
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic\Storage\Exception;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* An SQL exception
|
||||
*/
|
||||
class SqlErrorException extends \TYPO3\CMS\Extbase\Persistence\Generic\Exception
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,815 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic\Storage;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
use Doctrine\DBAL\DBALException;
|
||||
use Doctrine\DBAL\Platforms\SQLServerPlatform;
|
||||
use TYPO3\CMS\Backend\Utility\BackendUtility;
|
||||
use TYPO3\CMS\Core\Context\Context;
|
||||
use TYPO3\CMS\Core\Context\WorkspaceAspect;
|
||||
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||
use TYPO3\CMS\Core\Database\Query\QueryBuilder;
|
||||
use TYPO3\CMS\Core\Database\Query\Restriction\FrontendRestrictionContainer;
|
||||
use TYPO3\CMS\Core\SingletonInterface;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Core\Utility\MathUtility;
|
||||
use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
|
||||
use TYPO3\CMS\Extbase\DomainObject\AbstractValueObject;
|
||||
use TYPO3\CMS\Extbase\Object\ObjectManagerInterface;
|
||||
use TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapper;
|
||||
use TYPO3\CMS\Extbase\Persistence\Generic\Qom;
|
||||
use TYPO3\CMS\Extbase\Persistence\Generic\Query;
|
||||
use TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface;
|
||||
use TYPO3\CMS\Extbase\Persistence\Generic\Storage\Exception\BadConstraintException;
|
||||
use TYPO3\CMS\Extbase\Persistence\Generic\Storage\Exception\SqlErrorException;
|
||||
use TYPO3\CMS\Extbase\Persistence\QueryInterface;
|
||||
use TYPO3\CMS\Extbase\Service\CacheService;
|
||||
use TYPO3\CMS\Extbase\Service\EnvironmentService;
|
||||
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
|
||||
use TYPO3\CMS\Frontend\Page\PageRepository;
|
||||
|
||||
/**
|
||||
* A Storage backend
|
||||
* @internal only to be used within Extbase, not part of TYPO3 Core API.
|
||||
*/
|
||||
class Typo3DbBackend implements BackendInterface, SingletonInterface
|
||||
{
|
||||
/**
|
||||
* @var ConnectionPool
|
||||
*/
|
||||
protected $connectionPool;
|
||||
|
||||
/**
|
||||
* @var ConfigurationManagerInterface
|
||||
*/
|
||||
protected $configurationManager;
|
||||
|
||||
/**
|
||||
* @var CacheService
|
||||
*/
|
||||
protected $cacheService;
|
||||
|
||||
/**
|
||||
* @var EnvironmentService
|
||||
*/
|
||||
protected $environmentService;
|
||||
|
||||
/**
|
||||
* @var ObjectManagerInterface
|
||||
*/
|
||||
protected $objectManager;
|
||||
|
||||
/**
|
||||
* As determining the table columns is a costly operation this is done only once per table during runtime and cached then
|
||||
*
|
||||
* @var array
|
||||
* @see clearPageCache()
|
||||
*/
|
||||
protected $hasPidColumn = [];
|
||||
|
||||
/**
|
||||
* @param ConfigurationManagerInterface $configurationManager
|
||||
*/
|
||||
public function injectConfigurationManager(ConfigurationManagerInterface $configurationManager)
|
||||
{
|
||||
$this->configurationManager = $configurationManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param CacheService $cacheService
|
||||
*/
|
||||
public function injectCacheService(CacheService $cacheService)
|
||||
{
|
||||
$this->cacheService = $cacheService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param EnvironmentService $environmentService
|
||||
*/
|
||||
public function injectEnvironmentService(EnvironmentService $environmentService)
|
||||
{
|
||||
$this->environmentService = $environmentService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ObjectManagerInterface $objectManager
|
||||
*/
|
||||
public function injectObjectManager(ObjectManagerInterface $objectManager)
|
||||
{
|
||||
$this->objectManager = $objectManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a row to the storage
|
||||
*
|
||||
* @param string $tableName The database table name
|
||||
* @param array $fieldValues The row to be inserted
|
||||
* @param bool $isRelation TRUE if we are currently inserting into a relation table, FALSE by default
|
||||
* @return int The uid of the inserted row
|
||||
* @throws SqlErrorException
|
||||
*/
|
||||
public function addRow($tableName, array $fieldValues, $isRelation = false)
|
||||
{
|
||||
if (isset($fieldValues['uid'])) {
|
||||
unset($fieldValues['uid']);
|
||||
}
|
||||
try {
|
||||
$connection = $this->connectionPool->getConnectionForTable($tableName);
|
||||
|
||||
$types = [];
|
||||
$platform = $connection->getDatabasePlatform();
|
||||
if ($platform instanceof SQLServerPlatform) {
|
||||
// mssql needs to set proper PARAM_LOB and others to update fields
|
||||
$tableDetails = $connection->getSchemaManager()->listTableDetails($tableName);
|
||||
foreach ($fieldValues as $columnName => $columnValue) {
|
||||
$types[$columnName] = $tableDetails->getColumn($columnName)->getType()->getBindingType();
|
||||
}
|
||||
}
|
||||
|
||||
$connection->insert($tableName, $fieldValues, $types);
|
||||
} catch (DBALException $e) {
|
||||
throw new SqlErrorException($e->getPrevious()->getMessage(), 1470230766, $e);
|
||||
}
|
||||
|
||||
$uid = 0;
|
||||
if (!$isRelation) {
|
||||
// Relation tables have no auto_increment column, so no retrieval must be tried.
|
||||
$uid = $connection->lastInsertId($tableName);
|
||||
$this->clearPageCache($tableName, $uid);
|
||||
}
|
||||
return (int)$uid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a row in the storage
|
||||
*
|
||||
* @param string $tableName The database table name
|
||||
* @param array $fieldValues The row to be updated
|
||||
* @param bool $isRelation TRUE if we are currently inserting into a relation table, FALSE by default
|
||||
* @return bool
|
||||
* @throws \InvalidArgumentException
|
||||
* @throws SqlErrorException
|
||||
*/
|
||||
public function updateRow($tableName, array $fieldValues, $isRelation = false)
|
||||
{
|
||||
if (!isset($fieldValues['uid'])) {
|
||||
throw new \InvalidArgumentException('The given row must contain a value for "uid".', 1476045164);
|
||||
}
|
||||
|
||||
$uid = (int)$fieldValues['uid'];
|
||||
unset($fieldValues['uid']);
|
||||
|
||||
try {
|
||||
$connection = $this->connectionPool->getConnectionForTable($tableName);
|
||||
|
||||
$types = [];
|
||||
$platform = $connection->getDatabasePlatform();
|
||||
if ($platform instanceof SQLServerPlatform) {
|
||||
// mssql needs to set proper PARAM_LOB and others to update fields
|
||||
$tableDetails = $connection->getSchemaManager()->listTableDetails($tableName);
|
||||
foreach ($fieldValues as $columnName => $columnValue) {
|
||||
$types[$columnName] = $tableDetails->getColumn($columnName)->getType()->getBindingType();
|
||||
}
|
||||
}
|
||||
|
||||
$connection->update($tableName, $fieldValues, ['uid' => $uid], $types);
|
||||
} catch (DBALException $e) {
|
||||
throw new SqlErrorException($e->getPrevious()->getMessage(), 1470230767, $e);
|
||||
}
|
||||
|
||||
if (!$isRelation) {
|
||||
$this->clearPageCache($tableName, $uid);
|
||||
}
|
||||
|
||||
// always returns true
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a relation row in the storage.
|
||||
*
|
||||
* @param string $tableName The database relation table name
|
||||
* @param array $fieldValues The row to be updated
|
||||
* @return bool
|
||||
* @throws SqlErrorException
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function updateRelationTableRow($tableName, array $fieldValues)
|
||||
{
|
||||
if (!isset($fieldValues['uid_local']) && !isset($fieldValues['uid_foreign'])) {
|
||||
throw new \InvalidArgumentException(
|
||||
'The given fieldValues must contain a value for "uid_local" and "uid_foreign".',
|
||||
1360500126
|
||||
);
|
||||
}
|
||||
|
||||
$where['uid_local'] = (int)$fieldValues['uid_local'];
|
||||
$where['uid_foreign'] = (int)$fieldValues['uid_foreign'];
|
||||
unset($fieldValues['uid_local']);
|
||||
unset($fieldValues['uid_foreign']);
|
||||
|
||||
if (!empty($fieldValues['tablenames'])) {
|
||||
$where['tablenames'] = $fieldValues['tablenames'];
|
||||
unset($fieldValues['tablenames']);
|
||||
}
|
||||
if (!empty($fieldValues['fieldname'])) {
|
||||
$where['fieldname'] = $fieldValues['fieldname'];
|
||||
unset($fieldValues['fieldname']);
|
||||
}
|
||||
|
||||
try {
|
||||
$this->connectionPool->getConnectionForTable($tableName)->update($tableName, $fieldValues, $where);
|
||||
} catch (DBALException $e) {
|
||||
throw new SqlErrorException($e->getPrevious()->getMessage(), 1470230768, $e);
|
||||
}
|
||||
|
||||
// always returns true
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a row in the storage
|
||||
*
|
||||
* @param string $tableName The database table name
|
||||
* @param array $where An array of where array('fieldname' => value).
|
||||
* @param bool $isRelation TRUE if we are currently manipulating a relation table, FALSE by default
|
||||
* @return bool
|
||||
* @throws SqlErrorException
|
||||
*/
|
||||
public function removeRow($tableName, array $where, $isRelation = false)
|
||||
{
|
||||
try {
|
||||
$this->connectionPool->getConnectionForTable($tableName)->delete($tableName, $where);
|
||||
} catch (DBALException $e) {
|
||||
throw new SqlErrorException($e->getPrevious()->getMessage(), 1470230769, $e);
|
||||
}
|
||||
|
||||
if (!$isRelation && isset($where['uid'])) {
|
||||
$this->clearPageCache($tableName, $where['uid']);
|
||||
}
|
||||
|
||||
// always returns true
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches maximal value for given table column from database.
|
||||
*
|
||||
* @param string $tableName The database table name
|
||||
* @param array $where An array of where array('fieldname' => value).
|
||||
* @param string $columnName column name to get the max value from
|
||||
* @return mixed the max value
|
||||
* @throws SqlErrorException
|
||||
*/
|
||||
public function getMaxValueFromTable($tableName, array $where, $columnName)
|
||||
{
|
||||
try {
|
||||
$queryBuilder = $this->connectionPool->getQueryBuilderForTable($tableName);
|
||||
$queryBuilder->getRestrictions()->removeAll();
|
||||
$queryBuilder
|
||||
->select($columnName)
|
||||
->from($tableName)
|
||||
->orderBy($columnName, 'DESC')
|
||||
->setMaxResults(1);
|
||||
|
||||
foreach ($where as $fieldName => $value) {
|
||||
$queryBuilder->andWhere(
|
||||
$queryBuilder->expr()->eq($fieldName, $queryBuilder->createNamedParameter($value, \PDO::PARAM_STR))
|
||||
);
|
||||
}
|
||||
|
||||
$result = $queryBuilder->execute()->fetchColumn(0);
|
||||
} catch (DBALException $e) {
|
||||
throw new SqlErrorException($e->getPrevious()->getMessage(), 1470230770, $e);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches row data from the database
|
||||
*
|
||||
* @param string $tableName
|
||||
* @param array $where An array of where array('fieldname' => value).
|
||||
* @return array|bool
|
||||
* @throws SqlErrorException
|
||||
*/
|
||||
public function getRowByIdentifier($tableName, array $where)
|
||||
{
|
||||
try {
|
||||
$queryBuilder = $this->connectionPool->getQueryBuilderForTable($tableName);
|
||||
$queryBuilder->getRestrictions()->removeAll();
|
||||
$queryBuilder
|
||||
->select('*')
|
||||
->from($tableName);
|
||||
|
||||
foreach ($where as $fieldName => $value) {
|
||||
$queryBuilder->andWhere(
|
||||
$queryBuilder->expr()->eq($fieldName, $queryBuilder->createNamedParameter($value, \PDO::PARAM_STR))
|
||||
);
|
||||
}
|
||||
|
||||
$row = $queryBuilder->execute()->fetch();
|
||||
} catch (DBALException $e) {
|
||||
throw new SqlErrorException($e->getPrevious()->getMessage(), 1470230771, $e);
|
||||
}
|
||||
return $row ?: false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the object data matching the $query.
|
||||
*
|
||||
* @param QueryInterface $query
|
||||
* @return array
|
||||
* @throws SqlErrorException
|
||||
*/
|
||||
public function getObjectDataByQuery(QueryInterface $query)
|
||||
{
|
||||
$statement = $query->getStatement();
|
||||
if ($statement instanceof Qom\Statement
|
||||
&& !$statement->getStatement() instanceof QueryBuilder
|
||||
) {
|
||||
$rows = $this->getObjectDataByRawQuery($statement);
|
||||
} else {
|
||||
$queryParser = $this->objectManager->get(Typo3DbQueryParser::class);
|
||||
if ($statement instanceof Qom\Statement
|
||||
&& $statement->getStatement() instanceof QueryBuilder
|
||||
) {
|
||||
$queryBuilder = $statement->getStatement();
|
||||
} else {
|
||||
$queryBuilder = $queryParser->convertQueryToDoctrineQueryBuilder($query);
|
||||
}
|
||||
$selectParts = $queryBuilder->getQueryPart('select');
|
||||
if ($queryParser->isDistinctQuerySuggested() && !empty($selectParts)) {
|
||||
$selectParts[0] = 'DISTINCT ' . $selectParts[0];
|
||||
$queryBuilder->selectLiteral(...$selectParts);
|
||||
}
|
||||
if ($query->getOffset()) {
|
||||
$queryBuilder->setFirstResult($query->getOffset());
|
||||
}
|
||||
if ($query->getLimit()) {
|
||||
$queryBuilder->setMaxResults($query->getLimit());
|
||||
}
|
||||
try {
|
||||
$rows = $queryBuilder->execute()->fetchAll();
|
||||
} catch (DBALException $e) {
|
||||
throw new SqlErrorException($e->getPrevious()->getMessage(), 1472074485, $e);
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->configurationManager->isFeatureEnabled('consistentTranslationOverlayHandling') && !empty($rows)) {
|
||||
$rows = $this->overlayLanguageAndWorkspace($query->getSource(), $rows, $query);
|
||||
} else {
|
||||
$rows = $this->doLanguageAndWorkspaceOverlay($query->getSource(), $rows, $query->getQuerySettings());
|
||||
}
|
||||
|
||||
return $rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the object data using a custom statement
|
||||
*
|
||||
* @param Qom\Statement $statement
|
||||
* @return array
|
||||
* @throws SqlErrorException when the raw SQL statement fails in the database
|
||||
*/
|
||||
protected function getObjectDataByRawQuery(Qom\Statement $statement)
|
||||
{
|
||||
$realStatement = $statement->getStatement();
|
||||
$parameters = $statement->getBoundVariables();
|
||||
|
||||
// The real statement is an instance of the Doctrine DBAL QueryBuilder, so fetching
|
||||
// this directly is possible
|
||||
if ($realStatement instanceof QueryBuilder) {
|
||||
try {
|
||||
$result = $realStatement->execute();
|
||||
} catch (DBALException $e) {
|
||||
throw new SqlErrorException($e->getPrevious()->getMessage(), 1472064721, $e);
|
||||
}
|
||||
$rows = $result->fetchAll();
|
||||
} elseif ($realStatement instanceof \Doctrine\DBAL\Statement) {
|
||||
try {
|
||||
$realStatement->execute($parameters);
|
||||
} catch (DBALException $e) {
|
||||
throw new SqlErrorException($e->getPrevious()->getMessage(), 1481281404, $e);
|
||||
}
|
||||
$rows = $realStatement->fetchAll();
|
||||
} else {
|
||||
// Do a real raw query. This is very stupid, as it does not allow to use DBAL's real power if
|
||||
// several tables are on different databases, so this is used with caution and could be removed
|
||||
// in the future
|
||||
try {
|
||||
$connection = $this->connectionPool->getConnectionByName(ConnectionPool::DEFAULT_CONNECTION_NAME);
|
||||
$statement = $connection->executeQuery($realStatement, $parameters);
|
||||
} catch (DBALException $e) {
|
||||
throw new SqlErrorException($e->getPrevious()->getMessage(), 1472064775, $e);
|
||||
}
|
||||
|
||||
$rows = $statement->fetchAll();
|
||||
}
|
||||
|
||||
return $rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of tuples matching the query.
|
||||
*
|
||||
* @param QueryInterface $query
|
||||
* @return int The number of matching tuples
|
||||
* @throws BadConstraintException
|
||||
* @throws SqlErrorException
|
||||
*/
|
||||
public function getObjectCountByQuery(QueryInterface $query)
|
||||
{
|
||||
if ($query->getConstraint() instanceof Qom\Statement) {
|
||||
throw new BadConstraintException('Could not execute count on queries with a constraint of type TYPO3\\CMS\\Extbase\\Persistence\\Generic\\Qom\\Statement', 1256661045);
|
||||
}
|
||||
|
||||
$statement = $query->getStatement();
|
||||
if ($statement instanceof Qom\Statement
|
||||
&& !$statement->getStatement() instanceof QueryBuilder
|
||||
) {
|
||||
$rows = $this->getObjectDataByQuery($query);
|
||||
$count = count($rows);
|
||||
} else {
|
||||
$queryParser = $this->objectManager->get(Typo3DbQueryParser::class);
|
||||
$queryBuilder = $queryParser
|
||||
->convertQueryToDoctrineQueryBuilder($query)
|
||||
->resetQueryPart('orderBy');
|
||||
|
||||
if ($queryParser->isDistinctQuerySuggested()) {
|
||||
$source = $queryBuilder->getQueryPart('from')[0];
|
||||
// Tablename is already quoted for the DBMS, we need to treat table and field names separately
|
||||
$tableName = $source['alias'] ?: $source['table'];
|
||||
$fieldName = $queryBuilder->quoteIdentifier('uid');
|
||||
$queryBuilder->resetQueryPart('groupBy')
|
||||
->selectLiteral(sprintf('COUNT(DISTINCT %s.%s)', $tableName, $fieldName));
|
||||
} else {
|
||||
$queryBuilder->count('*');
|
||||
}
|
||||
|
||||
try {
|
||||
$count = $queryBuilder->execute()->fetchColumn(0);
|
||||
} catch (DBALException $e) {
|
||||
throw new SqlErrorException($e->getPrevious()->getMessage(), 1472074379, $e);
|
||||
}
|
||||
if ($query->getOffset()) {
|
||||
$count -= $query->getOffset();
|
||||
}
|
||||
if ($query->getLimit()) {
|
||||
$count = min($count, $query->getLimit());
|
||||
}
|
||||
}
|
||||
return (int)max(0, $count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a Value Object equal to the given Object exists in the database
|
||||
*
|
||||
* @param AbstractValueObject $object The Value Object
|
||||
* @return mixed The matching uid if an object was found, else FALSE
|
||||
* @throws SqlErrorException
|
||||
*/
|
||||
public function getUidOfAlreadyPersistedValueObject(AbstractValueObject $object)
|
||||
{
|
||||
$dataMapper = $this->objectManager->get(DataMapper::class);
|
||||
$dataMap = $dataMapper->getDataMap(get_class($object));
|
||||
$tableName = $dataMap->getTableName();
|
||||
$queryBuilder = $this->connectionPool->getQueryBuilderForTable($tableName);
|
||||
if ($this->environmentService->isEnvironmentInFrontendMode()) {
|
||||
$queryBuilder->setRestrictions(GeneralUtility::makeInstance(FrontendRestrictionContainer::class));
|
||||
}
|
||||
$whereClause = [];
|
||||
// loop over all properties of the object to exactly set the values of each database field
|
||||
$properties = $object->_getProperties();
|
||||
foreach ($properties as $propertyName => $propertyValue) {
|
||||
// @todo We couple the Backend to the Entity implementation (uid, isClone); changes there breaks this method
|
||||
if ($dataMap->isPersistableProperty($propertyName) && $propertyName !== 'uid' && $propertyName !== 'pid' && $propertyName !== 'isClone') {
|
||||
$fieldName = $dataMap->getColumnMap($propertyName)->getColumnName();
|
||||
if ($propertyValue === null) {
|
||||
$whereClause[] = $queryBuilder->expr()->isNull($fieldName);
|
||||
} else {
|
||||
$whereClause[] = $queryBuilder->expr()->eq($fieldName, $queryBuilder->createNamedParameter($dataMapper->getPlainValue($propertyValue)));
|
||||
}
|
||||
}
|
||||
}
|
||||
$queryBuilder
|
||||
->select('uid')
|
||||
->from($tableName)
|
||||
->where(...$whereClause);
|
||||
|
||||
try {
|
||||
$uid = (int)$queryBuilder
|
||||
->execute()
|
||||
->fetchColumn(0);
|
||||
if ($uid > 0) {
|
||||
return $uid;
|
||||
}
|
||||
return false;
|
||||
} catch (DBALException $e) {
|
||||
throw new SqlErrorException($e->getPrevious()->getMessage(), 1470231748, $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs workspace and language overlay on the given row array. The language and workspace id is automatically
|
||||
* detected (depending on FE or BE context). You can also explicitly set the language/workspace id.
|
||||
*
|
||||
* This method performs overlay in a legacy way (when consistentTranslationOverlayHandling flag is disabled)
|
||||
*
|
||||
* @param Qom\SourceInterface $source The source (selector od join)
|
||||
* @param array $rows
|
||||
* @param QuerySettingsInterface $querySettings The TYPO3 CMS specific query settings
|
||||
* @param int|null $workspaceUid
|
||||
* @return array
|
||||
*/
|
||||
protected function doLanguageAndWorkspaceOverlay(Qom\SourceInterface $source, array $rows, QuerySettingsInterface $querySettings, $workspaceUid = null)
|
||||
{
|
||||
if ($source instanceof Qom\SelectorInterface) {
|
||||
$tableName = $source->getSelectorName();
|
||||
} elseif ($source instanceof Qom\JoinInterface) {
|
||||
$tableName = $source->getRight()->getSelectorName();
|
||||
} else {
|
||||
// No proper source, so we do not have a table name here
|
||||
// we cannot do an overlay and return the original rows instead.
|
||||
return $rows;
|
||||
}
|
||||
|
||||
$context = $this->objectManager->get(Context::class);
|
||||
if ($workspaceUid === null) {
|
||||
$workspaceUid = $context->getPropertyFromAspect('workspace', 'id');
|
||||
} else {
|
||||
// A custom query is needed, so a custom context is cloned
|
||||
$workspaceUid = (int)$workspaceUid;
|
||||
$context = clone $context;
|
||||
$context->setAspect('workspace', $this->objectManager->get(WorkspaceAspect::class, $workspaceUid));
|
||||
}
|
||||
$pageRepository = $this->objectManager->get(PageRepository::class, $context);
|
||||
|
||||
// Fetches the move-placeholder in case it is supported
|
||||
// by the table and if there's only one row in the result set
|
||||
// (applying this to all rows does not work, since the sorting
|
||||
// order would be destroyed and possible limits not met anymore)
|
||||
if (!empty($workspaceUid)
|
||||
&& BackendUtility::isTableWorkspaceEnabled($tableName)
|
||||
&& count($rows) === 1
|
||||
) {
|
||||
$queryBuilder = $this->connectionPool->getQueryBuilderForTable($tableName);
|
||||
$queryBuilder->getRestrictions()->removeAll();
|
||||
$movePlaceholder = $queryBuilder
|
||||
->select($tableName . '.*')
|
||||
->from($tableName)
|
||||
->where(
|
||||
$queryBuilder->expr()->eq('t3ver_state', $queryBuilder->createNamedParameter(3, \PDO::PARAM_INT)),
|
||||
$queryBuilder->expr()->eq('t3ver_wsid', $queryBuilder->createNamedParameter($workspaceUid, \PDO::PARAM_INT)),
|
||||
$queryBuilder->expr()->eq('t3ver_move_id', $queryBuilder->createNamedParameter($rows[0]['uid'], \PDO::PARAM_INT))
|
||||
)
|
||||
->setMaxResults(1)
|
||||
->execute()
|
||||
->fetch();
|
||||
if (!empty($movePlaceholder)) {
|
||||
$rows = [$movePlaceholder];
|
||||
}
|
||||
}
|
||||
|
||||
$overlaidRows = [];
|
||||
foreach ($rows as $row) {
|
||||
// If current row is a translation select its parent
|
||||
if (isset($tableName) && isset($GLOBALS['TCA'][$tableName])
|
||||
&& isset($GLOBALS['TCA'][$tableName]['ctrl']['languageField'])
|
||||
&& isset($GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField'])
|
||||
&& isset($row[$GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField']])
|
||||
&& $row[$GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField']] > 0
|
||||
) {
|
||||
$queryBuilder = $this->connectionPool->getQueryBuilderForTable($tableName);
|
||||
$queryBuilder->getRestrictions()->removeAll();
|
||||
$row = $queryBuilder
|
||||
->select($tableName . '.*')
|
||||
->from($tableName)
|
||||
->where(
|
||||
$queryBuilder->expr()->eq(
|
||||
$tableName . '.uid',
|
||||
$queryBuilder->createNamedParameter(
|
||||
$row[$GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField']],
|
||||
\PDO::PARAM_INT
|
||||
)
|
||||
),
|
||||
$queryBuilder->expr()->eq(
|
||||
$tableName . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['languageField'],
|
||||
$queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)
|
||||
)
|
||||
)
|
||||
->setMaxResults(1)
|
||||
->execute()
|
||||
->fetch();
|
||||
}
|
||||
$pageRepository->versionOL($tableName, $row, true);
|
||||
if ($tableName === 'pages') {
|
||||
$row = $pageRepository->getPageOverlay($row, $querySettings->getLanguageUid());
|
||||
} elseif (isset($GLOBALS['TCA'][$tableName]['ctrl']['languageField'])
|
||||
&& $GLOBALS['TCA'][$tableName]['ctrl']['languageField'] !== ''
|
||||
&& in_array($row[$GLOBALS['TCA'][$tableName]['ctrl']['languageField']], [-1, 0])
|
||||
) {
|
||||
$overlayMode = $querySettings->getLanguageMode() === 'strict' ? 'hideNonTranslated' : '';
|
||||
$row = $pageRepository->getRecordOverlay($tableName, $row, $querySettings->getLanguageUid(), $overlayMode);
|
||||
}
|
||||
if (is_array($row)) {
|
||||
$overlaidRows[] = $row;
|
||||
}
|
||||
}
|
||||
return $overlaidRows;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs workspace and language overlay on the given row array. The language and workspace id is automatically
|
||||
* detected (depending on FE or BE context). You can also explicitly set the language/workspace id.
|
||||
*
|
||||
* @param Qom\SourceInterface $source The source (selector or join)
|
||||
* @param array $rows
|
||||
* @param QueryInterface $query
|
||||
* @param int|null $workspaceUid
|
||||
* @return array
|
||||
* @throws \TYPO3\CMS\Core\Context\Exception\AspectNotFoundException
|
||||
*/
|
||||
protected function overlayLanguageAndWorkspace(Qom\SourceInterface $source, array $rows, QueryInterface $query, int $workspaceUid = null): array
|
||||
{
|
||||
if ($source instanceof Qom\SelectorInterface) {
|
||||
$tableName = $source->getSelectorName();
|
||||
} elseif ($source instanceof Qom\JoinInterface) {
|
||||
$tableName = $source->getRight()->getSelectorName();
|
||||
} else {
|
||||
// No proper source, so we do not have a table name here
|
||||
// we cannot do an overlay and return the original rows instead.
|
||||
return $rows;
|
||||
}
|
||||
|
||||
$context = $this->objectManager->get(Context::class);
|
||||
if ($workspaceUid === null) {
|
||||
$workspaceUid = $context->getPropertyFromAspect('workspace', 'id');
|
||||
} else {
|
||||
// A custom query is needed, so a custom context is cloned
|
||||
$workspaceUid = (int)$workspaceUid;
|
||||
$context = clone $context;
|
||||
$context->setAspect('workspace', $this->objectManager->get(WorkspaceAspect::class, $workspaceUid));
|
||||
}
|
||||
$pageRepository = $this->objectManager->get(PageRepository::class, $context);
|
||||
|
||||
// Fetches the move-placeholder in case it is supported
|
||||
// by the table and if there's only one row in the result set
|
||||
// (applying this to all rows does not work, since the sorting
|
||||
// order would be destroyed and possible limits not met anymore)
|
||||
if (!empty($workspaceUid)
|
||||
&& BackendUtility::isTableWorkspaceEnabled($tableName)
|
||||
&& count($rows) === 1
|
||||
) {
|
||||
$versionId = $workspaceUid;
|
||||
$queryBuilder = $this->connectionPool->getQueryBuilderForTable($tableName);
|
||||
$queryBuilder->getRestrictions()->removeAll();
|
||||
$movePlaceholder = $queryBuilder
|
||||
->select($tableName . '.*')
|
||||
->from($tableName)
|
||||
->where(
|
||||
$queryBuilder->expr()->eq('t3ver_state', $queryBuilder->createNamedParameter(3, \PDO::PARAM_INT)),
|
||||
$queryBuilder->expr()->eq('t3ver_wsid', $queryBuilder->createNamedParameter($versionId, \PDO::PARAM_INT)),
|
||||
$queryBuilder->expr()->eq('t3ver_move_id', $queryBuilder->createNamedParameter($rows[0]['uid'], \PDO::PARAM_INT))
|
||||
)
|
||||
->setMaxResults(1)
|
||||
->execute()
|
||||
->fetchAll();
|
||||
if (!empty($movePlaceholder)) {
|
||||
$rows = $movePlaceholder;
|
||||
}
|
||||
}
|
||||
$overlaidRows = [];
|
||||
foreach ($rows as $row) {
|
||||
$pageRepository->versionOL($tableName, $row, true);
|
||||
$querySettings = $query->getQuerySettings();
|
||||
if (is_array($row) && $querySettings->getLanguageOverlayMode()) {
|
||||
if ($tableName === 'pages') {
|
||||
$row = $pageRepository->getPageOverlay($row, $querySettings->getLanguageUid());
|
||||
} else {
|
||||
$languageUid = (int)$querySettings->getLanguageUid();
|
||||
if (!$querySettings->getRespectSysLanguage()
|
||||
&& isset($row[$GLOBALS['TCA'][$tableName]['ctrl']['languageField']])
|
||||
&& $row[$GLOBALS['TCA'][$tableName]['ctrl']['languageField']] > 0
|
||||
&& (!$query instanceof Query || !$query->getParentQuery())
|
||||
) {
|
||||
//no parent query means we're processing the aggregate root.
|
||||
//respectSysLanguage is false which means that records returned by the query
|
||||
//might be from different languages (which is desired).
|
||||
//So we need to force language used for overlay to the language of the current record.
|
||||
$languageUid = $row[$GLOBALS['TCA'][$tableName]['ctrl']['languageField']];
|
||||
}
|
||||
if (isset($GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField']) && $row[$GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField']] > 0) {
|
||||
//force overlay by faking default language record, as getRecordOverlay can only handle default language records
|
||||
$row['uid'] = $row[$GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField']];
|
||||
$row[$GLOBALS['TCA'][$tableName]['ctrl']['languageField']] = 0;
|
||||
}
|
||||
$row = $pageRepository->getRecordOverlay($tableName, $row, $languageUid, (string)$querySettings->getLanguageOverlayMode());
|
||||
}
|
||||
}
|
||||
if ($row !== null && is_array($row)) {
|
||||
$overlaidRows[] = $row;
|
||||
}
|
||||
}
|
||||
return $overlaidRows;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the TYPO3 page cache for the given record.
|
||||
* If the record lies on a page, then we clear the cache of this page.
|
||||
* If the record has no PID column, we clear the cache of the current page as best-effort.
|
||||
*
|
||||
* Much of this functionality is taken from DataHandler::clear_cache() which unfortunately only works with logged-in BE user.
|
||||
*
|
||||
* @param string $tableName Table name of the record
|
||||
* @param int $uid UID of the record
|
||||
*/
|
||||
protected function clearPageCache($tableName, $uid)
|
||||
{
|
||||
$frameworkConfiguration = $this->configurationManager->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK);
|
||||
if (empty($frameworkConfiguration['persistence']['enableAutomaticCacheClearing'])) {
|
||||
return;
|
||||
}
|
||||
$pageIdsToClear = [];
|
||||
$storagePage = null;
|
||||
|
||||
// As determining the table columns is a costly operation this is done only once per table during runtime and cached then
|
||||
if (!isset($this->hasPidColumn[$tableName])) {
|
||||
$columns = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||
->getConnectionForTable($tableName)
|
||||
->getSchemaManager()
|
||||
->listTableColumns($tableName);
|
||||
$this->hasPidColumn[$tableName] = array_key_exists('pid', $columns);
|
||||
}
|
||||
|
||||
$tsfe = $this->getTSFE();
|
||||
if ($this->hasPidColumn[$tableName]) {
|
||||
$queryBuilder = $this->connectionPool->getQueryBuilderForTable($tableName);
|
||||
$queryBuilder->getRestrictions()->removeAll();
|
||||
$result = $queryBuilder
|
||||
->select('pid')
|
||||
->from($tableName)
|
||||
->where(
|
||||
$queryBuilder->expr()->eq(
|
||||
'uid',
|
||||
$queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT)
|
||||
)
|
||||
)
|
||||
->execute();
|
||||
if ($row = $result->fetch()) {
|
||||
$storagePage = $row['pid'];
|
||||
$pageIdsToClear[] = $storagePage;
|
||||
}
|
||||
} elseif (isset($tsfe)) {
|
||||
// No PID column - we can do a best-effort to clear the cache of the current page if in FE
|
||||
$storagePage = $tsfe->id;
|
||||
$pageIdsToClear[] = $storagePage;
|
||||
}
|
||||
if ($storagePage === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$pageTS = BackendUtility::getPagesTSconfig($storagePage);
|
||||
if (isset($pageTS['TCEMAIN.']['clearCacheCmd'])) {
|
||||
$clearCacheCommands = GeneralUtility::trimExplode(',', strtolower($pageTS['TCEMAIN.']['clearCacheCmd']), true);
|
||||
$clearCacheCommands = array_unique($clearCacheCommands);
|
||||
foreach ($clearCacheCommands as $clearCacheCommand) {
|
||||
if (MathUtility::canBeInterpretedAsInteger($clearCacheCommand)) {
|
||||
$pageIdsToClear[] = $clearCacheCommand;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($pageIdsToClear as $pageIdToClear) {
|
||||
$this->cacheService->getPageIdStack()->push($pageIdToClear);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TypoScriptFrontendController|null
|
||||
*/
|
||||
protected function getTSFE()
|
||||
{
|
||||
return $GLOBALS['TSFE'] ?? null;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,335 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence\Generic;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
use TYPO3\CMS\Core\Context\Context;
|
||||
use TYPO3\CMS\Core\Context\LanguageAspect;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
|
||||
use TYPO3\CMS\Extbase\Object\ObjectManager;
|
||||
use TYPO3\CMS\Extbase\Service\EnvironmentService;
|
||||
|
||||
/**
|
||||
* Query settings, reflects the settings unique to TYPO3 CMS.
|
||||
*/
|
||||
class Typo3QuerySettings implements QuerySettingsInterface
|
||||
{
|
||||
/**
|
||||
* Flag if the storage page should be respected for the query.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $respectStoragePage = true;
|
||||
|
||||
/**
|
||||
* the pid(s) of the storage page(s) that should be respected for the query.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $storagePageIds = [];
|
||||
|
||||
/**
|
||||
* A flag indicating whether all or some enable fields should be ignored. If TRUE, all enable fields are ignored.
|
||||
* If--in addition to this--enableFieldsToBeIgnored is set, only fields specified there are ignored. If FALSE, all
|
||||
* enable fields are taken into account, regardless of the enableFieldsToBeIgnored setting.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $ignoreEnableFields = false;
|
||||
|
||||
/**
|
||||
* An array of column names in the enable columns array (array keys in $GLOBALS['TCA'][$table]['ctrl']['enablecolumns']),
|
||||
* to be ignored while building the query statement
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $enableFieldsToBeIgnored = [];
|
||||
|
||||
/**
|
||||
* Flag whether deleted records should be included in the result set.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $includeDeleted = false;
|
||||
|
||||
/**
|
||||
* Flag if the sys_language_uid should be respected (default is TRUE).
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $respectSysLanguage = true;
|
||||
|
||||
/**
|
||||
* Representing sys_language_overlay only valid for current context
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
protected $languageOverlayMode = true;
|
||||
|
||||
/**
|
||||
* Language Mode is NOT used when consistentTranslationOverlayHandling is enabled
|
||||
*
|
||||
* Representing sys_language_mode only valid for current context
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $languageMode;
|
||||
|
||||
/**
|
||||
* Representing sys_language_uid only valid for current context
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $languageUid = 0;
|
||||
|
||||
/**
|
||||
* @var EnvironmentService
|
||||
*/
|
||||
protected $environmentService;
|
||||
|
||||
/**
|
||||
* @param EnvironmentService $environmentService
|
||||
*/
|
||||
public function injectEnvironmentService(EnvironmentService $environmentService)
|
||||
{
|
||||
$this->environmentService = $environmentService;
|
||||
}
|
||||
|
||||
/**
|
||||
* As long as we use a feature flag ignoreAllEnableFieldsInBe to determine the default behavior, the
|
||||
* initializeObject is responsible for handling that.
|
||||
*/
|
||||
public function initializeObject()
|
||||
{
|
||||
/** @var ObjectManager $objectManager */
|
||||
$objectManager = GeneralUtility::makeInstance(ObjectManager::class);
|
||||
/** @var ConfigurationManagerInterface $configurationManager */
|
||||
$configurationManager = $objectManager->get(ConfigurationManagerInterface::class);
|
||||
if ($this->environmentService->isEnvironmentInBackendMode() && $configurationManager->isFeatureEnabled('ignoreAllEnableFieldsInBe')) {
|
||||
$this->setIgnoreEnableFields(true);
|
||||
}
|
||||
/** @var LanguageAspect $languageAspect */
|
||||
$languageAspect = GeneralUtility::makeInstance(Context::class)->getAspect('language');
|
||||
$this->setLanguageUid($languageAspect->getContentId());
|
||||
$this->setLanguageOverlayMode(false);
|
||||
|
||||
if ($this->environmentService->isEnvironmentInFrontendMode()) {
|
||||
$overlayMode = $languageAspect->getLegacyOverlayType() === 'hideNonTranslated' ? 'hideNonTranslated' : (bool)$languageAspect->getLegacyOverlayType();
|
||||
$this->setLanguageOverlayMode($overlayMode);
|
||||
$this->setLanguageMode($languageAspect->getLegacyLanguageMode() ?: null);
|
||||
} elseif ((int)GeneralUtility::_GP('L')) {
|
||||
// Set language from 'L' parameter
|
||||
$this->setLanguageUid((int)GeneralUtility::_GP('L'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the flag if the storage page should be respected for the query.
|
||||
*
|
||||
* @param bool $respectStoragePage If TRUE the storage page ID will be determined and the statement will be extended accordingly.
|
||||
* @return QuerySettingsInterface
|
||||
*/
|
||||
public function setRespectStoragePage($respectStoragePage)
|
||||
{
|
||||
$this->respectStoragePage = $respectStoragePage;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the state, if the storage page should be respected for the query.
|
||||
*
|
||||
* @return bool TRUE, if the storage page should be respected; otherwise FALSE.
|
||||
*/
|
||||
public function getRespectStoragePage()
|
||||
{
|
||||
return $this->respectStoragePage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the pid(s) of the storage page(s) that should be respected for the query.
|
||||
*
|
||||
* @param array $storagePageIds If given the storage page IDs will be determined and the statement will be extended accordingly.
|
||||
* @return QuerySettingsInterface
|
||||
*/
|
||||
public function setStoragePageIds(array $storagePageIds)
|
||||
{
|
||||
$this->storagePageIds = $storagePageIds;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the pid(s) of the storage page(s) that should be respected for the query.
|
||||
*
|
||||
* @return array list of integers that each represent a storage page id
|
||||
*/
|
||||
public function getStoragePageIds()
|
||||
{
|
||||
return $this->storagePageIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $respectSysLanguage TRUE if TYPO3 language settings are to be applied
|
||||
* @return QuerySettingsInterface
|
||||
*/
|
||||
public function setRespectSysLanguage($respectSysLanguage)
|
||||
{
|
||||
$this->respectSysLanguage = $respectSysLanguage;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool TRUE if TYPO3 language settings are to be applied
|
||||
*/
|
||||
public function getRespectSysLanguage()
|
||||
{
|
||||
return $this->respectSysLanguage;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $languageOverlayMode TRUE, FALSE or "hideNonTranslated"
|
||||
* @return QuerySettingsInterface instance of $this to allow method chaining
|
||||
*/
|
||||
public function setLanguageOverlayMode($languageOverlayMode = false)
|
||||
{
|
||||
$this->languageOverlayMode = $languageOverlayMode;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed TRUE, FALSE or "hideNonTranslated"
|
||||
*/
|
||||
public function getLanguageOverlayMode()
|
||||
{
|
||||
return $this->languageOverlayMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Language Mode is NOT used when consistentTranslationOverlayHandling is enabled
|
||||
*
|
||||
* @param string $languageMode NULL, "content_fallback", "strict" or "ignore"
|
||||
* @return QuerySettingsInterface instance of $this to allow method chaining
|
||||
*/
|
||||
public function setLanguageMode($languageMode = '')
|
||||
{
|
||||
$this->languageMode = $languageMode;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Language Mode is NOT used when consistentTranslationOverlayHandling is enabled
|
||||
*
|
||||
* @return string NULL, "content_fallback", "strict" or "ignore"
|
||||
*/
|
||||
public function getLanguageMode()
|
||||
{
|
||||
return $this->languageMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $languageUid
|
||||
* @return QuerySettingsInterface instance of $this to allow method chaining
|
||||
*/
|
||||
public function setLanguageUid($languageUid)
|
||||
{
|
||||
$this->languageUid = $languageUid;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getLanguageUid()
|
||||
{
|
||||
return $this->languageUid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a flag indicating whether all or some enable fields should be ignored. If TRUE, all enable fields are ignored.
|
||||
* If--in addition to this--enableFieldsToBeIgnored is set, only fields specified there are ignored. If FALSE, all
|
||||
* enable fields are taken into account, regardless of the enableFieldsToBeIgnored setting.
|
||||
*
|
||||
* @param bool $ignoreEnableFields
|
||||
* @return QuerySettingsInterface
|
||||
* @see setEnableFieldsToBeIgnored()
|
||||
*/
|
||||
public function setIgnoreEnableFields($ignoreEnableFields)
|
||||
{
|
||||
$this->ignoreEnableFields = $ignoreEnableFields;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The returned value indicates whether all or some enable fields should be ignored.
|
||||
*
|
||||
* If TRUE, all enable fields are ignored. If--in addition to this--enableFieldsToBeIgnored is set, only fields specified there are ignored.
|
||||
* If FALSE, all enable fields are taken into account, regardless of the enableFieldsToBeIgnored setting.
|
||||
*
|
||||
* @return bool
|
||||
* @see getEnableFieldsToBeIgnored()
|
||||
*/
|
||||
public function getIgnoreEnableFields()
|
||||
{
|
||||
return $this->ignoreEnableFields;
|
||||
}
|
||||
|
||||
/**
|
||||
* An array of column names in the enable columns array (array keys in $GLOBALS['TCA'][$table]['ctrl']['enablecolumns']),
|
||||
* to be ignored while building the query statement. Adding a column name here effectively switches off filtering
|
||||
* by this column. This setting is only taken into account if $this->ignoreEnableFields = TRUE.
|
||||
*
|
||||
* @param array $enableFieldsToBeIgnored
|
||||
* @return QuerySettingsInterface
|
||||
* @see setIgnoreEnableFields()
|
||||
*/
|
||||
public function setEnableFieldsToBeIgnored($enableFieldsToBeIgnored)
|
||||
{
|
||||
$this->enableFieldsToBeIgnored = $enableFieldsToBeIgnored;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* An array of column names in the enable columns array (array keys in $GLOBALS['TCA'][$table]['ctrl']['enablecolumns']),
|
||||
* to be ignored while building the query statement.
|
||||
*
|
||||
* @return array
|
||||
* @see getIgnoreEnableFields()
|
||||
*/
|
||||
public function getEnableFieldsToBeIgnored()
|
||||
{
|
||||
return $this->enableFieldsToBeIgnored;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the flag if the query should return objects that are deleted.
|
||||
*
|
||||
* @param bool $includeDeleted
|
||||
* @return QuerySettingsInterface
|
||||
*/
|
||||
public function setIncludeDeleted($includeDeleted)
|
||||
{
|
||||
$this->includeDeleted = $includeDeleted;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if the query should return objects that are deleted.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getIncludeDeleted()
|
||||
{
|
||||
return $this->includeDeleted;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* An interface how to monitor changes on an object and its properties. All domain objects which should be persisted need to implement the below interface.
|
||||
*
|
||||
* @see \TYPO3\CMS\Extbase\DomainObject\AbstractEntity
|
||||
* @see \TYPO3\CMS\Extbase\DomainObject\AbstractValueObject
|
||||
*/
|
||||
interface ObjectMonitoringInterface
|
||||
{
|
||||
/**
|
||||
* Register an object's clean state, e.g. after it has been reconstituted
|
||||
* from the database
|
||||
*/
|
||||
public function _memorizeCleanState();
|
||||
|
||||
/**
|
||||
* Returns TRUE if the properties were modified after reconstitution
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function _isDirty();
|
||||
}
|
||||
@@ -0,0 +1,380 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
use TYPO3\CMS\Core\Utility\MathUtility;
|
||||
|
||||
/**
|
||||
* The storage for objects. It ensures the uniqueness of an object in the storage. It's a remake of the
|
||||
* SplObjectStorage introduced in PHP 5.3.
|
||||
*
|
||||
* Opposed to the SplObjectStorage the ObjectStorage does not implement the Serializable interface.
|
||||
*/
|
||||
class ObjectStorage implements \Countable, \Iterator, \ArrayAccess, ObjectMonitoringInterface
|
||||
{
|
||||
/**
|
||||
* This field is only needed to make debugging easier:
|
||||
* If you call current() on a class that implements Iterator, PHP will return the first field of the object
|
||||
* instead of calling the current() method of the interface.
|
||||
* We use this unusual behavior of PHP to return the warning below in this case.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $warning = 'You should never see this warning. If you do, you probably used PHP array functions like current() on the TYPO3\\CMS\\Extbase\\Persistence\\ObjectStorage. To retrieve the first result, you can use the rewind() and current() methods.';
|
||||
|
||||
/**
|
||||
* An array holding the objects and the stored information. The key of the array items ist the
|
||||
* spl_object_hash of the given object.
|
||||
*
|
||||
* array(
|
||||
* spl_object_hash =>
|
||||
* array(
|
||||
* 'obj' => $object,
|
||||
* 'inf' => $information
|
||||
* )
|
||||
* )
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $storage = [];
|
||||
|
||||
/**
|
||||
* A flag indication if the object storage was modified after reconstitution (eg. by adding a new object)
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $isModified = false;
|
||||
|
||||
/**
|
||||
* An array holding the internal position the object was added.
|
||||
* The object entry is unsetted when the object gets removed from the objectstorage
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $addedObjectsPositions = [];
|
||||
|
||||
/**
|
||||
* An array holding the internal position the object was added before, when it would
|
||||
* be removed from the objectstorage
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $removedObjectsPositions = [];
|
||||
|
||||
/**
|
||||
* An internal var holding the count of added objects to be stored as position.
|
||||
* It would be resetted, when all objects will be removed from the objectstorage
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $positionCounter = 0;
|
||||
|
||||
/**
|
||||
* Rewinds the iterator to the first storage element.
|
||||
*/
|
||||
public function rewind()
|
||||
{
|
||||
reset($this->storage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the array pointer of the storage points to a valid position.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function valid()
|
||||
{
|
||||
return current($this->storage) !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index at which the iterator currently is.
|
||||
*
|
||||
* This is different from the SplObjectStorage as the key in this implementation is the object hash (string).
|
||||
*
|
||||
* @return string The index corresponding to the position of the iterator.
|
||||
*/
|
||||
public function key()
|
||||
{
|
||||
return key($this->storage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current storage entry.
|
||||
*
|
||||
* @return object The object at the current iterator position.
|
||||
*/
|
||||
public function current()
|
||||
{
|
||||
$item = current($this->storage);
|
||||
return $item['obj'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves to the next entry.
|
||||
*/
|
||||
public function next()
|
||||
{
|
||||
next($this->storage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of objects in the storage.
|
||||
*
|
||||
* @return int The number of objects in the storage.
|
||||
*/
|
||||
public function count()
|
||||
{
|
||||
return count($this->storage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Associates data to an object in the storage. offsetSet() is an alias of attach().
|
||||
*
|
||||
* @param object $object The object to add.
|
||||
* @param mixed $information The data to associate with the object.
|
||||
*/
|
||||
public function offsetSet($object, $information)
|
||||
{
|
||||
$this->isModified = true;
|
||||
$this->storage[spl_object_hash($object)] = ['obj' => $object, 'inf' => $information];
|
||||
|
||||
$this->positionCounter++;
|
||||
$this->addedObjectsPositions[spl_object_hash($object)] = $this->positionCounter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether an object exists in the storage.
|
||||
*
|
||||
* @param object|int $value The object to look for, or the key in the storage.
|
||||
* @return bool
|
||||
*/
|
||||
public function offsetExists($value)
|
||||
{
|
||||
return is_object($value) && isset($this->storage[spl_object_hash($value)])
|
||||
|| MathUtility::canBeInterpretedAsInteger($value) && isset(array_values($this->storage)[$value]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an object from the storage. offsetUnset() is an alias of detach().
|
||||
*
|
||||
* @param object|int $value The object to remove, or its key in the storage.
|
||||
*/
|
||||
public function offsetUnset($value)
|
||||
{
|
||||
$this->isModified = true;
|
||||
|
||||
$object = $value;
|
||||
|
||||
if (MathUtility::canBeInterpretedAsInteger($value)) {
|
||||
$object = $this->offsetGet($value);
|
||||
}
|
||||
|
||||
unset($this->storage[spl_object_hash($object)]);
|
||||
|
||||
if (empty($this->storage)) {
|
||||
$this->positionCounter = 0;
|
||||
}
|
||||
|
||||
$this->removedObjectsPositions[spl_object_hash($object)] = $this->addedObjectsPositions[spl_object_hash($object)] ?? null;
|
||||
unset($this->addedObjectsPositions[spl_object_hash($object)]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the data associated with an object, or the object itself if an
|
||||
* integer is passed.
|
||||
*
|
||||
* @param object|int $value The object to look for, or its key in the storage.
|
||||
* @return mixed The data associated with an object in the storage, or the object itself if an integer is passed.
|
||||
*/
|
||||
public function offsetGet($value)
|
||||
{
|
||||
if (MathUtility::canBeInterpretedAsInteger($value)) {
|
||||
return array_values($this->storage)[$value]['obj'];
|
||||
}
|
||||
|
||||
return $this->storage[spl_object_hash($value)]['inf'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the storage contains a specific object.
|
||||
*
|
||||
* @param object $object The object to look for.
|
||||
* @return bool
|
||||
*/
|
||||
public function contains($object)
|
||||
{
|
||||
return $this->offsetExists($object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an object in the storage, and optionaly associate it to some data.
|
||||
*
|
||||
* @param object $object The object to add.
|
||||
* @param mixed $information The data to associate with the object.
|
||||
*/
|
||||
public function attach($object, $information = null)
|
||||
{
|
||||
$this->offsetSet($object, $information);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an object from the storage.
|
||||
*
|
||||
* @param object $object The object to remove.
|
||||
*/
|
||||
public function detach($object)
|
||||
{
|
||||
$this->offsetUnset($object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the data, or info, associated with the object pointed by the current iterator position.
|
||||
*
|
||||
* @return mixed The data associated with the current iterator position.
|
||||
*/
|
||||
public function getInfo()
|
||||
{
|
||||
$item = current($this->storage);
|
||||
return $item['inf'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Associates data, or info, with the object currently pointed to by the iterator.
|
||||
*
|
||||
* @param mixed $data
|
||||
*/
|
||||
public function setInfo($data)
|
||||
{
|
||||
$this->isModified = true;
|
||||
$key = key($this->storage);
|
||||
$this->storage[$key]['inf'] = $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds all objects-data pairs from a different storage in the current storage.
|
||||
*
|
||||
* @param ObjectStorage $objectStorage
|
||||
*/
|
||||
public function addAll(ObjectStorage $objectStorage)
|
||||
{
|
||||
foreach ($objectStorage as $object) {
|
||||
$this->attach($object, $objectStorage->getInfo());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes objects contained in another storage from the current storage.
|
||||
*
|
||||
* @param ObjectStorage $objectStorage The storage containing the elements to remove.
|
||||
*/
|
||||
public function removeAll(ObjectStorage $objectStorage)
|
||||
{
|
||||
foreach ($objectStorage as $object) {
|
||||
$this->detach($object);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns this object storage as an array
|
||||
*
|
||||
* @return array The object storage
|
||||
*/
|
||||
public function toArray()
|
||||
{
|
||||
$array = [];
|
||||
$storage = array_values($this->storage);
|
||||
foreach ($storage as $item) {
|
||||
$array[] = $item['obj'];
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias of toArray which allows that method to be used from contexts which support
|
||||
* for example dotted paths, e.g. ObjectAccess::getPropertyPath($object, 'children.array.123')
|
||||
* to get exactly the 123rd item in the "children" property which is an ObjectStorage.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getArray()
|
||||
{
|
||||
return $this->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Dummy method to avoid serialization.
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function serialize()
|
||||
{
|
||||
throw new \RuntimeException('An ObjectStorage instance cannot be serialized.', 1267700868);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dummy method to avoid unserialization.
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function unserialize()
|
||||
{
|
||||
throw new \RuntimeException('A ObjectStorage instance cannot be unserialized.', 1267700870);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the storage's clean state, e.g. after it has been reconstituted from the database.
|
||||
*/
|
||||
public function _memorizeCleanState()
|
||||
{
|
||||
$this->isModified = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns TRUE if the storage was modified after reconstitution.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function _isDirty()
|
||||
{
|
||||
return $this->isModified;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns TRUE if an object is added, then removed and added at a different position
|
||||
*
|
||||
* @param mixed $object
|
||||
* @return bool
|
||||
*/
|
||||
public function isRelationDirty($object)
|
||||
{
|
||||
return isset($this->addedObjectsPositions[spl_object_hash($object)])
|
||||
&& isset($this->removedObjectsPositions[spl_object_hash($object)])
|
||||
&& ($this->addedObjectsPositions[spl_object_hash($object)] !== $this->removedObjectsPositions[spl_object_hash($object)]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $object
|
||||
* @return int|null
|
||||
*/
|
||||
public function getPosition($object)
|
||||
{
|
||||
if (!isset($this->addedObjectsPositions[spl_object_hash($object)])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->addedObjectsPositions[spl_object_hash($object)];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* The Extbase Persistence Manager interface
|
||||
*/
|
||||
interface PersistenceManagerInterface
|
||||
{
|
||||
/**
|
||||
* Commits new objects and changes to objects in the current persistence
|
||||
* session into the backend
|
||||
*/
|
||||
public function persistAll();
|
||||
|
||||
/**
|
||||
* Clears the in-memory state of the persistence.
|
||||
*
|
||||
* Managed instances become detached, any fetches will
|
||||
* return data directly from the persistence "backend".
|
||||
*/
|
||||
public function clearState();
|
||||
|
||||
/**
|
||||
* Checks if the given object has ever been persisted.
|
||||
*
|
||||
* @param object $object The object to check
|
||||
* @return bool TRUE if the object is new, FALSE if the object exists in the repository
|
||||
*/
|
||||
public function isNewObject($object);
|
||||
|
||||
// @todo realign with Flow PersistenceManager again
|
||||
|
||||
/**
|
||||
* Returns the (internal) identifier for the object, if it is known to the
|
||||
* backend. Otherwise NULL is returned.
|
||||
*
|
||||
* Note: this returns an identifier even if the object has not been
|
||||
* persisted in case of AOP-managed entities. Use isNewObject() if you need
|
||||
* to distinguish those cases.
|
||||
*
|
||||
* @param object $object
|
||||
* @return mixed The identifier for the object if it is known, or NULL
|
||||
*/
|
||||
public function getIdentifierByObject($object);
|
||||
|
||||
/**
|
||||
* Returns the object with the (internal) identifier, if it is known to the
|
||||
* backend. Otherwise NULL is returned.
|
||||
*
|
||||
* @param mixed $identifier
|
||||
* @param string $objectType
|
||||
* @param bool $useLazyLoading Set to TRUE if you want to use lazy loading for this object
|
||||
* @return object The object for the identifier if it is known, or NULL
|
||||
*/
|
||||
public function getObjectByIdentifier($identifier, $objectType = null, $useLazyLoading = false);
|
||||
|
||||
/**
|
||||
* Returns the number of records matching the query.
|
||||
*
|
||||
* @param QueryInterface $query
|
||||
* @return int
|
||||
* @deprecated since Extbase 6.0, will be removed in Extbase 7.0. It is deprecated only in the interface to be more
|
||||
* in sync with Flow in future and will stay in Generic Persistence.
|
||||
*/
|
||||
public function getObjectCountByQuery(QueryInterface $query);
|
||||
|
||||
/**
|
||||
* Returns the object data matching the $query.
|
||||
*
|
||||
* @param QueryInterface $query
|
||||
* @return array
|
||||
* @deprecated since Extbase 6.0, will be removed in Extbase 7.0. It is deprecated only in the interface to be more
|
||||
* in sync with Flow in future and will stay in Generic Persistence.
|
||||
*/
|
||||
public function getObjectDataByQuery(QueryInterface $query);
|
||||
|
||||
/**
|
||||
* Registers a repository
|
||||
*
|
||||
* @param string $className The class name of the repository to be registered
|
||||
* @deprecated since Extbase 6.0, will be removed in Extbase 7.0. It is deprecated only in the interface to be more
|
||||
* in sync with Flow in future and will stay in Generic Persistence.
|
||||
*/
|
||||
public function registerRepositoryClassName($className);
|
||||
|
||||
/**
|
||||
* Adds an object to the persistence.
|
||||
*
|
||||
* @param object $object The object to add
|
||||
*/
|
||||
public function add($object);
|
||||
|
||||
/**
|
||||
* Removes an object to the persistence.
|
||||
*
|
||||
* @param object $object The object to remove
|
||||
*/
|
||||
public function remove($object);
|
||||
|
||||
/**
|
||||
* Update an object in the persistence.
|
||||
*
|
||||
* @param object $object The modified object
|
||||
* @throws \TYPO3\CMS\Extbase\Persistence\Exception\UnknownObjectException
|
||||
*/
|
||||
public function update($object);
|
||||
|
||||
/**
|
||||
* Injects the Extbase settings, called by Extbase.
|
||||
*
|
||||
* @param array $settings
|
||||
*/
|
||||
public function injectSettings(array $settings);
|
||||
|
||||
/**
|
||||
* Converts the given object into an array containing the identity of the domain object.
|
||||
*
|
||||
* @param object $object The object to be converted
|
||||
* @return array The identity array in the format array('__identity' => '...')
|
||||
* @throws \TYPO3\CMS\Extbase\Persistence\Exception\UnknownObjectException if the given object is not known to the Persistence Manager
|
||||
*/
|
||||
public function convertObjectToIdentityArray($object);
|
||||
|
||||
/**
|
||||
* Recursively iterates through the given array and turns objects
|
||||
* into arrays containing the identity of the domain object.
|
||||
*
|
||||
* @param array $array The array to be iterated over
|
||||
* @return array The modified array without objects
|
||||
* @throws \TYPO3\CMS\Extbase\Persistence\Exception\UnknownObjectException if array contains objects that are not known to the Persistence Manager
|
||||
* @see convertObjectToIdentityArray()
|
||||
*/
|
||||
public function convertObjectsToIdentityArrays(array $array);
|
||||
|
||||
/**
|
||||
* Return a query object for the given type.
|
||||
*
|
||||
* @param string $type
|
||||
* @return QueryInterface
|
||||
*/
|
||||
public function createQueryForType($type);
|
||||
}
|
||||
@@ -0,0 +1,358 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
use TYPO3\CMS\Extbase\Persistence\Generic\Qom\AndInterface;
|
||||
use TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface;
|
||||
use TYPO3\CMS\Extbase\Persistence\Generic\Qom\ConstraintInterface;
|
||||
use TYPO3\CMS\Extbase\Persistence\Generic\Qom\OrInterface;
|
||||
|
||||
/**
|
||||
* A persistence query interface
|
||||
*/
|
||||
interface QueryInterface
|
||||
{
|
||||
/**
|
||||
* The '=' comparison operator.
|
||||
*/
|
||||
const OPERATOR_EQUAL_TO = 1;
|
||||
|
||||
/**
|
||||
* For NULL we have to use 'IS' instead of '='
|
||||
*/
|
||||
const OPERATOR_EQUAL_TO_NULL = 101;
|
||||
|
||||
/**
|
||||
* The '!=' comparison operator.
|
||||
*/
|
||||
const OPERATOR_NOT_EQUAL_TO = 2;
|
||||
|
||||
/**
|
||||
* For NULL we have to use 'IS NOT' instead of '!='
|
||||
*/
|
||||
const OPERATOR_NOT_EQUAL_TO_NULL = 202;
|
||||
|
||||
/**
|
||||
* The '<' comparison operator.
|
||||
*/
|
||||
const OPERATOR_LESS_THAN = 3;
|
||||
|
||||
/**
|
||||
* The '<=' comparison operator.
|
||||
*/
|
||||
const OPERATOR_LESS_THAN_OR_EQUAL_TO = 4;
|
||||
|
||||
/**
|
||||
* The '>' comparison operator.
|
||||
*/
|
||||
const OPERATOR_GREATER_THAN = 5;
|
||||
|
||||
/**
|
||||
* The '>=' comparison operator.
|
||||
*/
|
||||
const OPERATOR_GREATER_THAN_OR_EQUAL_TO = 6;
|
||||
|
||||
/**
|
||||
* The 'like' comparison operator.
|
||||
*/
|
||||
const OPERATOR_LIKE = 7;
|
||||
|
||||
/**
|
||||
* The 'contains' comparison operator for collections.
|
||||
*/
|
||||
const OPERATOR_CONTAINS = 8;
|
||||
|
||||
/**
|
||||
* The 'in' comparison operator.
|
||||
*/
|
||||
const OPERATOR_IN = 9;
|
||||
|
||||
/**
|
||||
* The 'is NULL' comparison operator.
|
||||
*/
|
||||
const OPERATOR_IS_NULL = 10;
|
||||
|
||||
/**
|
||||
* The 'is empty' comparison operator for collections.
|
||||
*/
|
||||
const OPERATOR_IS_EMPTY = 11;
|
||||
|
||||
/**
|
||||
* Constants representing the direction when ordering result sets.
|
||||
*/
|
||||
const ORDER_ASCENDING = 'ASC';
|
||||
const ORDER_DESCENDING = 'DESC';
|
||||
|
||||
/**
|
||||
* Gets the node-tuple source for this query.
|
||||
*
|
||||
* @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\SourceInterface the node-tuple source; non-NULL
|
||||
* @deprecated since Extbase 6.0, will be removed in Extbase 7.0. It is deprecated only in the interface to be more
|
||||
* in sync with Flow in future and will stay in Generic Persistence.
|
||||
*/
|
||||
public function getSource();
|
||||
|
||||
/**
|
||||
* Executes the query and returns the result.
|
||||
*
|
||||
* @param bool $returnRawQueryResult avoids the object mapping by the persistence
|
||||
* @return \TYPO3\CMS\Extbase\Persistence\QueryResultInterface|array The query result object or an array if $returnRawQueryResult is TRUE
|
||||
*/
|
||||
public function execute($returnRawQueryResult = false);
|
||||
|
||||
/**
|
||||
* Sets the property names to order the result by. Expected like this:
|
||||
* array(
|
||||
* 'foo' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_ASCENDING,
|
||||
* 'bar' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_DESCENDING
|
||||
* )
|
||||
*
|
||||
* @param array $orderings The property names to order by
|
||||
* @return \TYPO3\CMS\Extbase\Persistence\QueryInterface
|
||||
*/
|
||||
public function setOrderings(array $orderings);
|
||||
|
||||
/**
|
||||
* Sets the maximum size of the result set to limit. Returns $this to allow
|
||||
* for chaining (fluid interface).
|
||||
*
|
||||
* @param int $limit
|
||||
* @return \TYPO3\CMS\Extbase\Persistence\QueryInterface
|
||||
*/
|
||||
public function setLimit($limit);
|
||||
|
||||
/**
|
||||
* Sets the start offset of the result set to offset. Returns $this to
|
||||
* allow for chaining (fluid interface).
|
||||
*
|
||||
* @param int $offset
|
||||
* @return \TYPO3\CMS\Extbase\Persistence\QueryInterface
|
||||
*/
|
||||
public function setOffset($offset);
|
||||
|
||||
/**
|
||||
* The constraint used to limit the result set. Returns $this to allow
|
||||
* for chaining (fluid interface).
|
||||
*
|
||||
* @param ConstraintInterface $constraint Some constraint, depending on the backend
|
||||
* @return \TYPO3\CMS\Extbase\Persistence\QueryInterface
|
||||
*/
|
||||
public function matching($constraint);
|
||||
|
||||
/**
|
||||
* Performs a logical conjunction of the two given constraints. The method
|
||||
* takes one or more constraints and concatenates them with a boolean AND.
|
||||
* It also accepts a single array of constraints to be concatenated.
|
||||
*
|
||||
* @param mixed $constraint1 The first of multiple constraints or an array of constraints.
|
||||
* @return AndInterface
|
||||
*/
|
||||
public function logicalAnd($constraint1);
|
||||
|
||||
/**
|
||||
* Performs a logical disjunction of the two given constraints. The method
|
||||
* takes one or more constraints and concatenates them with a boolean OR.
|
||||
* It also accepts a single array of constraints to be concatenated.
|
||||
*
|
||||
* @param mixed $constraint1 The first of multiple constraints or an array of constraints.
|
||||
* @return OrInterface
|
||||
*/
|
||||
public function logicalOr($constraint1);
|
||||
|
||||
/**
|
||||
* Performs a logical negation of the given constraint
|
||||
*
|
||||
* @param ConstraintInterface $constraint Constraint to negate
|
||||
* @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\NotInterface
|
||||
*/
|
||||
public function logicalNot(ConstraintInterface $constraint);
|
||||
|
||||
/**
|
||||
* Returns an equals criterion used for matching objects against a query.
|
||||
*
|
||||
* It matches if the $operand equals the value of the property named
|
||||
* $propertyName. If $operand is NULL a strict check for NULL is done. For
|
||||
* strings the comparison can be done with or without case-sensitivity.
|
||||
*
|
||||
* @param string $propertyName The name of the property to compare against
|
||||
* @param mixed $operand The value to compare with
|
||||
* @param bool $caseSensitive Whether the equality test should be done case-sensitive for strings
|
||||
* @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
|
||||
*/
|
||||
public function equals($propertyName, $operand, $caseSensitive = true);
|
||||
|
||||
/**
|
||||
* Returns a like criterion used for matching objects against a query.
|
||||
* Matches if the property named $propertyName is like the $operand, using
|
||||
* standard SQL wildcards.
|
||||
*
|
||||
* @param string $propertyName The name of the property to compare against
|
||||
* @param string $operand The value to compare with
|
||||
* @return ComparisonInterface
|
||||
* @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException if used on a non-string property
|
||||
*/
|
||||
public function like($propertyName, $operand);
|
||||
|
||||
/**
|
||||
* Returns a "contains" criterion used for matching objects against a query.
|
||||
* It matches if the multivalued property contains the given operand.
|
||||
*
|
||||
* If NULL is given as $operand, there will never be a match!
|
||||
*
|
||||
* @param string $propertyName The name of the multivalued property to compare against
|
||||
* @param mixed $operand The value to compare with
|
||||
* @return ComparisonInterface
|
||||
* @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException if used on a single-valued property
|
||||
*/
|
||||
public function contains($propertyName, $operand);
|
||||
|
||||
/**
|
||||
* Returns an "in" criterion used for matching objects against a query. It
|
||||
* matches if the property's value is contained in the multivalued operand.
|
||||
*
|
||||
* @param string $propertyName The name of the property to compare against
|
||||
* @param mixed $operand The value to compare with, multivalued
|
||||
* @return ComparisonInterface
|
||||
* @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException if used on a multi-valued property
|
||||
*/
|
||||
public function in($propertyName, $operand);
|
||||
|
||||
/**
|
||||
* Returns a less than criterion used for matching objects against a query
|
||||
*
|
||||
* @param string $propertyName The name of the property to compare against
|
||||
* @param mixed $operand The value to compare with
|
||||
* @return ComparisonInterface
|
||||
* @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException if used on a multi-valued property or with a non-literal/non-DateTime operand
|
||||
*/
|
||||
public function lessThan($propertyName, $operand);
|
||||
|
||||
/**
|
||||
* Returns a less or equal than criterion used for matching objects against a query
|
||||
*
|
||||
* @param string $propertyName The name of the property to compare against
|
||||
* @param mixed $operand The value to compare with
|
||||
* @return ComparisonInterface
|
||||
* @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException if used on a multi-valued property or with a non-literal/non-DateTime operand
|
||||
*/
|
||||
public function lessThanOrEqual($propertyName, $operand);
|
||||
|
||||
/**
|
||||
* Returns a greater than criterion used for matching objects against a query
|
||||
*
|
||||
* @param string $propertyName The name of the property to compare against
|
||||
* @param mixed $operand The value to compare with
|
||||
* @return ComparisonInterface
|
||||
* @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException if used on a multi-valued property or with a non-literal/non-DateTime operand
|
||||
*/
|
||||
public function greaterThan($propertyName, $operand);
|
||||
|
||||
/**
|
||||
* Returns a greater than or equal criterion used for matching objects against a query
|
||||
*
|
||||
* @param string $propertyName The name of the property to compare against
|
||||
* @param mixed $operand The value to compare with
|
||||
* @return ComparisonInterface
|
||||
* @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException if used on a multi-valued property or with a non-literal/non-DateTime operand
|
||||
*/
|
||||
public function greaterThanOrEqual($propertyName, $operand);
|
||||
|
||||
/**
|
||||
* Returns the type this query cares for.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType();
|
||||
|
||||
/**
|
||||
* Sets the Query Settings. These Query settings must match the settings expected by
|
||||
* the specific Storage Backend.
|
||||
*
|
||||
* @param \TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface $querySettings The Query Settings
|
||||
* @todo decide whether this can be deprecated somewhen
|
||||
*/
|
||||
public function setQuerySettings(Generic\QuerySettingsInterface $querySettings);
|
||||
|
||||
/**
|
||||
* Returns the Query Settings.
|
||||
*
|
||||
* @return \TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface $querySettings The Query Settings
|
||||
* @todo decide whether this can be deprecated eventually
|
||||
*/
|
||||
public function getQuerySettings();
|
||||
|
||||
/**
|
||||
* Returns the query result count.
|
||||
*
|
||||
* @return int The query result count
|
||||
*/
|
||||
public function count();
|
||||
|
||||
/**
|
||||
* Gets the property names to order the result by, like this:
|
||||
* array(
|
||||
* 'foo' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_ASCENDING,
|
||||
* 'bar' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_DESCENDING
|
||||
* )
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getOrderings();
|
||||
|
||||
/**
|
||||
* Returns the maximum size of the result set to limit.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getLimit();
|
||||
|
||||
/**
|
||||
* Returns the start offset of the result set.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getOffset();
|
||||
|
||||
/**
|
||||
* Gets the constraint for this query.
|
||||
*
|
||||
* @return ConstraintInterface|null the constraint, or null if none
|
||||
*/
|
||||
public function getConstraint();
|
||||
|
||||
/**
|
||||
* Returns an "isEmpty" criterion used for matching objects against a query.
|
||||
* It matches if the multivalued property contains no values or is NULL.
|
||||
*
|
||||
* @param string $propertyName The name of the multivalued property to compare against
|
||||
* @return bool
|
||||
* @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException if used on a single-valued property
|
||||
*/
|
||||
public function isEmpty($propertyName);
|
||||
|
||||
/**
|
||||
* Sets the source to fetch the result from
|
||||
*
|
||||
* @param \TYPO3\CMS\Extbase\Persistence\Generic\Qom\SourceInterface $source
|
||||
*/
|
||||
public function setSource(Generic\Qom\SourceInterface $source);
|
||||
|
||||
/**
|
||||
* Returns the statement of this query.
|
||||
*
|
||||
* @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\Statement
|
||||
*/
|
||||
public function getStatement();
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* A lazy result list that is returned by Query::execute()
|
||||
*/
|
||||
interface QueryResultInterface extends \Countable, \Iterator, \ArrayAccess
|
||||
{
|
||||
/**
|
||||
* Returns a clone of the query object
|
||||
*
|
||||
* @return \TYPO3\CMS\Extbase\Persistence\QueryInterface
|
||||
*/
|
||||
public function getQuery();
|
||||
|
||||
/**
|
||||
* Returns the first object in the result set
|
||||
*
|
||||
* @return object
|
||||
*/
|
||||
public function getFirst();
|
||||
|
||||
/**
|
||||
* Returns an array with the objects in the result set
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function toArray();
|
||||
}
|
||||
@@ -0,0 +1,251 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
use TYPO3\CMS\Core\Utility\ClassNamingUtility;
|
||||
|
||||
/**
|
||||
* The base repository - will usually be extended by a more concrete repository.
|
||||
*/
|
||||
class Repository implements RepositoryInterface, \TYPO3\CMS\Core\SingletonInterface
|
||||
{
|
||||
/**
|
||||
* @var \TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface
|
||||
*/
|
||||
protected $persistenceManager;
|
||||
|
||||
/**
|
||||
* @var \TYPO3\CMS\Extbase\Object\ObjectManagerInterface
|
||||
*/
|
||||
protected $objectManager;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $objectType;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $defaultOrderings = [];
|
||||
|
||||
/**
|
||||
* @var \TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface
|
||||
*/
|
||||
protected $defaultQuerySettings;
|
||||
|
||||
/**
|
||||
* @param \TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface $persistenceManager
|
||||
*/
|
||||
public function injectPersistenceManager(\TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface $persistenceManager)
|
||||
{
|
||||
$this->persistenceManager = $persistenceManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new Repository
|
||||
*
|
||||
* @param \TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager
|
||||
*/
|
||||
public function __construct(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager)
|
||||
{
|
||||
$this->objectManager = $objectManager;
|
||||
$this->objectType = ClassNamingUtility::translateRepositoryNameToModelName($this->getRepositoryClassName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an object to this repository
|
||||
*
|
||||
* @param object $object The object to add
|
||||
* @throws Exception\IllegalObjectTypeException
|
||||
*/
|
||||
public function add($object)
|
||||
{
|
||||
if (!$object instanceof $this->objectType) {
|
||||
throw new \TYPO3\CMS\Extbase\Persistence\Exception\IllegalObjectTypeException('The object given to add() was not of the type (' . $this->objectType . ') this repository manages.', 1248363335);
|
||||
}
|
||||
$this->persistenceManager->add($object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an object from this repository.
|
||||
*
|
||||
* @param object $object The object to remove
|
||||
* @throws Exception\IllegalObjectTypeException
|
||||
*/
|
||||
public function remove($object)
|
||||
{
|
||||
if (!$object instanceof $this->objectType) {
|
||||
throw new \TYPO3\CMS\Extbase\Persistence\Exception\IllegalObjectTypeException('The object given to remove() was not of the type (' . $this->objectType . ') this repository manages.', 1248363336);
|
||||
}
|
||||
$this->persistenceManager->remove($object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces an existing object with the same identifier by the given object
|
||||
*
|
||||
* @param object $modifiedObject The modified object
|
||||
* @throws Exception\UnknownObjectException
|
||||
* @throws Exception\IllegalObjectTypeException
|
||||
*/
|
||||
public function update($modifiedObject)
|
||||
{
|
||||
if (!$modifiedObject instanceof $this->objectType) {
|
||||
throw new \TYPO3\CMS\Extbase\Persistence\Exception\IllegalObjectTypeException('The modified object given to update() was not of the type (' . $this->objectType . ') this repository manages.', 1249479625);
|
||||
}
|
||||
$this->persistenceManager->update($modifiedObject);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all objects of this repository.
|
||||
*
|
||||
* @return QueryResultInterface|array
|
||||
*/
|
||||
public function findAll()
|
||||
{
|
||||
return $this->createQuery()->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the total number objects of this repository.
|
||||
*
|
||||
* @return int The object count
|
||||
*/
|
||||
public function countAll()
|
||||
{
|
||||
return $this->createQuery()->execute()->count();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all objects of this repository as if remove() was called for
|
||||
* all of them.
|
||||
*/
|
||||
public function removeAll()
|
||||
{
|
||||
foreach ($this->findAll() as $object) {
|
||||
$this->remove($object);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds an object matching the given identifier.
|
||||
*
|
||||
* @param int $uid The identifier of the object to find
|
||||
* @return object The matching object if found, otherwise NULL
|
||||
*/
|
||||
public function findByUid($uid)
|
||||
{
|
||||
return $this->findByIdentifier($uid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds an object matching the given identifier.
|
||||
*
|
||||
* @param mixed $identifier The identifier of the object to find
|
||||
* @return object The matching object if found, otherwise NULL
|
||||
*/
|
||||
public function findByIdentifier($identifier)
|
||||
{
|
||||
return $this->persistenceManager->getObjectByIdentifier($identifier, $this->objectType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the property names to order the result by per default.
|
||||
* Expected like this:
|
||||
* array(
|
||||
* 'foo' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_ASCENDING,
|
||||
* 'bar' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_DESCENDING
|
||||
* )
|
||||
*
|
||||
* @param array $defaultOrderings The property names to order by
|
||||
*/
|
||||
public function setDefaultOrderings(array $defaultOrderings)
|
||||
{
|
||||
$this->defaultOrderings = $defaultOrderings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default query settings to be used in this repository
|
||||
*
|
||||
* @param \TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface $defaultQuerySettings The query settings to be used by default
|
||||
*/
|
||||
public function setDefaultQuerySettings(\TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface $defaultQuerySettings)
|
||||
{
|
||||
$this->defaultQuerySettings = $defaultQuerySettings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a query for objects of this repository
|
||||
*
|
||||
* @return \TYPO3\CMS\Extbase\Persistence\QueryInterface
|
||||
*/
|
||||
public function createQuery()
|
||||
{
|
||||
$query = $this->persistenceManager->createQueryForType($this->objectType);
|
||||
if ($this->defaultOrderings !== []) {
|
||||
$query->setOrderings($this->defaultOrderings);
|
||||
}
|
||||
if ($this->defaultQuerySettings !== null) {
|
||||
$query->setQuerySettings(clone $this->defaultQuerySettings);
|
||||
}
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches magic methods (findBy[Property]())
|
||||
*
|
||||
* @param string $methodName The name of the magic method
|
||||
* @param string $arguments The arguments of the magic method
|
||||
* @throws \TYPO3\CMS\Extbase\Persistence\Generic\Exception\UnsupportedMethodException
|
||||
* @return mixed
|
||||
*/
|
||||
public function __call($methodName, $arguments)
|
||||
{
|
||||
if (strpos($methodName, 'findBy') === 0 && strlen($methodName) > 7) {
|
||||
$propertyName = lcfirst(substr($methodName, 6));
|
||||
$query = $this->createQuery();
|
||||
$result = $query->matching($query->equals($propertyName, $arguments[0]))->execute();
|
||||
return $result;
|
||||
}
|
||||
if (strpos($methodName, 'findOneBy') === 0 && strlen($methodName) > 10) {
|
||||
$propertyName = lcfirst(substr($methodName, 9));
|
||||
$query = $this->createQuery();
|
||||
|
||||
$result = $query->matching($query->equals($propertyName, $arguments[0]))->setLimit(1)->execute();
|
||||
if ($result instanceof QueryResultInterface) {
|
||||
return $result->getFirst();
|
||||
}
|
||||
if (is_array($result)) {
|
||||
return $result[0] ?? null;
|
||||
}
|
||||
} elseif (strpos($methodName, 'countBy') === 0 && strlen($methodName) > 8) {
|
||||
$propertyName = lcfirst(substr($methodName, 7));
|
||||
$query = $this->createQuery();
|
||||
$result = $query->matching($query->equals($propertyName, $arguments[0]))->execute()->count();
|
||||
return $result;
|
||||
}
|
||||
throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception\UnsupportedMethodException('The method "' . $methodName . '" is not supported by the repository.', 1233180480);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the class name of this class.
|
||||
*
|
||||
* @return string Class name of the repository.
|
||||
*/
|
||||
protected function getRepositoryClassName()
|
||||
{
|
||||
return static::class;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\Persistence;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* Contract for a repository
|
||||
*/
|
||||
interface RepositoryInterface
|
||||
{
|
||||
/**
|
||||
* Adds an object to this repository.
|
||||
*
|
||||
* @param object $object The object to add
|
||||
*/
|
||||
public function add($object);
|
||||
|
||||
/**
|
||||
* Removes an object from this repository.
|
||||
*
|
||||
* @param object $object The object to remove
|
||||
*/
|
||||
public function remove($object);
|
||||
|
||||
/**
|
||||
* Replaces an existing object with the same identifier by the given object
|
||||
*
|
||||
* @param object $modifiedObject The modified object
|
||||
*/
|
||||
public function update($modifiedObject);
|
||||
|
||||
/**
|
||||
* Returns all objects of this repository.
|
||||
*
|
||||
* @return \TYPO3\CMS\Extbase\Persistence\QueryResultInterface|array The query result
|
||||
*/
|
||||
public function findAll();
|
||||
|
||||
/**
|
||||
* Returns the total number objects of this repository.
|
||||
*
|
||||
* @return int The object count
|
||||
*/
|
||||
public function countAll();
|
||||
|
||||
/**
|
||||
* Removes all objects of this repository as if remove() was called for
|
||||
* all of them.
|
||||
*/
|
||||
public function removeAll();
|
||||
|
||||
/**
|
||||
* Finds an object matching the given identifier.
|
||||
*
|
||||
* @param int $uid The identifier of the object to find
|
||||
* @return object The matching object if found, otherwise NULL
|
||||
*/
|
||||
public function findByUid($uid);
|
||||
|
||||
/**
|
||||
* Finds an object matching the given identifier.
|
||||
*
|
||||
* @param mixed $identifier The identifier of the object to find
|
||||
* @return object The matching object if found, otherwise NULL
|
||||
*/
|
||||
public function findByIdentifier($identifier);
|
||||
|
||||
/**
|
||||
* Sets the property names to order the result by per default.
|
||||
* Expected like this:
|
||||
* array(
|
||||
* 'foo' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_ASCENDING,
|
||||
* 'bar' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_DESCENDING
|
||||
* )
|
||||
*
|
||||
* @param array $defaultOrderings The property names to order by
|
||||
*/
|
||||
public function setDefaultOrderings(array $defaultOrderings);
|
||||
|
||||
/**
|
||||
* Sets the default query settings to be used in this repository
|
||||
*
|
||||
* @param \TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface $defaultQuerySettings The query settings to be used by default
|
||||
*/
|
||||
public function setDefaultQuerySettings(\TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface $defaultQuerySettings);
|
||||
|
||||
/**
|
||||
* Returns a query for objects of this repository
|
||||
*
|
||||
* @return \TYPO3\CMS\Extbase\Persistence\QueryInterface
|
||||
*/
|
||||
public function createQuery();
|
||||
}
|
||||
Reference in new issue
Block a user