Router::getRoute('Storage_AclStruct')->getLink('', [ 'namespace' => $namespace ]),
'class' => "btn btn-md btn-link",
], " Wróć do struktury"),
" | ",
UI::h('a', [
'href' => $this->getLink('viewXsdSource', [ 'namespace' => $namespace ]),
'class' => "btn btn-md btn-link",
'target' => "_blank",
], "Otwórz plik xsd (źródłowy)"),
]);
if ('reinstall' == V::get('_postTask', '', $_POST)) {
Lib::loadClass('Schema_SystemObjectFieldStorageAcl');
$objFieldAcl = new Schema_SystemObjectFieldStorageAcl();
$objFieldAcl->updateCache($namespace);
try {
$dbgInfo = [
'idInstance' => ACL::getInstanceId($namespace),
'rootInstance' => ACL::getRootNamespace($namespace),
'conf' => ACL::fetchInstanceConfig($namespace),
// 'table' => ACL::getInstanceTable($namespace), // Object structure not installed 'default_db/{tableName}'
];
DBG::nicePrint($dbgInfo, "dbg");
} catch (Exception $e) {
UI::alert('warning', $e->getMessage());
}
$item = SchemaFactory::loadDefaultObject('SystemObject')->getItem($namespace, [ 'propertyName' => '*,field' ]);
$childRefList = ACL::getChildRefFullList($namespace);
DBG::nicePrint($childRefList, '$childRefList');
DBG::nicePrint($item, '$item');
$activeFields = array_filter($item['field'], function ($field) {
return ($field['isActive'] > 0);
});
$fieldNsList = array_map(function ($field) {
return $field['fieldNamespace'];
}, $activeFields);
DBG::nicePrint($fieldNsList, '$fieldNsList');
if ('AntAcl' === $item['_type']) {
foreach ($childRefList as $childRef) { // [ namespace, A_STATUS ]
if ($childRef['A_STATUS'] !== 'DELETED' && !in_array($childRef['namespace'], $fieldNsList)) {
UI::alert('danger', "remove ref config for '{$childRef['namespace']}' ...");
if (!$childRef['ID']) throw new Exception("Missing ref config ID");
DB::getPDO()->update('CRM_REF_CONFIG', 'ID', $childRef['ID'], [
'A_STATUS' => 'DELETED',
'A_LAST_ACTION_DATE' => 'NOW()',
]);
}
else if ($childRef['A_STATUS'] !== 'DELETED' && in_array($childRef['namespace'], $fieldNsList)) {
UI::alert('info', "ref config for '{$childRef['namespace']}' active - OK");
}
else if ($childRef['A_STATUS'] === 'DELETED' && in_array($childRef['namespace'], $fieldNsList)) {
UI::alert('warning', "activate ref config for '{$childRef['namespace']}' ...");
if (!$childRef['ID']) throw new Exception("Missing ref config ID");
DB::getPDO()->update('CRM_REF_CONFIG', 'ID', $childRef['ID'], [
'A_STATUS' => 'NORMAL',
'A_LAST_ACTION_DATE' => 'NOW()',
]);
}
else if ($childRef['A_STATUS'] === 'DELETED' && !in_array($childRef['namespace'], $fieldNsList)) {
UI::alert('info', "ref config for '{$childRef['namespace']}' removed - OK");
}
else {
UI::alert('danger', "Not implemented action for '{$childRef['namespace']}'");
}
}
// TODO: create missing refConfig - field is not in $childRefList
}
if ('AntAcl' === $item['_type']) { // fix ref config by appInfo
$refFields = array_filter($item['field'], function ($field) {
return ('ref:' === substr($field['xsdType'], 0, 4));
});
DBG::log($refFields, 'array', "DBG \$refFields");
// analyze
$toMakeRefEvaluateByBackRef = false;
$toMakeRefAsView = false;
foreach ($refFields as $field) {
$fieldName = $field['fieldNamespace'];
$appInfo = ACL::decodeAppInfoJson($field['appInfo']);
DBG::log($appInfo, 'array', "DBG field({$fieldName}) \$appInfo");
// $appInfo['flat_relation_cache'] = [ ... ]
// $appInfo['flat_relation_cache'] = [ ... ]
// $appInfo['flat_relation_cache']['@backref_evaluate'] = 'true'
// $appInfo['flat_relation_cache']['source'] = [ ... ]
// $appInfo['flat_relation_cache']['source']['@name'] => 'krs'
// $appInfo['flat_relation_cache']['source']['@xpath'] => 'default_db__x3A__BI_audit_KRS:BI_audit_KRS/krs'
// $appInfo['flat_relation_cache']['source']['@ref_engine'] => 'view'
if (!empty($appInfo['flat_relation_cache'])) {
$flatCache = $appInfo['flat_relation_cache'];
if ('true' === V::get('@backref_evaluate', '', $flatCache)) {
$toMakeRefEvaluateByBackRef = true;
}
if (!empty($appInfo['flat_relation_cache']['source'])) {
$sourceInfo = $appInfo['flat_relation_cache']['source'];
if ('view' === V::get('@ref_engine', '', $sourceInfo)) {
$toMakeRefAsView = true;
}
}
}
}
// update ref config
if ($toMakeRefAsView && !$toMakeRefEvaluateByBackRef) {
UI::alert('danger', "TODO: set ref config to 'view' - field({$fieldName})");
}
if ($toMakeRefEvaluateByBackRef) { // $toMakeRefAsView nie ma znaczenia - czyta wg configa dla backRef
try {
$fieldRefConfRow = array_filter($childRefList, function ($childRef) use ($fieldName) {
return ($fieldName === $childRef['namespace']);
});
if (!$fieldRefConfRow) throw new Exception("Nie znaleziono konfiguracji dla powiązania {$fieldName}");
if (count($fieldRefConfRow) > 1) throw new Exception("BUG Znaleziono za dużo konfiguracji dla powiązania {$fieldName}");
$fieldRefConfRow = $fieldRefConfRow[0];
DBG::nicePrint($fieldRefConfRow, "\$fieldRefConfRow - TODO field({$fieldName})");
// [namespace] => default_db__x3A__BI_audit_KRS:BI_audit_KRS
// [A_STATUS] => NORMAL
// [ID] => 118
// [SOURCE] => view
$refTable = ACL::getRefTable($item['namespace'], $fieldName); // updates ref_config_table if needed
try {
$refSelect = ACL::generateRefSelectSqlByBackRef($item['namespace'], $fieldName);
ACL::setRefSource($item['namespace'], $fieldName, 'backRef', $refSelect);
} catch (Exception $e) {
DBG::log($e);
UI::alert('danger', $e->getMessage());
}
if ('backRef' !== $fieldRefConfRow['SOURCE']) {
ACL::updateChildRefSource($fieldRefConfRow['ID'], 'backRef');
}
} catch (Exception $e) {
UI::alert('danger', $e->getMessage());
}
}
}
{
if ('AntAcl' === $item['_type']) {
$dbName = DB::getPDO()->getDatabaseName();
$sqlFunBody = ACL::generateIsInstanceFunctionBody($namespace, $item);
DBG::nicePrint($sqlFunBody, "\$sqlFunBody");
$idInstance = ACL::getInstanceId($namespace);
DB::getPDO()->execSql(" DROP FUNCTION IF EXISTS `{$dbName}`.`isInstance_{$idInstance}` ");
// CREATE
// [DEFINER = { user | CURRENT_USER }]
// FUNCTION sp_name ([func_parameter[,...]])
// RETURNS type
// [characteristic ...] routine_body
DB::getPDO()->execSql("
CREATE DEFINER=`root`@`localhost`
FUNCTION `{$dbName}`.`isInstance_{$idInstance}` ( pk INT(11) )
RETURNS TINYINT(1)
{$sqlFunBody}
");
}
}
return;
}
echo UI::hButtonPost("Reinstall", [
'data' => [
'_postTask' => 'reinstall'
],
'class' => 'btn btn-md btn-danger',
'title' => "Reinstall structure"
]);
echo '
';
try {
$this->printReinstallPreview($namespace);
} catch (Exception $e) {
DBG::log($e);
UI::alert('danger', $e->getMessage());
}
} catch (Exception $e) {
UI::alert('danger', "Error #" . $e->getCode() . "|" . $e->getLine() . ": " . $e->getMessage());
DBG::log($e);
}
UI::endContainer();
UI::dol();
}
public function printReinstallPreview($namespace) {
$objectItem = SchemaFactory::loadDefaultObject('SystemObject')->getItem($namespace, [ 'propertyName' => "*,field" ]);
DBG::log($objectItem, 'array', '$objectItem preview');
switch ($objectItem['_type']) {
case 'AntAcl': $this->printReinstallAntAclPreview($objectItem); break;
case 'TableAcl': $this->printReinstallTableAclPreview($objectItem); break;
case 'StorageAcl': $this->printReinstallStorageAclPreview($objectItem); break;
default: throw new Exception("TODO: Not Implemented type '{$objectItem['_type']}'");
}
}
public function printReinstallAntAclPreview($item) {
Lib::loadClass('Schema_SystemObjectFieldStorageAcl');
$antAclPath = Schema_SystemObjectFieldStorageAcl::getAntAclXsdBasePath($item['typeName']);
if (!file_exists("{$antAclPath}/build.xml")) throw new Exception("Ant build file not exists");
Lib::loadClass('XML');
$xsdType = XML::getXsdTypeFromXsdSchema("{$antAclPath}/{$item['name']}.xsd", $namespace = $item['namespace'], $name = $item['name']);
DBG::nicePrint($item, '$item');
DBG::nicePrint($xsdType, '$xsdType');
echo '
';
echo UI::h('h3', [], "Lista zmian:");
echo ($item['primaryKey'] != $xsdType['primaryKey'])
? UI::h('p', [ 'style' => "" ], "@primaryKey - zmiana z '{$item['primaryKey']}' na '{$xsdType['primaryKey']}'")
: UI::h('p', [ 'style' => "font-style:italic; color:silver" ], "@primaryKey - bez zmian");
if (empty($xsdType['struct'])) throw new Exception("Field list not found for '{$item['namespace']}'");
foreach ($xsdType['struct'] as $fieldName => $x) {
$listEnum = [];
if (!empty($x['restrictions']['enumeration'])) {
$listEnum = $x['restrictions']['enumeration'];
unset($x['restrictions']['enumeration']);
}
if (!empty($listEnum)) {
DBG::log($listEnum, 'array', "\$listEnum for field '{$fieldName}'");
}
}
$old = [
'fields' => array_map(function ($field) { return $field['fieldNamespace']; }, $item['field']),
];
$new = [
'fields' => array_keys($xsdType['struct']),
];
sort($old['fields']);
sort($new['fields']);
$diffFieldsToCreate = array_diff($new['fields'], $old['fields']);
$diffFieldsToRemove = array_diff($old['fields'], $new['fields']);
$sameFields = array_intersect($new['fields'], $old['fields']);
echo (!empty($diffFieldsToCreate))
? UI::h('details', [ 'open' => "open" ], [
UI::h('summary', [], "Pola do dodania (".count($diffFieldsToCreate)."):"),
UI::h('ul', [], array_map(function ($fieldName) {
return UI::h('li', [], $fieldName);
}, $diffFieldsToCreate)),
])
: UI::h('p', [ 'style' => "font-style:italic; color:silver" ], "Brak pól do dodania");
echo (!empty($diffFieldsToRemove))
? UI::h('details', [ 'open' => "open", 'style' => "margin:4px 0; color:#8a6d3b; background-color:#fcf8e3; border:1px solid #faebcc;" ], [
UI::h('summary', [ 'style' => "padding:4px; outline:none; cursor:pointer" ], "Pola do usunięcia (".count($diffFieldsToRemove)."):"),
UI::h('ul', [], array_map(function ($fieldName) {
return UI::h('li', [], $fieldName);
}, $diffFieldsToRemove)),
])
: UI::h('p', [ 'style' => "font-style:italic; color:silver" ], "Brak pól do usunięcia");
foreach ($sameFields as $fieldName) {
// UI::alert('warning', "TODO: is field changed? '{$fieldName}'");
$oldField = array_filter($item['field'], function ($field) use ($fieldName) { return ( $fieldName === $field['fieldNamespace'] ); });
$oldField = ($oldField) ? reset($oldField) : null;
// DBG::nicePrint($oldField, "\$oldField '$fieldName'");
$newField = $xsdType['struct'][$fieldName];
// DBG::nicePrint($newField, "\$newField '$fieldName'");
$fieldDiff = [];
if ($newField['type'] !== $oldField['xsdType']) $fieldDiff[] = 'xsdType';
if ($newField['minOccurs'] != $oldField['minOccurs']) $fieldDiff[] = 'minOccurs';
if ($newField['maxOccurs'] != $oldField['maxOccurs']) $fieldDiff[] = 'maxOccurs';
if (json_encode($newField['restrictions']) !== $oldField['xsdRestrictions']) $fieldDiff[] = 'xsdRestrictions';
if (json_encode($newField['appInfo']) !== $oldField['appInfo']) $fieldDiff[] = 'appInfo';
echo (!empty($fieldDiff))
? UI::h('p', [ 'style' => "" ], "Pole '{$fieldName}' - zmiany: " . implode(", ", $fieldDiff))
: UI::h('p', [ 'style' => "font-style:italic; color:silver" ], "Pole '{$fieldName}' - bez zmian");
}
}
public function printReinstallTableAclPreview($item) {
throw new Exception("TODO: Podgląd zmian dla tabeli {$item['namespace']} ...");
}
public function printReinstallStorageAclPreview($item) {
DBG::nicePrint($item, '$item');
$acl = SchemaFactory::loadDefaultObject($item['name']);
DBG::nicePrint($acl, '$acl');
$xsdType = [
'primaryKey' => $acl->getPrimaryKeyField(),
'struct' => $acl->getFieldsWithXsdTypes()
];
DBG::nicePrint($xsdType, '$xsdType');
echo '
';
echo UI::h('h3', [], "Lista zmian:");
echo ($item['primaryKey'] != $xsdType['primaryKey'])
? UI::h('p', [ 'style' => "" ], "@primaryKey - zmiana z '{$item['primaryKey']}' na '{$xsdType['primaryKey']}'")
: UI::h('p', [ 'style' => "font-style:italic; color:silver" ], "@primaryKey - bez zmian");
if (empty($xsdType['struct'])) throw new Exception("Field list not found for '{$item['namespace']}'");
foreach ($xsdType['struct'] as $fieldName => $x) {
$listEnum = [];
if (!empty($x['restrictions']['enumeration'])) {
$listEnum = $x['restrictions']['enumeration'];
unset($x['restrictions']['enumeration']);
}
if (!empty($listEnum)) {
DBG::log($listEnum, 'array', "\$listEnum for field '{$fieldName}'");
}
}
$old = [
'fields' => array_map(function ($field) { return $field['fieldNamespace']; }, $item['field']),
];
$new = [
'fields' => array_keys($xsdType['struct']),
];
sort($old['fields']);
sort($new['fields']);
$diffFieldsToCreate = array_diff($new['fields'], $old['fields']);
$diffFieldsToRemove = array_diff($old['fields'], $new['fields']);
$sameFields = array_intersect($new['fields'], $old['fields']);
echo (!empty($diffFieldsToCreate))
? UI::h('details', [ 'open' => "open" ], [
UI::h('summary', [], "Pola do dodania (".count($diffFieldsToCreate)."):"),
UI::h('ul', [], array_map(function ($fieldName) {
return UI::h('li', [], $fieldName);
}, $diffFieldsToCreate)),
])
: UI::h('p', [ 'style' => "font-style:italic; color:silver" ], "Brak pól do dodania");
echo (!empty($diffFieldsToRemove))
? UI::h('details', [ 'open' => "open", 'style' => "margin:4px 0; color:#8a6d3b; background-color:#fcf8e3; border:1px solid #faebcc;" ], [
UI::h('summary', [ 'style' => "padding:4px; outline:none; cursor:pointer" ], "Pola do usunięcia (".count($diffFieldsToRemove)."):"),
UI::h('ul', [], array_map(function ($fieldName) {
return UI::h('li', [], $fieldName);
}, $diffFieldsToRemove)),
])
: UI::h('p', [ 'style' => "font-style:italic; color:silver" ], "Brak pól do usunięcia");
foreach ($sameFields as $fieldName) {
// UI::alert('warning', "TODO: is field changed? '{$fieldName}'");
$oldField = array_filter($item['field'], function ($field) use ($fieldName) { return ( $fieldName === $field['fieldNamespace'] ); });
$oldField = ($oldField) ? reset($oldField) : null;
// DBG::nicePrint($oldField, "\$oldField '$fieldName'");
$newField = $xsdType['struct'][$fieldName];
// DBG::nicePrint($newField, "\$newField '$fieldName'");
$fieldDiff = [];
if ($newField['type'] !== $oldField['xsdType']) $fieldDiff[] = 'xsdType';
if ($newField['minOccurs'] != $oldField['minOccurs']) $fieldDiff[] = 'minOccurs';
if ($newField['maxOccurs'] != $oldField['maxOccurs']) $fieldDiff[] = 'maxOccurs';
if (json_encode($newField['restrictions']) !== $oldField['xsdRestrictions']) $fieldDiff[] = 'xsdRestrictions';
if (json_encode($newField['appInfo']) !== $oldField['appInfo']) $fieldDiff[] = 'appInfo';
echo (!empty($fieldDiff))
? UI::h('p', [ 'style' => "" ], "Pole '{$fieldName}' - zmiany: " . implode(", ", $fieldDiff))
: UI::h('p', [ 'style' => "font-style:italic; color:silver" ], "Pole '{$fieldName}' - bez zmian");
}
}
public function viewXsdSourceAction() {
try {
$namespace = V::get('namespace', '', $_GET);
if (empty($namespace)) throw new Exception("Missing param namespace");
$objectItem = SchemaFactory::loadDefaultObject('SystemObject')->getItem($namespace, [ 'propertyName' => "*,field" ]);
switch ($objectItem['_type']) {
case 'AntAcl': $this->viewXsdSource($objectItem); break;
// case 'TableAcl': $this->viewXsdSource($objectItem); break;
default: throw new Exception("TODO: Not Implemented type '{$objectItem['_type']}'");
}
} catch (Exception $e) {
DBG::log($e);
echo "Error #" . $e->getCode() . "|" . $e->getLine() . ": " . $e->getMessage();
}
}
function viewXsdSource($objectItem) {
if (empty($objectItem)) throw new Exception("Missing objectItem in viewXsdSource");
DBG::log($objectItem, "viewXsdSource \$objectItem");
Lib::loadClass('Schema_SystemObjectFieldStorageAcl');
$antAclPath = Schema_SystemObjectFieldStorageAcl::getAntAclXsdBasePath($objectItem['typeName']);
if (!file_exists("{$antAclPath}/build.xml")) throw new Exception("Ant build file not exists");
DBG::log(str_replace(APP_PATH_ROOT, '~', $antAclPath), "viewXsdSource \$antAclPath");
$xsdFile = "{$antAclPath}/{$objectItem['name']}.xsd";
if (!file_exists($xsdFile)) throw new Exception("Xsd file not exists");
DBG::log(str_replace(APP_PATH_ROOT, '~', $xsdFile), "viewXsdSource \$xsdFile");
header('Content-Type: application/xml; charset=utf-8');
$fd = fopen($xsdFile, 'r');
fpassthru($fd);
exit;
}
}