コード例 #1
0
 /**
  * Determine PropertyType from on variable type.
  *
  * This is most of the remainder of ValueFactory that is still needed.
  *
  * - if the given $value is a Node object, type will be REFERENCE, unless
  *    $weak is set to true which results in WEAKREFERENCE
  * - if the given $value is a DateTime object, the type will be DATE.
  * - if the $value is an empty array, the type is arbitrarily set to STRING
  * - if the $value is a non-empty array, the type of its first element is
  *   chosen.
  *
  * Note that string is converted to date exactly if it matches the jcr
  * formatting spec for dates (sYYYY-MM-DDThh:mm:ss.sssTZD) according to
  * http://www.day.com/specs/jcr/2.0/3_Repository_Model.html#3.6.4.3%20From%20DATE%20To
  *
  * @param mixed   $value The variable we need to know the type of
  * @param boolean $weak  When a Node is given as $value this can be given
  *                       as true to create a WEAKREFERENCE.
  *
  * @return int One of the type constants
  *
  * @throws ValueFormatException if the type can not be determined
  */
 public function determineType($value, $weak = false)
 {
     if (is_array($value)) {
         if (0 === count($value)) {
             // there is no value to determine the type on. we arbitrarily
             // chose string, which is what jackrabbit does as well.
             return PropertyType::STRING;
         }
         $value = reset($value);
     }
     return PropertyType::determineType($value, $weak);
 }
コード例 #2
0
ファイル: Property.php プロジェクト: ruflin/jackalope
 /**
  * Internally used to set the value of the property without any notification
  * of changes nor state change.
  *
  * @param mixed $value
  * @param string $type
  *
  * @return void
  *
  * @see Property::setValue()
  *
  * @private
  */
 public function _setValue($value, $type = PropertyType::UNDEFINED)
 {
     if (is_null($value)) {
         $this->remove();
         return;
     }
     if (!is_integer($type)) {
         // @codeCoverageIgnoreStart
         throw new InvalidArgumentException("The type has to be one of the numeric constants defined in PHPCR\\PropertyType. {$type}");
         // @codeCoverageIgnoreEnd
     }
     if ($this->isNew()) {
         $this->isMultiple = is_array($value);
     }
     if (is_array($value) && !$this->isMultiple) {
         throw new ValueFormatException('Can not set a single value property (' . $this->name . ') with an array of values');
     }
     //TODO: check if changing type allowed.
     /*
      * if ($type !== null && ! canHaveType($type)) {
      *   throw new ConstraintViolationException("Can not set this property to type ".PropertyType::nameFromValue($type));
      * }
      */
     if (PropertyType::UNDEFINED === $type) {
         $type = PropertyType::determineType(is_array($value) ? reset($value) : $value);
     }
     $targettype = $this->type;
     if ($this->type !== $type) {
         /* TODO: find out with node type definition if the new type is allowed
              if (canHaveType($type)) {
            */
         $targettype = $type;
         /*
           } else {
               //convert to an allowed type. if the current type is defined $targettype = $this->type;
           }
         */
     }
     $value = PropertyType::convertType($value, $targettype, $type);
     if (PropertyType::BINARY === $targettype) {
         $stat = fstat($value);
         //TODO: read file into local context? fstat not available on all streams
         $this->length = $stat['size'];
     }
     $this->type = $targettype;
     $this->value = $value;
 }
コード例 #3
0
 /**
  * @expectedException \PHPCR\ValueFormatException
  */
 public function testDetermineTypeNull()
 {
     PropertyType::determineType(null);
 }
コード例 #4
0
 /**
  * Determine PropertyType from on variable type.
  *
  * This is most of the remainder of ValueFactory that is still needed.
  *
  * - if the given $value is a Node object, type will be REFERENCE, unless
  *    $weak is set to true which results in WEAKREFERENCE
  * - if the given $value is a DateTime object, the type will be DATE.
  *
  * Note that string is converted to date exactly if it matches the jcr
  * formatting spec for dates (sYYYY-MM-DDThh:mm:ss.sssTZD) according to
  * http://www.day.com/specs/jcr/2.0/3_Repository_Model.html#3.6.4.3%20From%20DATE%20To
  *
  * @param mixed   $value The variable we need to know the type of
  * @param boolean $weak  When a Node is given as $value this can be given
  *                       as true to create a WEAKREFERENCE.
  *
  * @return int One of the type constants
  *
  * @throws ValueFormatException if the type can not be determined
  */
 public function determineType($value, $weak = false)
 {
     return PropertyType::determineType($value, $weak);
 }
