ObjectId.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  */
11 namespace wcmf\lib\persistence;
12 
14 
15 /**
16  * ObjectId is the unique identifier of an object.
17  *
18  * @note The ObjectId must provide enough information to select the appropriate mapper for the object.
19  * This may be achived by different strategies, e.g. coding the object type into the ObjectId or
20  * having a global registry which maps ObjectIds to objects. wCMF uses the first method.
21  * Serialized ObjectIds have the following notation: prefix:type:id1:id2:... where type is the object type
22  * and id1, id2, .. are the values of the primary key columns (in case of simple keys only one).
23  * Serialization is done using the __toString method (using the ObjectId instance in a string context).
24  *
25  * @author ingo herwig <ingo@wemove.com>
26  */
27 class ObjectId {
28 
29  const DELIMITER = ':';
30 
31  private $_prefix;
32  private $_fqType;
33  private $_id;
34  private $_strVal = null;
35 
36  private static $_dummyIdPattern = 'wcmf[A-Za-z0-9]{32}';
37  private static $_idPattern = null;
38  private static $_delimiterPattern = null;
39  private static $_numPkKeys = array();
40 
41  private static $_nullOID = null;
42 
43  /**
44  * Constructor.
45  * @param $type The type name of the object (either fully qualified or simple, if not ambiguous)
46  * @param $id Either a single value or an array of values (for compound primary keys) identifying
47  * the object between others of the same type. If not given, a dummy id will be
48  * assigned (optional, default: _null_)
49  * @param $prefix A prefix for identifying a set of objects belonging to one storage in a
50  * distributed enviroment
51  * @note If id is an array, the order of the values must match the order of the primary key names given
52  * by PersistenceMapper::getPkNames().
53  */
54  public function __construct($type, $id=null, $prefix=null) {
55  $this->_prefix = $prefix;
56  $persistenceFacade = ObjectFactory::getInstance('persistenceFacade');
57  $this->_fqType = $type != 'NULL' ? $persistenceFacade->getFullyQualifiedType($type) : 'NULL';
58 
59  // get given primary keys
60  if ($id != null) {
61  if (!is_array($id)) {
62  $this->_id = array($id);
63  }
64  else {
65  $this->_id = $id;
66  }
67  }
68  else {
69  $this->_id = array();
70  }
71 
72  // add dummy ids for missing primary key values
73  $numPKs = self::getNumberOfPKs($type);
74  while (sizeof($this->_id) < $numPKs) {
75  $this->_id[] = self::getDummyId();
76  }
77 
78  // set strVal immediatly otherwise object comparison will fail in
79  // cases where __toString was only called on one instance
80  $this->_strVal = $this->__toString();
81  }
82 
83  /**
84  * Get the NULL instance
85  * @return String
86  */
87  public static function NULL_OID() {
88  if (self::$_nullOID == null) {
89  self::$_nullOID = new ObjectId('NULL');
90  }
91  return self::$_nullOID;
92  }
93 
94  /**
95  * Get the prefix
96  * @return String
97  */
98  public function getPrefix() {
99  return $this->_prefix;
100  }
101 
102  /**
103  * Get the type (including namespace)
104  * @return String
105  */
106  public function getType() {
107  return $this->_fqType;
108  }
109 
110  /**
111  * Get the id
112  * @return Array
113  */
114  public function getId() {
115  return $this->_id;
116  }
117 
118  /**
119  * Get the first id. This is especially usefull, when you know that this id only consists of one id.
120  * @return String
121  */
122  public function getFirstId() {
123  return $this->_id[0];
124  }
125 
126  /**
127  * Check if a serialized ObjectId has a valid syntax, the type is known and
128  * if the number of primary keys match the type.
129  * @param $oid The serialized ObjectId.
130  * @return Boolean
131  */
132  public static function isValid($oid) {
133  if (self::parse($oid) == null) {
134  return false;
135  }
136  return true;
137  }
138 
139  /**
140  * Parse a serialized object id string into an ObjectId instance.
141  * @param $oid The string
142  * @return ObjectId or null, if the id cannot be parsed
143  */
144  public static function parse($oid) {
145  // fast checks first
146  if ($oid instanceof ObjectId) {
147  return $oid;
148  }
149 
150  if (strlen($oid) == 0) {
151  return null;
152  }
153 
154  if (self::$_delimiterPattern == null) {
155  self::$_delimiterPattern = '/'.self::DELIMITER.'/';
156  }
157 
158  $oidParts = preg_split(self::$_delimiterPattern, $oid);
159  if (sizeof($oidParts) < 2) {
160  return null;
161  }
162 
163  if (self::$_idPattern == null) {
164  self::$_idPattern = '/^[0-9]*$|^'.self::$_dummyIdPattern.'$/';
165  }
166 
167  // get the ids from the oid
168  $ids = array();
169  $nextPart = array_pop($oidParts);
170  while($nextPart !== null && preg_match(self::$_idPattern, $nextPart) == 1) {
171  $intNextPart = (int)$nextPart;
172  if ($nextPart == (string)$intNextPart) {
173  $ids[] = $intNextPart;
174  }
175  else {
176  $ids[] = $nextPart;
177  }
178  $nextPart = array_pop($oidParts);
179  }
180  $ids = array_reverse($ids);
181 
182  // get the type
183  $type = $nextPart;
184  if (!ObjectFactory::getInstance('persistenceFacade')->isKnownType($type)) {
185  return null;
186  }
187 
188  // check if number of ids match the type
189  $numPks = self::getNumberOfPKs($type);
190  if ($numPks == null || $numPks != sizeof($ids)) {
191  return null;
192  }
193 
194  // get the prefix
195  $prefix = join(self::DELIMITER, $oidParts);
196 
197  return new ObjectID($type, $ids, $prefix);
198  }
199 
200  /**
201  * Get a string representation of the object id.
202  * @return String
203  */
204  public function __toString() {
205  if ($this->_strVal == null) {
206  $oidStr = $this->_fqType.self::DELIMITER.join(self::DELIMITER, $this->_id);
207  if (strlen(trim($this->_prefix)) > 0) {
208  $oidStr = $this->_prefix.self::DELIMITER.$oidStr;
209  }
210  $this->_strVal = $oidStr;
211  }
212  return $this->_strVal;
213  }
214 
215  /**
216  * Get a dummy id ("wcmf" + unique 32 character string).
217  * @return String
218  */
219  public static function getDummyId() {
220  return 'wcmf'.md5(uniqid(ip2long(@$_SERVER['REMOTE_ADDR']) ^ (int)@$_SERVER['REMOTE_PORT'] ^ @getmypid() ^ @disk_free_space(sys_get_temp_dir()), 1));
221  }
222 
223  /**
224  * Check if a given id is a dummy id.
225  * @param $id The id to check
226  * @return Boolean
227  */
228  public static function isDummyId($id) {
229  return (strlen($id) == 36 && strpos($id, 'wcmf') === 0);
230  }
231 
232  /**
233  * Check if this object id contains a dummy id.
234  * @return Boolean
235  */
236  public function containsDummyIds() {
237  foreach ($this->getId() as $id) {
238  if (self::isDummyId($id)) {
239  return true;
240  }
241  }
242  return false;
243  }
244 
245  /**
246  * Get the number of primary keys a type has.
247  * @param $type The type
248  * @return Integer (1 if the type is unknown)
249  */
250  private static function getNumberOfPKs($type) {
251  if (!isset(self::$_numPkKeys[$type])) {
252  $numPKs = 1;
253  $persistenceFacade = ObjectFactory::getInstance('persistenceFacade');
254  if ($persistenceFacade->isKnownType($type)) {
255  $mapper = $persistenceFacade->getMapper($type);
256  $numPKs = sizeof($mapper->getPKNames());
257  }
258  self::$_numPkKeys[$type] = $numPKs;
259  }
260  return self::$_numPkKeys[$type];
261  }
262 }
263 ?>
static getDummyId()
Get a dummy id ("wcmf" + unique 32 character string).
Definition: ObjectId.php:219
static NULL_OID()
Get the NULL instance.
Definition: ObjectId.php:87
getPrefix()
Get the prefix.
Definition: ObjectId.php:98
Persistence layer related interfaces and classes.
Definition: namespaces.php:42
ObjectId is the unique identifier of an object.
Definition: ObjectId.php:27
static getInstance($name, $dynamicConfiguration=array())
static isDummyId($id)
Check if a given id is a dummy id.
Definition: ObjectId.php:228
containsDummyIds()
Check if this object id contains a dummy id.
Definition: ObjectId.php:236
static parse($oid)
Parse a serialized object id string into an ObjectId instance.
Definition: ObjectId.php:144
__toString()
Get a string representation of the object id.
Definition: ObjectId.php:204
static isValid($oid)
Check if a serialized ObjectId has a valid syntax, the type is known and if the number of primary key...
Definition: ObjectId.php:132
getFirstId()
Get the first id.
Definition: ObjectId.php:122
__construct($type, $id=null, $prefix=null)
Constructor.
Definition: ObjectId.php:54
getType()
Get the type (including namespace)
Definition: ObjectId.php:106