db = $db; } /** * Fetches properties for a path. * * This method received a PropFind object, which contains all the * information about the properties that need to be fetched. * * Usually you would just want to call 'get404Properties' on this object, * as this will give you the _exact_ list of properties that need to be * fetched, and haven't yet. * * However, you can also support the 'allprops' property here. In that * case, you should check for $propFind->isAllProps(). * * @param string $path * @param PropFind $propFind */ public function propFind($path, PropFind $propFind) { if (!$propFind->isAllProps() && 0 === count($propFind->get404Properties())) { return; } $propertys = $this->db->select('*') ->from('propertystorage.json') ->where(['path' => $path]) ->get(); foreach ($propertys as $property) { if ('resource' === gettype($property['value'])) { $property['value'] = stream_get_contents($property['value']); } switch ($property['valuetype']) { case null: case self::VT_STRING: $propFind->set($property['name'], $property['value']); break; case self::VT_XML: $propFind->set($property['name'], new Complex($property['value'])); break; case self::VT_OBJECT: $propFind->set($property['name'], unserialize($property['value'])); break; } } } /** * Updates properties for a path. * * This method received a PropPatch object, which contains all the * information about the update. * * Usually you would want to call 'handleRemaining' on this object, to get; * a list of all properties that need to be stored. * * @param string $path * @param PropPatch $propPatch */ public function propPatch ($path, PropPatch $propPatch) { $propPatch->handleRemaining(function ($properties) use ($path) { foreach ($properties as $name => $value) { if (!is_null($value)) { if (is_scalar($value)) { $valueType = self::VT_STRING; } elseif ($value instanceof Complex) { $valueType = self::VT_XML; $value = $value->getXml(); } else { $valueType = self::VT_OBJECT; $value = serialize($value); } $result = $this->db->select('*') ->from('propertystorage.json') ->where(['path' => $path, 'name' => $name]) ->get(); if (!$result) { $this->db->insert('propertystorage.json', [ 'path' => $path, 'name' => $name, 'valuetype' => $valueType, 'value' => $value, ]); } else { $this->db->update(['valuetype' => $valueType, 'value' => $value]) ->from('propertystorage.json') ->where(['path' => $path, 'name' => $name]) ->trigger(); } } else { $this->db->delete() ->from('propertystorage.json') ->where(['path' => $path, 'name' => $name]) ->trigger(); } } return true; }); } /** * This method is called after a node is deleted. * * This allows a backend to clean up all associated properties. * * The delete method will get called once for the deletion of an entire * tree. * * @param string $path */ public function delete ($path) { $paths = []; $results = $this->db->select('path') ->from('propertystorage.json') ->get(); foreach ($results as $result) { if (!Helpers::startsWith($path, $result['path'])) continue; $paths[] = $result['path']; } foreach ($paths as $path) { $this->db->delete() ->from('propertystorage.json') ->where(['path' => $path]) ->trigger(); } } /** * This method is called after a successful MOVE. * * This should be used to migrate all properties from one path to another. * Note that entire collections may be moved, so ensure that all properties * for children are also moved along. * * @param string $source * @param string $destination */ public function move ($source, $destination) { $paths = []; $results = $this->db->select('path') ->from('propertystorage.json') ->get(); foreach ($results as $result) { if (!Helpers::startsWith($source, $result['path'])) continue; $paths[] = $result['path']; } foreach ($paths as $path) { if ($row['path'] !== $source && 0 !== strpos($row['path'], $source.'/')) { continue; } $trailingPart = substr($row['path'], strlen($source) + 1); $newPath = $destination; if ($trailingPart) { $newPath .= '/'.$trailingPart; } $update->execute([$newPath, $row['id']]); $this->db->update(['path' => $newPath]) ->from('propertystorage.json') ->where(['path' => $path]) ->trigger(); } } }