コード例 #5
0
ファイル: Node.php プロジェクト: ruflin/jackalope
 /**
  * Initialize or update this object with raw data from backend.
  *
  * @param array $rawData in the format as returned from Jackalope\Transport\TransportInterface
  * @param boolean $update whether to initialize this object or update
  * @param boolean $keepChanges only used if $update is true, same as $keepChanges in refresh()
  *
  * @see Node::__construct()
  * @see Node::refresh()
  */
 private function parseData($rawData, $update, $keepChanges = false)
 {
     //TODO: refactor to use hash array instead of stdClass struct
     if ($update) {
         // keep backup of old state so we can remove what needs to be removed
         $oldNodes = array_flip(array_values($this->nodes));
         $oldProperties = $this->properties;
     }
     /*
      * we collect all nodes coming from the backend. if we update with
      * $keepChanges, we use this to update the node list rather than losing
      * reorders
      *
      * properties are easy as they are not ordered.
      */
     $nodesInBackend = array();
     foreach ($rawData as $key => $value) {
         $node = false;
         // reset to avoid trouble
         if (is_object($value)) {
             // this is a node. add it if
             if (!$update || !$keepChanges || isset($oldNodes[$key]) || !($node = $this->objectManager->getCachedNode($this->path . '/' . $key))) {
                 // for all those cases, if the node was moved away or is deleted in current session, we do not add it
                 if (!$this->objectManager->isNodeMoved($this->path . '/' . $key) && !$this->objectManager->isItemDeleted($this->path . '/' . $key)) {
                     // otherwise we (re)load a node from backend but a child has been moved away already
                     $nodesInBackend[] = $key;
                 }
             }
             if ($update) {
                 unset($oldNodes[$key]);
             }
         } else {
             //property or meta information
             /* Property type declarations start with :, the value then is
              * the type string from the NodeType constants. We skip that and
              * look at the type when we encounter the value of the property.
              *
              * If its a binary data, we only get the type declaration and
              * no data. Then the $value of the type declaration is not the
              * type string for binary, but the number of bytes of the
              * property - resp. array of number of bytes.
              *
              * The magic property ::NodeIteratorSize tells this node has no
              * children. Ignore that info for now. We might optimize with
              * this info once we do prefetch nodes.
              */
             if (0 === strpos($key, ':')) {
                 if ((is_int($value) || is_array($value)) && $key != '::NodeIteratorSize') {
                     // This is a binary property and we just got its length with no data
                     $key = substr($key, 1);
                     if (!isset($rawData->{$key})) {
                         $binaries[$key] = $value;
                         if ($update) {
                             unset($oldProperties[$key]);
                         }
                         if (isset($this->properties[$key])) {
                             // refresh existing binary, this will only happen in update
                             // only update length
                             if (!($keepChanges && $this->properties[$key]->isModified())) {
                                 $this->properties[$key]->_setLength($value);
                                 if ($this->properties[$key]->isDirty()) {
                                     $this->properties[$key]->setClean();
                                 }
                             }
                         } else {
                             // this will always fall into the creation mode
                             $this->_setProperty($key, $value, PropertyType::BINARY, true);
                         }
                     }
                 }
                 //else this is a type declaration
                 //skip this entry (if its binary, its already processeed
                 continue;
             }
             if ($update && array_key_exists($key, $this->properties)) {
                 unset($oldProperties[$key]);
                 $prop = $this->properties[$key];
                 if ($keepChanges && $prop->isModified()) {
                     continue;
                 }
             } elseif ($update && array_key_exists($key, $this->deletedProperties)) {
                 if ($keepChanges) {
                     // keep the delete
                     continue;
                 } else {
                     // restore the property
                     $this->properties[$key] = $this->deletedProperties[$key];
                     $this->properties[$key]->setClean();
                     // now let the loop update the value. no need to talk to ObjectManager as it
                     // does not store property deletions
                 }
             }
             switch ($key) {
                 case 'jcr:index':
                     $this->index = $value;
                     break;
                 case 'jcr:primaryType':
                     $this->primaryType = $value;
                     // type information is exposed as property too, although there exist more specific methods
                     $this->_setProperty('jcr:primaryType', $value, PropertyType::NAME, true);
                     break;
                 case 'jcr:mixinTypes':
                     // type information is exposed as property too, although there exist more specific methods
                     $this->_setProperty($key, $value, PropertyType::NAME, true);
                     break;
                     // OPTIMIZE: do not instantiate properties until needed
                 // OPTIMIZE: do not instantiate properties until needed
                 default:
                     if (isset($rawData->{':' . $key})) {
                         /*
                          * this is an inconsistency between jackrabbit and
                          * dbal transport: jackrabbit has type name, dbal
                          * delivers numeric type.
                          * we should eventually fix the format returned by
                          * transport and either have jackrabbit transport
                          * do the conversion or let dbal store a string
                          * value instead of numerical.
                          */
                         $type = is_numeric($rawData->{':' . $key}) ? $rawData->{':' . $key} : PropertyType::valueFromName($rawData->{':' . $key});
                     } else {
                         $type = PropertyType::determineType(is_array($value) ? reset($value) : $value);
                     }
                     $this->_setProperty($key, $value, $type, true);
                     break;
             }
         }
     }
     if ($update) {
         if ($keepChanges) {
             // we keep changes. merge new nodes to the right place
             $previous = null;
             $newFromBackend = array_diff($nodesInBackend, array_intersect($this->nodes, $nodesInBackend));
             foreach ($newFromBackend as $name) {
                 $pos = array_search($name, $nodesInBackend);
                 if (is_array($this->originalNodesOrder)) {
                     // update original order to send the correct reorderings
                     array_splice($this->originalNodesOrder, $pos, 0, $name);
                 }
                 if ($pos === 0) {
                     array_unshift($this->nodes, $name);
                 } else {
                     // do we find the predecessor of the new node in the list?
                     $insert = array_search($nodesInBackend[$pos - 1], $this->nodes);
                     if (false !== $insert) {
                         array_splice($this->nodes, $insert + 1, 0, $name);
                     } else {
                         // failed to find predecessor, add to the end
                         $this->nodes[] = $name;
                     }
                 }
             }
         } else {
             // discard changes, just overwrite node list
             $this->nodes = $nodesInBackend;
             $this->originalNodesOrder = null;
         }
         foreach ($oldProperties as $name => $property) {
             if (!($keepChanges && $property->isNew())) {
                 // may not call remove(), we dont want another delete with the backend to be attempted
                 $this->properties[$name]->setDeleted();
                 unset($this->properties[$name]);
             }
         }
         // notify nodes that where not received again that they disappeared
         foreach ($oldNodes as $name => $index) {
             if ($this->objectManager->purgeDisappearedNode($this->path . '/' . $name, $keepChanges)) {
                 // drop, it was not a new child
                 if ($keepChanges) {
                     // otherwise we overwrote $this->nodes with the backend
                     $id = array_search($name, $this->nodes);
                     if (false !== $id) {
                         unset($this->nodes[$id]);
                     }
                 }
             }
         }
     } else {
         // new node loaded from backend
         $this->nodes = $nodesInBackend;
     }
 }
