DefaultPersistenceFacade.php
1 <?php
2 /**
3  * wCMF - wemove Content Management Framework
4  * Copyright (C) 2005-2015 wemove digital solutions GmbH
5  *
6  * Licensed under the terms of the MIT License.
7  *
8  * See the LICENSE file distributed with this work for
9  * additional information.
10  */
12 
25 
26 /**
27  * Default PersistenceFacade implementation.
28  *
29  * @author ingo herwig <ingo@wemove.com>
30  */
32 
33  private $_mappers = array();
34  private $_simpleToFqNames = array();
35  private $_createdOIDs = array();
36  private $_eventManager = null;
37  private $_currentTransaction = null;
38  private $_logStrategy = null;
39 
40  /**
41  * Constructor
42  * @param $eventManager
43  * @param $logStrategy OutputStrategy used for logging persistence actions.
44  */
45  public function __construct(EventManager $eventManager,
46  OutputStrategy $logStrategy) {
47  $this->_eventManager = $eventManager;
48  $this->_logStrategy = $logStrategy;
49  // register as change listener to track the created oids, after save
50  $this->_eventManager->addListener(StateChangeEvent::NAME,
51  array($this, 'stateChanged'));
52  }
53 
54  /**
55  * Destructor
56  */
57  public function __destruct() {
58  $this->_eventManager->removeListener(StateChangeEvent::NAME,
59  array($this, 'stateChanged'));
60  }
61 
62  /**
63  * Set the PersistentMapper instances.
64  * @param $mappers Associative array with the fully qualified
65  * mapped class names as keys and the mapper instances as values
66  */
67  public function setMappers($mappers) {
68  $this->_mappers = $mappers;
69  foreach ($mappers as $fqName => $mapper) {
70  // register simple type names
71  $name = $this->getSimpleType($fqName);
72  if (!isset($this->_mappers[$name])) {
73  $this->_mappers[$name] = $mapper;
74  $this->_simpleToFqNames[$name] = $fqName;
75  }
76  // set logging strategy
77  $mapper->setLogStrategy($this->_logStrategy);
78  }
79  }
80 
81  /**
82  * @see PersistenceFacade::getKnownTypes()
83  */
84  public function getKnownTypes() {
85  return array_values($this->_simpleToFqNames);
86  }
87 
88  /**
89  * @see PersistenceFacade::isKnownType()
90  */
91  public function isKnownType($type) {
92  return (isset($this->_mappers[$type]));
93  }
94 
95  /**
96  * @see PersistenceFacade::getFullyQualifiedType()
97  */
98  public function getFullyQualifiedType($type) {
99  if (isset($this->_simpleToFqNames[$type])) {
100  return $this->_simpleToFqNames[$type];
101  }
102  if ($this->isKnownType($type)) {
103  return $type;
104  }
105  throw new ConfigurationException("Type '".$type."' is unknown.");
106  }
107 
108  /**
109  * @see PersistenceFacade::getSimpleType()
110  */
111  public function getSimpleType($type) {
112  $pos = strrpos($type, '.');
113  if ($pos !== false) {
114  return substr($type, $pos+1);
115  }
116  return $type;
117  }
118 
119  /**
120  * @see PersistenceFacade::load()
121  */
122  public function load(ObjectId $oid, $buildDepth=BuildDepth::SINGLE) {
123  if ($buildDepth < 0 && !in_array($buildDepth, array(BuildDepth::INFINITE, BuildDepth::SINGLE))) {
124  throw new IllegalArgumentException("Build depth not supported: $buildDepth");
125  }
126  // check if the object is already part of the transaction
127  $transaction = $this->getTransaction();
128  $obj = $transaction->getLoaded($oid);
129 
130  // if not cached or build depth requested, load
131  if ($obj == null || $buildDepth != BuildDepth::SINGLE) {
132  $mapper = $this->getMapper($oid->getType());
133  $obj = $mapper->load($oid, $buildDepth);
134  }
135  return $obj;
136  }
137 
138  /**
139  * @see PersistenceFacade::create()
140  */
141  public function create($type, $buildDepth=BuildDepth::SINGLE) {
142  if ($buildDepth < 0 && !in_array($buildDepth, array(BuildDepth::INFINITE, BuildDepth::SINGLE, BuildDepth::REQUIRED))) {
143  throw new IllegalArgumentException("Build depth not supported: $buildDepth");
144  }
145 
146  $mapper = $this->getMapper($type);
147  $obj = $mapper->create($type, $buildDepth);
148 
149  // register the object with the transaction, if it is active
150  $transaction = $this->getTransaction();
151  if ($transaction->isActive()) {
152  $transaction->registerNew($obj);
153  }
154 
155  return $obj;
156  }
157 
158  /**
159  * @see PersistenceFacade::getLastCreatedOID()
160  */
161  public function getLastCreatedOID($type) {
162  $fqType = $this->getFullyQualifiedType($type);
163  if (isset($this->_createdOIDs[$fqType]) && sizeof($this->_createdOIDs[$fqType]) > 0) {
164  return $this->_createdOIDs[$fqType][sizeof($this->_createdOIDs[$fqType])-1];
165  }
166  return null;
167  }
168 
169  /**
170  * @see PersistenceFacade::getOIDs()
171  */
172  public function getOIDs($type, $criteria=null, $orderby=null, PagingInfo $pagingInfo=null) {
173  $this->checkArrayParameter($criteria, 'criteria', 'wcmf\lib\persistence\Criteria');
174  $this->checkArrayParameter($orderby, 'orderby');
175 
176  $mapper = $this->getMapper($type);
177  $result = $mapper->getOIDs($type, $criteria, $orderby, $pagingInfo);
178  return $result;
179  }
180 
181  /**
182  * @see PersistenceFacade::getFirstOID()
183  */
184  public function getFirstOID($type, $criteria=null, $orderby=null, PagingInfo $pagingInfo=null) {
185  if ($pagingInfo == null) {
186  $pagingInfo = new PagingInfo(1);
187  }
188  $oids = $this->getOIDs($type, $criteria, $orderby, $pagingInfo);
189  if (sizeof($oids) > 0) {
190  return $oids[0];
191  }
192  else {
193  return null;
194  }
195  }
196 
197  /**
198  * @see PersistenceFacade::loadObjects()
199  */
200  public function loadObjects($type, $buildDepth=BuildDepth::SINGLE, $criteria=null, $orderby=null, PagingInfo $pagingInfo=null) {
201  $this->checkArrayParameter($criteria, 'criteria', 'wcmf\lib\persistence\Criteria');
202  $this->checkArrayParameter($orderby, 'orderby');
203 
204  $mapper = $this->getMapper($type);
205  $result = $mapper->loadObjects($type, $buildDepth, $criteria, $orderby, $pagingInfo);
206  return $result;
207  }
208 
209  /**
210  * @see PersistenceFacade::loadFirstObject()
211  */
212  public function loadFirstObject($type, $buildDepth=BuildDepth::SINGLE, $criteria=null, $orderby=null, PagingInfo $pagingInfo=null) {
213  if ($pagingInfo == null) {
214  $pagingInfo = new PagingInfo(1);
215  }
216  $objects = $this->loadObjects($type, $buildDepth, $criteria, $orderby, $pagingInfo);
217  if (sizeof($objects) > 0) {
218  return $objects[0];
219  }
220  else {
221  return null;
222  }
223  }
224 
225  /**
226  * @see PersistenceFacade::getTransaction()
227  */
228  public function getTransaction() {
229  if ($this->_currentTransaction == null) {
230  $this->_currentTransaction = ObjectFactory::getInstance('transaction');
231  }
232  return $this->_currentTransaction;
233  }
234 
235  /**
236  * @see PersistenceFacade::getMapper()
237  */
238  public function getMapper($type) {
239  if ($this->isKnownType($type)) {
240  $mapper = $this->_mappers[$type];
241  return $mapper;
242  }
243  else {
244  throw new ConfigurationException("No PersistenceMapper found for type '".$type."'");
245  }
246  }
247 
248  /**
249  * @see PersistenceFacade::setMapper()
250  */
251  public function setMapper($type, PersistenceMapper $mapper) {
252  $this->_mappers[$type] = $mapper;
253  }
254 
255  /**
256  * Check if the given value is either null or an array and
257  * throw an exception if not
258  * @param $param The parameter
259  * @param $name The name of the parameter (used in the exception text)
260  * @param $className Classname to match if, instances of a specific type are expected (optional)
261  */
262  private function checkArrayParameter($param, $paramName, $className=null) {
263  if ($param == null) {
264  return;
265  }
266  if (!is_array($param)) {
267  throw new IllegalArgumentException("The parameter '".$paramName.
268  "' is expected to be null or an array");
269  }
270  if ($className != null) {
271  foreach ($param as $instance) {
272  if (!($instance instanceof $className)) {
273  throw new IllegalArgumentException("The parameter '".$paramName.
274  "' is expected to contain only instances of '".$className."'");
275  }
276  }
277  }
278  }
279 
280  /**
281  * Listen to StateChangeEvents
282  * @param $event StateChangeEvent instance
283  */
284  public function stateChanged(StateChangeEvent $event) {
285  $oldState = $event->getOldValue();
286  $newState = $event->getNewValue();
287  // store the object id in the internal registry if the object was saved after creation
288  if ($oldState == PersistentObject::STATE_NEW && $newState == PersistentObject::STATE_CLEAN) {
289  $object = $event->getObject();
290  $type = $object->getType();
291  if (!array_key_exists($type, $this->_createdOIDs)) {
292  $this->_createdOIDs[$type] = array();
293  }
294  $this->_createdOIDs[$type][] = $object->getOID();
295  }
296  }
297 }
298 ?>
EventManager is responsible for dispatching events to registered listeners.
OutputStrategy defines the interface for classes that write an object's content to a destination (cal...
IllegalArgumentException signals an exception in method arguments.
getObject()
Get the object whose state has changed.
ObjectId is the unique identifier of an object.
Definition: ObjectId.php:27
getFirstOID($type, $criteria=null, $orderby=null, PagingInfo $pagingInfo=null)
StateChangeEvent signals a change of the state of a PersistentObject instance.
PersistenceMapper defines the interface for all mapper classes.
stateChanged(StateChangeEvent $event)
Listen to StateChangeEvents.
static getInstance($name, $dynamicConfiguration=array())
PagingInfo contains information about a paged list.
Definition: PagingInfo.php:18
loadFirstObject($type, $buildDepth=BuildDepth::SINGLE, $criteria=null, $orderby=null, PagingInfo $pagingInfo=null)
Default PersistenceFacade implementation.
load(ObjectId $oid, $buildDepth=BuildDepth::SINGLE)
setMappers($mappers)
Set the PersistentMapper instances.
loadObjects($type, $buildDepth=BuildDepth::SINGLE, $criteria=null, $orderby=null, PagingInfo $pagingInfo=null)
PersistenceFacade defines the interface for PersistenceFacade implementations.
getType()
Get the type (including namespace)
Definition: ObjectId.php:106
getOIDs($type, $criteria=null, $orderby=null, PagingInfo $pagingInfo=null)
ConfigurationException signals an exception in the configuration.
__construct(EventManager $eventManager, OutputStrategy $logStrategy)
Constructor.