| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412 |
- <?php
- Lib::loadClass('Api_WfsNs');
- Lib::loadClass('Api_WfsException');
- Lib::loadClass('User');
- Lib::loadClass('Core_AclHelper');
- Lib::loadClass('Core_AclBase');
- // TODO: need PermProfile - array of perm profile list or just 'R,W,X,C,S', etc.
- class Core_AclSimpleSchemaBase extends Core_AclBase {
- /** simpleSchema - php structure:
- $simpleSchema = [
- 'root' => [
- '@namespace' => 'default_db/ZALICZKA/Zaliczka',
- '@primaryKey' => 'ID',
- 'ID' => 'xsd:integer', // short syntax - define only simpleType
- 'KWOTA' => [ // long syntax - define type with another params like restrictions
- '@type' => 'xsd:decimal'
- ],
- 'worker' => 'ref:Worker' // short syntax - define only type = ref
- 'pozycja' => [ // long syntax - define ref with maxOccurs, TODO: use more xsd attributes
- '@ref' => 'ZaliczkaPozycja',
- '@maxOccurs' => 'unbounded'
- ]
- ],
- 'Worker' => [
- '@namespace' => 'default_objects/AccessOwner',
- ...
- ],
- 'ZaliczkaPozycja' => [
- '@namespace' => 'default_db/ZALICZKA_POZYCJA/ZaliczkaPozycja',
- ...
- ]
- 'YT_LINK' => [ '@type' => 'p5:typeSpecialSimpleLink',
- '@label' => "Youtube link",
- '@@params' => [// $acl->getXsdFieldParam($col, 'format');
- 'format' => '<a href="https://www.youtube.com/watch?v={LINK}" target="_blank"></a>',
- 'aliasMap' => [
- 'LINK' => 'LINK'
- ]
- ]
- ],
- ]
- */
- public $_simpleSchema = array();
- public $_xsdTypes = null;// set by parseXsdTypes()
- public $_name = '';
- public $_namespace = '';
- public $_primaryKey = '';
- public $_rootTableName = '';
- public $_sourceNamespace = '';
- public $_xmlnsMap = [];
- public function __construct($simpleSchema = null) {
- if ($simpleSchema) $this->_simpleSchema = $simpleSchema;
- if (!$this->_simpleSchema) throw new Exception("Missing simpleSchema");
- if (empty($this->_simpleSchema['root'])) throw new Exception("Wrong simpleSchema syntax");
- if (empty($this->_simpleSchema['root']['@namespace'])) throw new Exception("Missing @namespace in simpleSchema");
- $this->_namespace = $this->_simpleSchema['root']['@namespace'];
- $ns = explode('/', $this->_namespace);
- $this->_name = end($ns);
- if (empty($this->_rootTableName)) {
- if (count($ns) < 3) throw new Exception("Wrong @namespace syntax in simpleSchema ns({$this->_simpleSchema['root']['@namespace']})");
- $this->_rootTableName = $ns[1];
- }
- {
- $this->_sourceNamespace = explode('/', $this->_namespace);
- array_pop($this->_sourceNamespace);// remove name
- $this->_sourceNamespace = implode('__x3A__', $this->_sourceNamespace);
- }
- if (empty($this->_simpleSchema['root']['@primaryKey'])) $this->_simpleSchema['root']['@primaryKey'] = 'ID';// TODO: throw new Exception("Missing @primaryKey in simpleSchema '{$this->_name}'");
- $this->_primaryKey = $this->_simpleSchema['root']['@primaryKey'];// TODO: check if field exists
- {// validate and fix _simpleSchema:
- // - convert field scalar to [ '@type' => ... ]
- // - check required @namespace attribute
- foreach ($this->_simpleSchema as $keySchema => $schema) {
- foreach ($schema as $fieldName => $params) {
- if ('@' == substr($fieldName, 0, 1)) continue;// skip params
- if (is_scalar($params)) {
- $this->_simpleSchema[ $keySchema ][ $fieldName ] = [ '@type' => $params ];
- } else if (!is_array($params)) {
- throw new Exception("Parse error - simpleSchema field type");
- }
- }
- if (empty($schema['@namespace'])) throw new Exception("Missing @namespace in schema for '{$keySchema}'");
- $ns = explode('/', $schema['@namespace']);
- $name = end($ns);
- if (count($ns) < 2) throw new Exception("Wrong @namespace syntax in schema for '{$keySchema}'");
- }
- }
- // $this->parseXsdTypes();// parse xsdTypes
- $this->_xsdTypes = array();
- {
- $generatedIdZasob = 10000;// fake zasob id
- foreach ($this->_simpleSchema['root'] as $key => $value) {
- if ('@' == substr($key, 0, 1)) continue;// skip attributes
- if (is_array($value)) {
- $fieldName = $key;
- $field = [ 'name' => $fieldName, 'perms' => '', 'idZasob' => $generatedIdZasob ];
- if (!empty($value['@label'])) $field['label'] = $value['@label'];
- if (!empty($value['@type'])) $field['xsdType'] = "{$value['@type']}";
- else if (!empty($value['@ref'])) {
- $field['xsdType'] = (false !== strpos($value['@ref'], '/'))
- ? "ref_uri:{$value['@ref']}"
- : "ref:{$value['@ref']}";
- }
- else throw new Exception("StorageAcl - field type not defined '{$key}'");
- if (!empty($value['@maxOccurs'])) $field['maxOccurs'] = $value['@maxOccurs'];
- $this->_xsdTypes[$fieldName] = $field;
- } else if (is_scalar($value)) {// short syntax: $fieldName => $xsdType
- $fieldName = $key;
- $field = [ 'name' => $fieldName, 'perms' => '', 'idZasob' => $generatedIdZasob ];
- $field['xsdType'] = $value;
- $this->_xsdTypes[$fieldName] = $field;
- } else {
- throw new Exception("StorageAcl - TODO: Unimplemented value type in simpleSchema: " . json_encode($value));
- }
- $generatedIdZasob++;
- }
- }
- // TODO: fix 'ref:*' types - use Core_AclHelper::parseNamespaceUrl($namespace)
- }
- public function __toString() {
- $out = "xsd @prefix(default_db__x3A__{$this->_rootTableName})" . "\n";
- $aliasRefUri = array();
- foreach ($this->_simpleSchema as $objectName => $schema) {
- if ('root' == $objectName) $objectName = $this->_name;
- $out .= "\t" . "{$objectName}";
- $out .= " @namespace({$schema['@namespace']})";
- $out .= "\n";
- foreach ($schema as $fieldName => $field) {
- if ('@' == substr($fieldName, 0, 1)) continue;// skip tags
- $out .= "\t\t" . "{$fieldName}";
- if (!empty($field['@type'])) {
- $out .= " @type({$field['@type']})";
- if (!empty($field['@alias'])) $out .= " @alias({$field['@alias']})";
- } else if (!empty($field['@ref'])) {
- $out .= " @ref({$field['@ref']})";
- if (false !== strpos($field['@ref'], '/')) $aliasRefUri[ $fieldName ] = $field['@ref'];
- } else {
- $out .= " @BUG('missing @type or @ref')";
- }
- // TODO: maxOccurs, nillable, etc.
- $out .= "\n";
- }
- foreach ($aliasRefUri as $fieldName => $nsUri) {
- $out .= "\t" . "{$objectName} @ref({$nsUri})" . "\n";
- // TODO: maxOccurs, nillable, etc.
- }
- }
- return $out;
- }
- public function hasSimpleSchema() { return true; }
- public function getSimpleSchema() { return $this->_simpleSchema; }
- public function getSimpleSchemaTree() {
- $tree = array();
- foreach ($this->_simpleSchema['root'] as $fieldName => $field) {
- $tree[ $fieldName ] = $field;
- if (is_array($field) && !empty($field['@ref'])) {
- $tree[ $fieldName ] = $this->_getSimpleSchemaTreeRec($field['@ref']);
- }
- }
- return $tree;
- }
- public function _getSimpleSchemaTreeRec($ref) {
- // echo "<p>DBG: F._getSimpleSchemaTreeRec({$ref})</p>";
- $tree = array();
- if (!empty($this->_simpleSchema[ $ref ])) {
- $tree = array();
- foreach ($this->_simpleSchema[ $ref ] as $fieldName => $field) {
- // echo "<p>DBG: F._getSimpleSchemaTreeRec({$ref}) 1/'{$fieldName}'</p>";
- $tree[ $fieldName ] = $field;
- if (is_array($field) && !empty($field['@ref'])) {
- $tree[ $fieldName ] = $this->_getSimpleSchemaTreeRec($field['@ref']);
- }
- }
- } else {
- $acl = Core_AclHelper::getAclByNamespace($ref);
- $tree[ '@namespace' ] = $acl->getNamespace();
- foreach ($acl->getXsdTypes() as $fieldName => $field) {
- // echo "<p>DBG: F._getSimpleSchemaTreeRec({$ref}) 2/'{$fieldName}'</p>";
- $tree[ $fieldName ] = $field;
- if (is_array($field) && !empty($field['@ref'])) {
- $tree[ $fieldName ] = $this->_getSimpleSchemaTreeRec($field['@ref']);
- }
- }
- }
- // echo'<pre>F._getSimpleSchemaTreeRec('.$ref.') tree';print_r($tree);echo'</pre>';
- return $tree;
- }
- public function getName() { return $this->_name; }
- public function getRootTableName() { return $this->_rootTableName; }
- public function getXsdTypes() { return $this->_xsdTypes; }
- public function getNamespace() { return $this->_namespace; }
- public function getSourceName() { return $this->_sourceNamespace; }
- public function init($force = false) {}
- public function isInitialized() { return true; }
- public function getFieldListByIdZasob() { return $this->getRealFieldListByIdZasob(); }
- public function getVisibleFieldListByIdZasob() { return $this->getRealFieldListByIdZasob(); }
- public function getVirtualFieldListByIdZasob() { return array(); }
- public function getRealFieldListByIdZasob($force = false) {
- $cols = array();
- foreach ($this->getFields() as $idField => $field) {
- $cols[$idField] = $field['name'];
- }
- return $cols;
- }
- public function getFields() {// @returns array - $this->_fields
- $fieldsById = array();
- foreach ($this->getXsdTypes() as $fieldName => $field) {
- $field['name'] = $fieldName;
- $field['label'] = V::get('label', $fieldName, $field);
- if ('p5:www_link' == $field['xsdType']) $field['simpleType'] = 'p5:www_link';
- $fieldsById[ $field['idZasob'] ] = $field;
- }
- return $fieldsById;
- }
- public function getFieldType($fieldName) {
- foreach ($this->getFields() as $field) {
- if ($fieldName == $field['name']) return $field;
- }
- return null;
- }
- // TODO: replace legacy functions: isAllowed, hasFieldPerm, getFieldIdByName
- public function canCreateField($fieldName) { return false; }// TODO: perms from Procesy
- public function canReadField($fieldName) { return true; }// TODO: perms from Procesy
- public function canReadObjectField($fieldName, $record) { return true; }// TODO: perms from Procesy
- public function canWriteField($fieldName) { return false; }// TODO: perms from Procesy
- public function canWriteObjectField($fieldName, $record) { return false; }// TODO: perms from Procesy
- public function getTotal($params = array()) { throw new Exception("Unimplemented - TODO: F." . __FUNCTION__); }// TODO: use ParseOgcQuery
- public function getItem($primaryKey, $params = []) { throw new Exception("Unimplemented - TODO: F." . __FUNCTION__); }
- public function getItems($params = array()) { throw new Exception("Unimplemented - TODO: F." . __FUNCTION__); }// TODO: use ParseOgcQuery
- public function fetchItemRef(&$items) { throw new Exception("Unimplemented - TODO: F." . __FUNCTION__); }// TODO: , $fieldName = ''
- public function fetchItemFieldRefs($primaryKey, $fieldName) {
- $refTable = Core_AclHelper::getRefTable($this->getName(), $fieldName);
- $sqlPk = DB::getPDO()->quote($primaryKey, PDO::PARAM_STR);
- return array_map(
- function ($row) {
- return [
- 'xlink' => "{$row['REMOTE_TYPENAME']}.{$row['REMOTE_PRIMARY_KEY']}" // TODO:
- ];
- }
- , DB::getPDO()->fetchAll("
- select r.REMOTE_PRIMARY_KEY, r.REMOTE_TYPENAME
- from `{$refTable}` r
- where r.PRIMARY_KEY = {$sqlPk}
- and r.A_STATUS != 'DELETED'
- ")
- );
- }
- public function addItem($itemTodo) { throw new Exception("Unimplemented - TODO: " . get_class($this) . "::" . __FUNCTION__); }
- public function updateItem($itemPatch) { throw new Exception("Unimplemented - TODO: F." . __FUNCTION__); }
- public function getGeomFieldType($fieldName) { return null; }
- public function getPrimaryKeyField() { return $this->_primaryKey; }
- public function getSqlPrimaryKeyField() {
- return (!empty($this->_simpleSchema['root'][$this->_primaryKey]['@alias']))
- ? $this->_simpleSchema['root'][$this->_primaryKey]['@alias']
- : $this->_primaryKey;
- }
- public function getSqlFieldName($fieldName) {
- if (empty($this->_simpleSchema['root'][$fieldName])) throw new Exception("Missing field in schema '{$fieldName}'");
- return (!empty($this->_simpleSchema['root'][$fieldName]['@alias']))
- ? $this->_simpleSchema['root'][$fieldName]['@alias']
- : $fieldName;
- }
- public function getID() { return 0; }
- public function getAttributesFromZasoby() { return array(); }
- public function isEnumerationField($fieldName) { return false; }
- public function getEnumerations($fieldName) { return null; }
- public function getXsdFieldType($fieldName) {
- $xsdTypes = $this->getXsdTypes();
- if (empty($xsdTypes[$fieldName])) throw new Exception("Field '{$fieldName}' not exists");
- return $xsdTypes[$fieldName]['xsdType'];
- }
- public function isGeomField($fieldName) {
- if ('File' == $fieldName) return false;
- if ('AccessGroupRead' == $fieldName) return false;
- if ('AccessGroupWrite' == $fieldName) return false;
- if ('AccessOwner' == $fieldName) return false;
- // if ('NestedObjectTest' == $fieldName) return false;
- // return $this->parentAcl->isGeomField($fieldName);
- }
- public function generateSqlSelectFromRootTable($prefix = 't') {
- $sqlSelect = [];
- foreach ($this->_simpleSchema['root'] as $key => $field) {
- if ('@' == substr($key, 0, 1)) continue;// skip attr
- if (!empty($field['@ref'])) continue;// skip ref
- if (empty($field['@type'])) continue;// skip wrong simpleType structure - BUG
- if ('xsd:' != substr($field['@type'], 0, 4)) continue;// skip non xsd types - eg. p5:typeSpecialSimpleLink
- $sqlField = (!empty($field['@alias'])) ? $field['@alias'] : $key;
- $sqlSelect[] = "{$prefix}.`{$sqlField}` as `$key`";
- }
- return implode("\n, ", $sqlSelect);
- }
- public function getXsdFieldParam($fieldName, $paramKey) {
- if (empty($this->_simpleSchema['root'][$fieldName])) return null;
- if (empty($this->_simpleSchema['root'][$fieldName]['@@params'])) return null;
- if (empty($this->_simpleSchema['root'][$fieldName]['@@params'][$paramKey])) return null;
- return $this->_simpleSchema['root'][$fieldName]['@@params'][$paramKey];
- }
- public function addP5Types(&$item) {
- DBG::_('DBG_ACL', '>1', "\$item", $item, __CLASS__, __FUNCTION__, __LINE__);
- $sqlSelect = [];
- foreach ($this->_simpleSchema['root'] as $key => $field) {
- if ('@' == substr($key, 0, 1)) continue;// skip attr
- if (empty($field['@type'])) continue;// skip ref
- if ('p5:' != substr($field['@type'], 0, 3)) continue;// skip non p5 types
- $fieldName = $key;
- $item[$fieldName] = '';
- switch ($field['@type']) {
- case 'p5:typeSpecialSimpleLink': {
- // '@@params' => [// $acl->getXsdFieldParam($col, 'format');
- // 'format' => '<a href="https://www.youtube.com/watch?v={LINK}" target="_blank"></a>',
- // 'aliasMap' => [
- // 'LINK' => 'LINK'
- // ]
- // ]
- $link = $this->getXsdFieldParam($fieldName, 'format');
- // $.each(_fieldProps._tsSimpleLink.aliasMap, function(i, v) {
- // //console.log('simpleLink aliasMap columnName:', columnName, 'i:', i, 'v:', v, 'props['+v+']', props[v], 'val', val, 'typeof val', typeof val);
- // if (undefined !== row[v]) {
- // valLink = valLink.replace(new RegExp('\{' + i + '\}', 'g'), row[v]);
- // }
- // });
- foreach ($this->getXsdFieldParam($fieldName, 'aliasMap') as $itemFieldName => $alias) {
- DBG::_('DBG_ACL', '>1', "aliasMap({$itemFieldName} => {$alias})", $item[$itemFieldName], __CLASS__, __FUNCTION__, __LINE__);
- $link = str_replace("{{$alias}}", $item[$itemFieldName], $link);
- }
- $item[$fieldName] = $link;
- } break;
- }
- }
- }
- public function fixParams(&$params) {// validate and fix params for getItem, getItems, etc. @see Api_WfsServerBase::parseGetFeatureArgsFromRequest()
- $params['cols'] = $this->parseParamCols($params['cols']);
- }
- public function parseParamCols($filterCols = []) {
- V::get('cols', [], $params);// wfs:propertyName
- if (empty($filterCols)) {// set default filter cols
- foreach ($this->_simpleSchema['root'] as $fieldName => $field) {
- if ('@' == substr($fieldName, 0, 1)) continue;
- if ('unbounded' == V::get('maxOccurs', '', $field)) continue;// TODO:?: default load only single value fields (skip maxOccurs="unbounded")?
- if (!empty($field['@type'])) {
- if ('xsd:' === substr($field['@type'], 0, 4)) $filterCols[$fieldName] = true;
- else if ('p5:' === substr($field['@type'], 0, 3)) $filterCols[$fieldName] = true;
- } else if (!empty($field['@ref'])) {
- $filterCols[$fieldName] = true;
- } else throw new Exception("Schema error for field '{$fieldName}' ns({$this->_namespace})");
- }
- }
- {// fix xpath for ref fields
- foreach ($filterCols as $fieldName => $bool) {
- $field = $this->_simpleSchema['root'][$fieldName];
- if (!empty($field['@ref'])) {
- $filterCols[$fieldName] = [];
- }
- }
- }
- return $filterCols;
- }
- public function buildFromSqlRow($row, $params = []) {
- $object = [];
- $filterCols = $this->parseParamCols($params['cols']);
- $object['_raw'] = $row;
- foreach ($this->_simpleSchema['root'] as $fieldName => $field) {
- if ('@' == substr($fieldName, 0, 1)) continue;
- if (!array_key_exists($fieldName, $filterCols)) continue;// only filter cols
- if (!empty($field['@type'])) {
- // UI::alert('warning', "TODO: field({$fieldName}) type({$field['@type']})");
- if ('xsd:' === substr($field['@type'], 0, 4)) {
- $sqlFieldName = (!empty($field['@alias'])) ? $field['@alias'] : $fieldName;
- $object[$fieldName] = V::get($sqlFieldName, '', $row);
- } else if ('p5:' === substr($field['@type'], 0, 3)) {
- $object[$fieldName] = "TODO: generate value for type {$field['@type']} - field '{$fieldName}' ns({$this->_namespace})";// TODO: single field method like addP5Types
- } else throw new Exception("Not Implemented type for field '{$fieldName}' ns({$this->_namespace})");
- } else if (!empty($field['@ref'])) {
- $object[$fieldName] = $this->fetchItemFieldRefs($primaryKey, $fieldName);
- } else throw new Exception("Schema error for field '{$fieldName}' ns({$this->_namespace})");
- }
- return $object;
- }
- }
|