コード例 #6
0
ファイル: Property.php プロジェクト: viral810/ngSimpleCMS
 /**
  * Create a property, either from server data or locally
  *
  * To indicate a property has newly been created locally, make sure to pass
  * true for the $new parameter. In that case, you should pass an empty array
  * for $data and use setValue afterwards to let the type magic be handled.
  * Then multivalue is determined on setValue
  *
  * For binary properties, the value is the length of the data(s), not the
  * data itself.
  *
  * @param FactoryInterface $factory the object factory
  * @param array            $data    array with fields <tt>type</tt>
  *      (integer or string from PropertyType) and <tt>value</tt> (data for
  *      creating the property value - array for multivalue property)
  * @param string        $path          the absolute path of this item
  * @param Session       $session       the session instance
  * @param ObjectManager $objectManager the objectManager instance - the
  *      caller has to take care of registering this item with the object
  *      manager
  * @param boolean $new optional: set to true to make this property aware
  *      its not yet existing on the server. defaults to false
  */
 public function __construct(FactoryInterface $factory, array $data, $path, Session $session, ObjectManager $objectManager, $new = false)
 {
     parent::__construct($factory, $path, $session, $objectManager, $new);
     $this->wrapBinaryStreams = $session->getRepository()->getDescriptor(Repository::JACKALOPE_OPTION_STREAM_WRAPPER);
     if (empty($data) && $new) {
         return;
     }
     if (!isset($data['value'])) {
         throw new InvalidArgumentException("Can't create property at {$path} without any data");
     }
     if (isset($data['type']) && PropertyType::UNDEFINED !== $data['type']) {
         $type = $data['type'];
         if (is_string($type)) {
             $type = PropertyType::valueFromName($type);
         } elseif (!is_numeric($type)) {
             // @codeCoverageIgnoreStart
             throw new RepositoryException("INTERNAL ERROR -- No valid type specified ({$type})");
             // @codeCoverageIgnoreEnd
         } else {
             //sanity check. this will throw InvalidArgumentException if $type is not a valid type
             PropertyType::nameFromValue($type);
         }
     } else {
         // we are creating a node
         $type = PropertyType::determineType(is_array($data['value']) ? reset($data['value']) : $data['value']);
     }
     $this->type = $type;
     if ($type == PropertyType::BINARY && !$new) {
         // reading a binary property from backend, we do not get the stream immediately but just the size
         if (is_array($data['value'])) {
             $this->isMultiple = true;
         }
         $this->length = $data['value'];
         $this->value = null;
         return;
     }
     if (is_array($data['value'])) {
         $this->isMultiple = true;
         $this->value = array();
         foreach ($data['value'] as $value) {
             $this->value[] = $this->valueConverter->convertType($value, $type);
         }
     } elseif (null !== $data['value']) {
         $this->value = $this->valueConverter->convertType($data['value'], $type);
     } else {
         // @codeCoverageIgnoreStart
         throw new RepositoryException('INTERNAL ERROR -- data[value] may not be null');
         // @codeCoverageIgnoreEnd
     }
 }
コード例 #7
0
ファイル: NodeType.php プロジェクト: ruflin/jackalope
 /**
  * {@inheritDoc}
  *
  * @api
  */
 public function canSetProperty($propertyName, $value, $throw = false)
 {
     $propDefs = $this->getPropertyDefinitions();
     try {
         $type = PropertyType::determineType(is_array($value) ? reset($value) : $value);
     } catch (ValueFormatException $e) {
         if ($throw) {
             throw $e;
         }
         return false;
     }
     // check explicit matches first and keep wildcard definitions for later
     $wildcards = array();
     foreach ($propDefs as $prop) {
         if ('*' == $prop->getName()) {
             $wildcards[] = $prop;
         } elseif ($propertyName == $prop->getName()) {
             if (is_array($value) != $prop->isMultiple()) {
                 if ($prop->isMultiple()) {
                     throw new ConstraintViolationException("The property definition is multivalued, but the value '{$value}' is not.");
                 }
                 if (is_array($value)) {
                     throw c("The value {$value} is multivalued, but the property definition is not.");
                 }
             }
             if (PropertyType::UNDEFINED == $prop->getRequiredType() || $type == $prop->getRequiredType()) {
                 return true;
             }
             // try if we can convert. OPTIMIZE: would be nice to know without actually attempting to convert
             try {
                 PropertyType::convertType($value, $prop->getRequiredType(), $type);
                 return true;
             } catch (ValueFormatException $e) {
                 // fall through and return false
             }
             if ($throw) {
                 throw new ConstraintViolationException("The property '{$propertyName}' with value '{$value}' can't be converted to an existing type.");
             }
             return false;
             // if there is an explicit match, it has to fit
         }
     }
     // now check if any of the wildcards matches
     foreach ($wildcards as $prop) {
         if (is_array($value) != $prop->isMultiple()) {
             continue;
         }
         if (PropertyType::UNDEFINED == $prop->getRequiredType() || $type == $prop->getRequiredType()) {
             return true;
         }
         // try if we can convert. OPTIMIZE: would be nice to know without actually attempting to convert
         try {
             PropertyType::convertType($value, $prop->getRequiredType(), $type);
             return true;
         } catch (ValueFormatException $e) {
             if ($throw) {
                 throw $e;
             }
             return false;
             // if there is an explicit match, it has to fit
         }
     }
     if ($throw) {
         $val = is_object($value) ? get_class($value) : (is_scalar($value) ? (string) $value : gettype($value));
         throw new ConstraintViolationException("Node type definition does not allow to set the property with name '{$propertyName}' and value '{$val}'");
     }
     return false;
 }