Compare commits

..

8 Commits

Author SHA1 Message Date
Anne-Cath
3ff97be963 use new method GetOwnerOrganizationAttCode in Attachment
+ test
2024-12-16 15:42:47 +01:00
Anne-Cath
add7743b6f Add tests 2024-12-16 15:27:28 +01:00
Anne-Cath
2415d3d5d3 Add tests 2024-12-16 14:56:23 +01:00
Anne-Cath
77989b6bd8 Add tests 2024-12-16 14:55:56 +01:00
Anne-Cath
f26ed0ea71 indentation 2024-12-16 14:17:26 +01:00
Anne-Cath
309b6bd900 Replace UserRightsProfile::GetOwnerOrganizationAttCode($sClass) by UserRights::GetOwnerOrganizationAttCode($sClass) 2024-12-09 10:53:09 +01:00
Anne-Cath
83f1476de4 Refactor
+ use new function in Attachment
2024-11-25 15:22:35 +01:00
Anne-Cath
c2d0c310a9 N°7963 - Inlineimage::SetDefaultOrgId blend field name between Person and linked class 2024-11-13 11:17:35 +01:00
3261 changed files with 230241 additions and 207786 deletions

99
.doc/README.md Normal file
View File

@@ -0,0 +1,99 @@
# Phpdoc dokuwiki template
This directory contains a template for rendering iTop phpdoc as dokuwiki pages.
Conventional tags that you should use:
* `@internal` : exclude from the documentation.
* `@api` : it means that a method is an api, thus it may be interacted with.
* `@see` : it points to another documented method
* `@link` : external url
* if you point to another page of the wiki, please use relative links.
* `@example` : let you provide example of code
* `@param`, `@return`, `@throws`, ...
## Special instructions
Some iTop specific tags were added :
* `@api-advanced`: it means that a method is an `@api` but mark it also as "complex" to use
* `@overwritable-hook`: used to mark a method as "designed to be extended"
* `@extension-hook`: not used for now
* `@phpdoc-tuning-exclude-inherited`: once this tag is present on a class, it's inherited methods won't be showed.
### known limitations:
#### `@see` tags must be very specific:
* always prefix class members (attributes or methods) with `ClassName::` (do not use self)
* for methods always suffix them with `()`,
* do not reference variables since they are not documented. If you have to, always prefix them with `$`
examples:
```
/**
* @see DBObject
* @see DBObject::Get()
* @see DBObject::$foo
*/
```
#### Do not use inline tags, they do not work properly, example:
```
/**
* This is a texts with an inline tag {@see [FQSEN] [<description>]} it must never be used
*/
```
#### The `@example` tag must respect this very precise syntax
* the sentence in the first line (next to the tag) is the title, it must be enclosed by double quotes
* the following lines are the sample code.
* 💔 since we simply hack the official tag, this syntax must be respected carefully 💔
example:
```
/**
* @example "This is the title of the multiline example"
* $foo = DBObject::Get('foo');
* DBObject::Set('foo', ++$foo);
*/
```
## How content is included into the documentation
**For a class** those requirements have to be respected:
- the file containing the class must be listed in `/phpdoc/files/file[]` of `.doc/phpdoc-objects-manipulation.dist.xml`
- the class **must not** have the tag `@internal`
- the class **must** have at least one of: `@api`, `@api-advanced`, `@overwritable-hook`, `@extension-hook`
Then, **for a method** of an eligible class:
- **public** methods **must** have at least one of: `@api`, `@api-advanced`, `@overwritable-hook`, `@extension-hook`
- **protected** methods **must** have at least one of: `@overwritable-hook`, `@extension-hook`
- **private** methods are **always excluded**
**Class properties** and **constants** are never documented (this is subject to change).
## A note about the rendering engine
:notebook: as spaces are used to mark code, the templates (`.doc/phpdoc-templates/combodo-wiki/*`) have very few indentation, thus they are awful to read (sorry).
## Installation
```
cd .doc
composer require phpdocumentor/phpdocumentor:~2 --dev
```
## Generation
1. Switch to this directory : `cd /path/to/itop/.doc`
2. `composer install`
3. `./bin/build-doc-object-manipulation`
3. `./bin/build-doc-extensions`
4. Get the generated files from `/path/to/itop/data/phpdocumentor/output`
## Dokuwiki requirements
* the template uses the [wrap plugin](https://www.dokuwiki.org/plugin:wrap).
* the generated files have to be placed under an arbitrary directory of `[/path/to/dokuwiki]/data/pages`.
* the html has to be activated [config:htmlok](https://www.dokuwiki.org/config:htmlok)
* the generated files have to be in lowercase

6
.doc/bin/build-doc-extensions Executable file
View File

@@ -0,0 +1,6 @@
#!/bin/sh -x
rm -rf /tmp/phpdoc-twig-cache/ && rm -rf data/phpdocumentor/output/extensions/ && rm -rf data/phpdocumentor/temp/extensions/ && ./vendor/bin/phpdoc -c ./phpdoc-extensions.dist.xml -vvv
# now wee need to lowercase every generated file because dokuwiki can't handle uppercase
cd ../data/phpdocumentor/output/extensions/ && for i in $(ls | grep [A-Z]); do mv -i $i $(echo $i | tr 'A-Z' 'a-z'); done

View File

@@ -0,0 +1,7 @@
#!/bin/sh -x
rm -rf /tmp/phpdoc-twig-cache/ && rm -rf ../data/phpdocumentor/output/objects-manipulation/ && rm -rf ../data/phpdocumentor/temp/objects-manipulation/ && ./vendor/bin/phpdoc -c ./phpdoc-objects-manipulation.dist.xml -vvv
# now wee need to lowercase every generated file because dokuwiki can't handle uppercase
cd ../data/phpdocumentor/output/objects-manipulation/ && for i in $( ls | grep [A-Z] ); do mv -i $i `echo $i | tr 'A-Z' 'a-z'`; done

6
.doc/composer.json Normal file
View File

@@ -0,0 +1,6 @@
{
"require-dev": {
"phpdocumentor/phpdocumentor": "~2",
"jms/serializer": "1.7.*"
}
}

3015
.doc/composer.lock generated Normal file

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 983 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 MiB

View File

@@ -0,0 +1,98 @@
# iTop version history
```mermaid
%%{init: { 'logLevel': 'debug', 'theme': 'base', 'themeVariables': {
'git0': 'lawngreen',
'git3': 'dodgerblue',
'git4': 'grey',
'git5': 'grey',
'git6': 'grey',
'git7': 'grey'
}, 'gitGraph': {'showBranches': true,'mainBranchName': 'develop','rotateCommitLabel': true}} }%%
gitGraph
commit id: "2016-07-06" tag: "2.3.0" type: HIGHLIGHT
branch support/2.3 order: 900
commit id: "2016-07-08" tag: "2.3.1"
commit id: "2016-12-22" tag: "2.3.3"
commit id: "2017-04-14" tag: "2.3.4"
checkout develop
commit id: "2017-07-12" tag: "2.4.0-beta" type: REVERSE
commit id: "2017-11-16" tag: "2.4.0" type: HIGHLIGHT
branch support/2.4 order: 890
commit id: "2018-02-14" tag: "2.4.1"
checkout develop
commit id: "2018-04-25" tag: "2.5.0-beta" type: REVERSE
checkout support/2.4
commit id: "2018-06-14" tag: "2.4.2"
checkout develop
commit id: "2018-06-27" tag: "2.5.0" type: HIGHLIGHT
branch support/2.5 order: 880
checkout develop
commit id: "2019-01-09" tag: "2.6.0" type: HIGHLIGHT
branch support/2.6 order: 870
commit id: "2019-03-28" tag: "2.6.1"
checkout develop
commit id: "2019-12-18" tag: "2.7.0-beta" type: REVERSE
checkout support/2.5
commit id: "2020-01-22" tag: "2.5.4"
checkout support/2.6
commit id: "2020-01-23" tag: "2.6.3"
checkout develop
commit id: "2020-01-29" tag: "2.7.0-beta2" type: REVERSE
commit id: "2020-04-01" tag: "2.7.0-1" type: HIGHLIGHT
checkout support/2.6
commit id: "2020-04-22" tag: "2.6.4"
checkout develop
branch support/2.7 order: 860
commit id: "2020-06-26" tag: "2.7.1"
checkout support/2.7
commit id: "2020-12-09" tag: "2.7.3"
commit id: "2021-03-31" tag: "2.7.4"
checkout develop
commit id: "2021-04-06" tag: "3.0.0-beta" type: REVERSE
checkout support/2.7
commit id: "2021-07-05" tag: "2.7.5"
checkout develop
commit id: "2021-07-05." tag: "3.0.0-beta2" type: REVERSE
checkout support/2.7
commit id: "2021-12-17" tag: "2.7.6"
checkout develop
commit id: "2022-01-04" tag: "3.0.0" type: HIGHLIGHT
branch support/3.0 order: 850
commit id: "2022-04-08" tag: "3.0.1"
checkout support/2.7
commit id: "2022-07-11" tag: "2.7.7"
checkout support/3.0
commit id: "2022-09-12" tag: "3.0.2-1"
checkout develop
checkout support/2.7
commit id: "2022-12-28" tag: "2.7.8"
checkout support/3.0
commit id: "2023-04-12" tag: "3.0.3"
checkout develop
commit id: "2023-06-19" tag: "3.1.0-beta" type: REVERSE
commit id: "2023-07-26" tag: "3.1.0-1" type: HIGHLIGHT
branch support/3.1 order: 840
checkout support/3.1
commit id: "2023-08-09" tag: "3.1.0-2"
checkout support/2.7
commit id: "2023-08-10" tag: "2.7.9"
checkout support/3.1
commit id: "2023-12-20" tag: "3.1.1"
checkout develop
commit id: "2024-01-15" tag: "Start 3.2" type: HIGHLIGHT
branch support/3.2 order: 830
checkout support/2.7
commit id: "2024-01-17a" tag: "2.7.10"
checkout support/3.0
commit id: "2024-01-17b" tag: "3.0.4"
checkout support/2.7
commit id: "2024-09-28" tag: "2.7.11"
checkout support/3.1
commit id: "2024-09-27" tag: "3.1.2"
checkout support/3.2
commit id: "2024-06-25" tag: "3.2.0-beta1" type: REVERSE
commit id: "2024-08-07" tag: "3.2.0"
```
To learn more, check the [iTop community versions history on the official wiki](https://www.itophub.io/wiki/page?id=latest:release:start).

20
.doc/phpdoc-extensions.dist.xml Executable file
View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8" ?>
<phpdoc>
<title><![CDATA[iTop extensions]]></title>
<parser>
<target>../data/phpdocumentor/temp/extensions</target>
</parser>
<transformer>
<target>../data/phpdocumentor/output/extensions</target>
</transformer>
<transformations>
<template name="phpdoc-templates/combodo-wiki"/>
</transformations>
<files>
<file>../application/applicationextension.inc.php</file>
</files>
</phpdoc>

View File

@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8" ?>
<phpdoc>
<!--
/**
The documentation of this file can be found here : https://docs.phpdoc.org/references/configuration.html
it has to be completed by the CLI parameters documentation which is more comprehensive: https://docs.phpdoc.org/references/commands/project_run.html#usage
usage:
vendor/bin/phpdoc -c phpdoc-objects-manipulation.dist.xml
*/
-->
<title><![CDATA[iTop's objects manipulation API]]></title>
<parser>
<default-package-name>iTopORM</default-package-name>
<target>../data/phpdocumentor/temp/objects-manipulation</target>
<visibility>public,protected</visibility>
<markers>
<!--<item>TODO</item>-->
<!--<item>FIXME</item>-->
</markers>
<extensions>
<extension>php</extension>
</extensions>
</parser>
<transformer>
<target>../data/phpdocumentor/output/objects-manipulation</target>
</transformer>
<transformations>
<template name="phpdoc-templates/combodo-wiki"/>
</transformations>
<!--<logging>-->
<!--<level>warn</level>-->
<!--<paths>-->
<!--&lt;!&ndash;<default>data/phpdocumentor/log/objects-manipulation/{DATE}.log</default>&ndash;&gt;-->
<!--&lt;!&ndash;<errors>data/phpdocumentor/log/objects-manipulation/{DATE}.errors.log</errors>&ndash;&gt;-->
<!--<default>{APP_ROOT}/data/log/{DATE}.log</default>-->
<!--<errors>{APP_ROOT}/data/log/{DATE}.errors.log</errors>-->
<!--</paths>-->
<!--</logging>-->
<files>
<file>../core/dbobject.class.php</file>
<file>../core/dbobjectsearch.class.php</file>
<file>../core/metamodel.class.php</file>
<file>../core/dbobjectset.class.php</file>
<file>../core/dbsearch.class.php</file>
<file>../core/dbunionsearch.class.php</file>
</files>
</phpdoc>

View File

View File

@@ -0,0 +1,136 @@
{% extends 'layout.txt.twig' %}
{% block content %}
<wrap button>[[start|🔙 Back]]</wrap>
{% if node.tags['internal'] is defined %}
====== {{ node.name }} ======
<WRAP alert>This class is "internal", and thus is not documented!</WRAP>
{% elseif node.tags['api'] is not defined and node.tags['api-advanced'] is not defined and node.tags['overwritable-hook'] is not defined and node.tags['extension-hook'] is not defined %}
====== {{ node.name }} ======
<WRAP alert>This class is neither "api", "api-advanced", "overwritable-hook" or "extension-hook", and thus is not documented!</WRAP>
{% else %}
====== {{ node.name }} ======
{% if node.deprecated %}<wrap danger>deprecated</wrap>{% endif %}
{% if node.abstract %}<wrap warning>abstract</wrap>{% endif %}
{% if node.final %}<wrap notice>final</wrap>{% endif %}
{% include 'includes/wrap-tags.txt.twig' with {structure:node, wrap: 'safety', wrapTags: ['api', 'api-advanced', 'overwritable-hook', 'extension-hook']} %}
{% if node.deprecated %}
=== **<del>Deprecated</del>**===
//{{ node.tags.deprecated[0].description }}//
{% endif %}
== {{ node.summary|replace({"\n":""})|raw }} ==
<html>{{ node.description|markdown|raw }}</html>
{% include 'includes/code-examples.txt.twig' with {structure:node, title_level: '====='} %}
{% set class = node.parent %}
{% block hierarchy_element %}
{% if class and class.name is defined and class.name|trim != '' %}
==== parent ====
{% set child = class %}
{% set class = class.parent %}
{{ block('hierarchy_element') }}
[[{{ child.name }}|{{ child.name }}]]
{% endif %}
{% endblock %}
{% for interface in node.interfaces|sort_asc %}
{% if loop.first %}
==== Implements ====
{% endif %}
{% if loop.length > 1 %} * {% endif %}{{ interface.fullyQualifiedStructuralElementName ?: interface }}
{% endfor %}
{% for trait in node.usedTraits|sort_asc %}
{% if loop.first %}
==== Uses traits ====
{% endif %}
{% if loop.length > 1 %} * {% endif %}{{ trait.fullyQualifiedStructuralElementName ?: trait }}
{% endfor %}
{% include 'includes/see-also.txt.twig' with {structure:node, title_level: '==='} %}
{% include 'includes/tags.txt.twig' with {structure:node, title_level: '=====', blacklist: ['link', 'see', 'abstract', 'example', 'method', 'property', 'property-read', 'property-write', 'package', 'subpackage', 'phpdoc-tuning-exclude-inherited', 'api', 'api-advanced', 'overwritable-hook', 'extension-hook', 'copyright', 'license', 'code-example']} %}
{% set methods = node.inheritedMethods.merge(node.methods.merge(node.magicMethods)) %}
{% include 'includes/tag-synthesys.txt.twig' with {methods:methods, tag:'api'} %}
{% include 'includes/tag-synthesys.txt.twig' with {methods:methods, tag:'api-advanced'} %}
{% include 'includes/tag-synthesys.txt.twig' with {methods:methods, tag:'overwritable-hook'} %}
{% include 'includes/tag-synthesys.txt.twig' with {methods:methods, tag:'extension-hook'} %}
{% include 'includes/code-examples.txt.twig' with {structure:node, title_level: '=====', sub_title_level: '=='} %}
<WRAP clear />
{% for method in methods|sort_asc
if method.visibility == 'public'
and (
method.tags['api'] is defined
or method.tags['api-advanced'] is defined
or method.tags['overwritable-hook'] is defined
or method.tags['extension-hook'] is defined
)
and (
node.tags['phpdoc-tuning-exclude-inherited'] is not defined
or method.parent.name == node.name
)
%}
{%- if loop.first %}
===== Public methods =====
{% endif %}
{{ block('method') }}
{% endfor %}
{% for method in methods|sort_asc if method.visibility == 'protected' and (method.tags['overwritable-hook'] is defined or method.tags['extension-hook'] is defined) %}
{%- if loop.first %}
===== Protected methods =====
{% endif %}
{{ block('method') }}
{% endfor %}
{% set constants = node.inheritedConstants.merge(node.constants) %}
{% if constants|length > 0 %}
===== Constants =====
{% for constant in constants|sort_asc %}
{{ block('constant') }}
{% endfor %}
{% endif %}
{#{% set properties = node.inheritedProperties.merge(node.properties.merge(node.magicProperties)) %}#}
{#{% for property in properties|sort_asc if property.visibility == 'public' %}#}
{#{%- if loop.first %}#}
{#===== Public properties =====#}
{#{% endif %}#}
{#{{ block('property') }}#}
{#{% endfor %}#}
{#{% for property in properties|sort_asc if property.visibility == 'protected' %}#}
{#{%- if loop.first %}#}
{#===== Protected properties =====#}
{#{% endif %}#}
{#{{ block('property') }}#}
{#{% endfor %}#}
{%- endif %} {#{% elseif node.tags['xxx'] is not defined and ... #}
<wrap button>[[start|🔙 Back]]</wrap>
{% endblock %}

View File

@@ -0,0 +1,31 @@
{% block constant %}
<WRAP group box >
<WRAP twothirds column >
==== {{ constant.name }} ====
</WRAP>{# twothirds column#}
<WRAP third column>
{% if constant.deprecated %}<wrap danger>deprecated</wrap> {% endif %}
{% if (node.parent is not null and constant.parent.fullyQualifiedStructuralElementName != node.fullyQualifiedStructuralElementName) %}<wrap notice>inherited</wrap> {% endif %}
</WRAP>{# third column#}
== {{ constant.summary|replace({"\n":""})|raw }} ==
<html>{{ constant.description|markdown|raw }}</html>
{% if constant.deprecated %}
=== Deprecated ===
{{ constant.tags.deprecated[0].description|raw }}
{% endif %}
{% include 'includes/inherited-from.txt.twig' with {structure:constant} %}
{% include 'includes/see-also.txt.twig' with {structure:constant, title_level: '=='} %}
{% include 'includes/uses.txt.twig' with {structure:constant, title_level: '=='} %}
{% include 'includes/tags.txt.twig' with {structure:constant, title_level: '==', blacklist: ['link', 'see', 'var', 'deprecated', 'uses', 'package', 'subpackage', 'todo', 'code-example']} %}
</WRAP>{# group #}
{% endblock %}

View File

@@ -0,0 +1,95 @@
{% block method %}
<WRAP group box >
<WRAP twothirds column >
==== {{ method.name }} ====
</WRAP>{# twothirds column#}
<WRAP third column >
{% include 'includes/wrap-tags.txt.twig' with {structure:method, wrap: 'safety', wrapTags: ['api', 'api-advanced', 'overwritable-hook', 'extension-hook']} %}
{% if method.deprecated %}<wrap danger>deprecated</wrap> {% endif %}
{% if (node.parent is not null and method.parent.fullyQualifiedStructuralElementName != node.fullyQualifiedStructuralElementName) %}<wrap notice>inherited</wrap> {% endif %}
{% if method.abstract %}<wrap warning>abstract</wrap> {% endif %}
{% if method.final %}<wrap notice>final</wrap> {% endif %}
<wrap notice>{{ method.visibility }}</wrap>
{% if method.static %}<wrap warning>static</wrap> {% endif %}
</WRAP>{# third column#}
== {{ method.summary|replace({"\n":""})|raw }} ==
<html>{{ method.description|markdown|raw }}</html>
<code php>{% if method.abstract %}abstract {% endif %}{% if method.final %}final {% endif %}{{ method.visibility }} {% if method.static %}static {% endif %}{{ method.name }}({% for argument in method.arguments %}{{ argument.isVariadic ? '...' }}{{ argument.name }}{{ argument.default ? (' = '~argument.default)|raw }}{% if not loop.last %}, {% endif %}{% endfor %})</code>
<WRAP twothirds column >
=== Parameters ===
{% if method.arguments|length > 0 -%}
^ types ^ name ^ default ^ description ^
{% for argument in method.arguments -%}
| **<nowiki>{{ argument.types|join('|')|raw }}</nowiki>** | {{ argument.name }} {{ argument.isVariadic ? '<small style="color: gray">variadic</small>' }} | <nowiki>{{ argument.default|raw }}</nowiki> | {{ argument.description|trim|replace("\n", ' ')|raw }} |{{ "\r\n" }}
{%- endfor %}
{% else %}
//none//
{% endif %}
{#=== Parameters ===#}
{#{% if method.arguments|length > 0 -%}#}
{#{% for argument in method.arguments -%}#}
{#== {{ argument.name }} ==#}
{#{% set varDesc %}#}
{#<span style="margin:0 10px; 0 20px; font-weight: bold;">{{ argument.types|join('|') }}</span>#}
{#{{ argument.isVariadic ? '<small style="color: gray">variadic</small>' }}#}
{#{{ argument.description|raw }}#}
{#{% endset %}#}
{#<html>{{ varDesc|markdown|raw }}</html>#}
{#{%- endfor %}#}
{#{% else %}#}
{#<wrap tip>This method has no parameter</wrap>#}
{#{% endif %}#}
{% if method.response and method.response.types|join() != 'void' %}
=== Returns ===
<html>{{ ('**' ~ method.response.types|join('|')|trim ~ '** ' ~ method.response.description)|markdown|raw }}</html>
{% endif %}
</WRAP>{# twothirds column#}
<WRAP third column >
{% if method.tags.throws|length > 0 or method.tags.throw|length > 0 %}
=== Throws ===
{% for exception in method.tags.throws -%}
{% if loop.length > 1 %} * {% endif %}''{{ exception.types|join('|')|raw }}'' <nowiki>{{ exception.description|raw }}</nowiki>
{% endfor %}
{% endif %}
{% include 'includes/inherited-from.txt.twig' with {structure:method} %}
{% include 'includes/see-also.txt.twig' with {structure:method, title_level: '==='} %}
{% include 'includes/uses.txt.twig' with {structure:method, title_level: '==='} %}
{% include 'includes/used-by.txt.twig' with {structure:method, title_level: '==='} %}
{% include 'includes/tags-with-description.txt.twig' with {structure:method, title_level: '===', WRAP: 'info', tagsWithDescription: ['api', 'api-advanced', 'overwritable-hook', 'extension-hook']} %}
{% include 'includes/tags.txt.twig' with {structure:method, title_level: '===', blacklist: ['todo', 'link', 'see', 'abstract', 'example', 'param', 'return', 'access', 'deprecated', 'throws', 'throw', 'uses', 'api', 'api-advanced', 'overwritable-hook', 'extension-hook', 'used-by', 'inheritdoc', 'code-example']} %}
</WRAP>{# third column#}
{% include 'includes/code-examples.txt.twig' with {structure:method, title_level: '==='} %}
</WRAP>{# group #}
{% endblock %}

View File

@@ -0,0 +1,49 @@
{% block property %}
<WRAP group box>
<WRAP twothirds column >
==== ${{ property.name }} ====
</WRAP>{# twothirds column#}
<WRAP third column>
{% if property.deprecated %}<wrap danger>deprecated</wrap> {% endif %}
{% if (node.parent is not null and property.parent.fullyQualifiedStructuralElementName != node.fullyQualifiedStructuralElementName) %}<wrap notice>inherited</wrap> {% endif %}
</WRAP>{# third column#}
== {{ property.summary|replace({"\n":""})|raw }} ==
<html>{{ property.description|markdown|raw }}</html>
{% if property.var.0.description %}<html>{{ property.var.0.description|markdown|raw }}</html>{% endif %}
{#{% if property.types %}#}
{#== Type ==#}
{#{% for type in property.types %}#}
{#{% if loop.length > 1 %} * {% endif %}{{ type|raw }} : {{ type.description|raw }}#}
{#{% endfor %}#}
{#{{ property.types|join('|')|raw }}#}
{#{% endif %}#}
{% if property.deprecated %}
== Deprecated ==
{{ property.tags.deprecated[0].description }}
{% endif %}
{% include 'includes/inherited-from.txt.twig' with {structure:property} %}
{% include 'includes/see-also.txt.twig' with {structure:property, title_level: '=='} %}
{% include 'includes/uses.txt.twig' with {structure:property, title_level: ''} %}
{% include 'includes/tags.txt.twig' with {structure:property, title_level: '==', blacklist: ['link', 'see', 'access', 'var', 'deprecated', 'uses', 'todo', 'code-example']} %}
<code php>{{ property.visibility }} ${{ property.name }}{% if property.types %} : {{ property.types|join('|')|raw }}{% endif %}</code>
</WRAP>{# group #}
{% endblock %}

View File

@@ -0,0 +1 @@
{{ node.source|raw }}

View File

@@ -0,0 +1,122 @@
{% extends 'layout.txt.twig' %}
{% block javascripts %}
{% endblock %}
{% block content %}
{#<section class="row-fluid">#}
{#<div class="span2 sidebar">#}
{#{% set namespace = project.namespace %}#}
{#{{ block('sidebarNamespaces') }}#}
{#</div>#}
{#</section>#}
{#<section class="row-fluid">#}
====== {{ node.path|split('/')|slice(0,-1)|join('/') }}{{ node.name }} ======
{{ node.summary }}
<html>{{ node.description|markdown|raw }}</html>
{% if node.traits|length > 0 %}
===== Traits =====
{% for trait in node.traits %}
<tr>
<td>{{ trait|raw }}</td>
<td><em>{{ trait.summary }}</em></td>
</tr>
{% endfor %}
{% endif %}
{% if node.interfaces|length > 0 %}
===== Interfaces =====
{% for interface in node.interfaces %}
<tr>
<td>{{ interface|raw }}</td>
<td><em>{{ interface.summary }}</em></td>
</tr>
{% endfor %}
{% endif %}
{% if node.classes|length > 0 %}
===== Classes =====
{% for class in node.classes %}
{{ class|raw }}
<em>{{ class.summary }}</em>
{% endfor %}
{% endif %}
{% if node.package is not empty and node.package != '\\' %}
===== Package =====
{{ node.subpackage ? (node.package ~ '\\' ~ node.subpackage) : node.package }}
{% endif %}
{% for tagName,tags in node.tags if tagName in ['link', 'see'] %}
{% if loop.first %}
===== See also =====
{% endif %}
{% for tag in tags %}
<dd><a href="{{ tag.reference ?: tag.link }}"><div class="namespace-wrapper">{{ tag.description ?: tag.reference }}</div></a></dd>
{% endfor %}
{% endfor %}
<h2>Tags</h2>
<table class="table table-condensed">
{% for tagName,tags in node.tags if tagName not in ['link', 'see', 'package', 'subpackage'] %}
<tr>
<th>
{{ tagName }}
</th>
<td>
{% for tag in tags %}
{{ tag.description|markdown|raw }}
{% endfor %}
</td>
</tr>
{% else %}
<tr><td colspan="2"><em>None found</em></td></tr>
{% endfor %}
</table>
</aside>
</div>
{% if node.constants|length > 0 %}
<div class="row-fluid">
<section class="span8 content file">
<h2>Constants</h2>
</section>
<aside class="span4 detailsbar"></aside>
</div>
{% for constant in node.constants %}
{{ block('constant') }}
{% endfor %}
{% endif %}
{% if node.functions|length > 0 %}
<div class="row-fluid">
<section class="span8 content file">
<h2>Functions</h2>
</section>
<aside class="span4 detailsbar"></aside>
</div>
{% for method in node.functions %}
{{ block('method') }}
{% endfor %}
{% endif %}
</div>
</section>
<div id="source-view" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="source-view-label" aria-hidden="true">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h3 id="source-view-label">{{ node.file.name }}</h3>
</div>
<div class="modal-body">
<pre data-src="{{ path('files/' ~ node.path ~ '.txt')|raw }}" class="language-php line-numbers"></pre>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,42 @@
{% extends 'layout.html.twig' %}
{% block stylesheets %}
<link href="{{ path('css/jquery.iviewer.css') }}" rel="stylesheet" media="all"/>
<style>
#viewer {
position: relative;
width: 100%;
}
.wrapper {
overflow: hidden;
}
</style>
{% endblock %}
{% block javascripts %}
<script src="{{ path('js/jquery.mousewheel.js') }}" type="text/javascript"></script>
<script src="{{ path('js/jquery.iviewer.js') }}" type="text/javascript"></script>
<script type="text/javascript">
$(window).resize(function(){
$("#viewer").height($(window).height() - 100);
});
$(document).ready(function() {
$("#viewer").iviewer({src: '{{ path('graphs/classes.svg') }}', zoom_animation: false});
$('#viewer img').bind('dragstart', function(event){
event.preventDefault();
});
$(window).resize();
});
</script>
{% endblock %}
{% block content %}
<div class="row-fluid">
<div class="span12">
<div class="wrapper">
<div id="viewer" class="viewer"></div>
</div>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,5 @@
# Fixes a vulnerability in CentOS: http://stackoverflow.com/questions/20533279/prevent-php-from-parsing-non-php-files-such-as-somefile-php-txt
<FilesMatch \.php\.txt$>
RemoveHandler .php
ForceType text/plain
</FilesMatch>

View File

@@ -0,0 +1,34 @@
{% if title_level is not defined %}
{%- set title_level = '==' -%}
{% endif %}
{% if sub_title_level is not defined %}
{%- set sub_title_level = title_level|slice(1) -%}
{% endif %}
{% if sub_title_level == '=' %}
{%- set sub_title_level = '' -%}
{% endif %}
{#{% for tagName,tags in structure.tags if tagName in ['code-example'] %}#}
{#{% if loop.first %}#}
{#{{title_level}} Examples {{title_level}}#}
{#{% endif %}#}
{#{% for tag in tags %}#}
{#{%- set descToken = tag.description|split("\n", 2) -%}#}
{#{%- set title = descToken[0] -%}#}
{#{%- set code = descToken[1] -%}#}
{#{{sub_title_level}} {{ title }} {{sub_title_level}}#}
{#<code php>{{ code|raw }}</code>#}
{#{% endfor %}#}
{#{% endfor %}#}
{% for tagName,tags in structure.tags if tagName in ['example'] %}
{% if loop.first %}
{{title_level}} Examples {{title_level}}
{% endif %}
{% for tag in tags %}
{{ sub_title_level }} {{ tag.filePath|escape }}{{ sub_title_level }}
<code php>{{ tag.description|raw }}</code>
{% endfor %}
{% endfor %}

View File

@@ -0,0 +1,12 @@
{% if title_level is not defined %}
{% set title_level='' %}
{% endif %}
{% if (node.parent is null) %}
{{title_level}} File {{ structure.path }} {{title_level}}
{% endif %}
{% if (node.parent is not null and structure.parent.fullyQualifiedStructuralElementName != node.fullyQualifiedStructuralElementName) %}
{{title_level}} Inherited from {{title_level}}
[[{{structure.parent}}|{{structure.parent}}]]
{% endif %}

View File

@@ -0,0 +1,26 @@
{% for structure in structures|sort_asc if structure.tags['internal'] is not defined and (structure.tags['api'] is defined or structure.tags['api-advanced'] is defined or structure.tags['overwritable-hook'] is defined or structure.tags['extension-hook'] is defined ) %}
{#{{ structure|raw }}#}
{% set structureName = structure|trim('\\', 'left') %}
<WRAP group box>
<WRAP twothirds column >
==== {{ structureName }} ====
</WRAP>{# twothirds column#}
<WRAP third column>
{% if structure.deprecated %}<wrap danger>deprecated</wrap>{% endif %}
{% if structure.abstract %}<wrap warning>abstract</wrap>{% endif %}
{% if structure.final %}<wrap notice>final</wrap>{% endif %}
{% if (node.parent is not null and structure.parent.fullyQualifiedStructuralElementName != node.fullyQualifiedStructuralElementName) %}<wrap notice>inherited</wrap> {% endif %}
{% include 'includes/wrap-tags.txt.twig' with {structure:structure, wrap: 'safety', wrapTags: ['api', 'api-advanced', 'overwritable-hook', 'extension-hook']} %}
</WRAP>{# third column#}
{{ structure.summary|raw }}
[[{{structureName}}|More information]]
</WRAP>{# group #}
{% endfor %}

View File

@@ -0,0 +1,26 @@
{% if title_level is not defined %}
{%- set title_level='==' -%}
{% endif %}
{% for tagName,tags in structure.tags if tagName in ['link', 'see'] %}
{% if loop.first %}
{{title_level}} See also {{title_level}}
{% endif %}
{% for tag in tags %}
{%- set linkTag = tag.reference|trim('\\', 'left') -%}
{% if not('()' in linkTag or '$' in linkTag or node.name in linkTag or '::' in linkTag ) %}
{%- set linkTag = linkTag|lower -%}
{% elseif node.name~'::' in linkTag %}
{%- set linkTag = linkTag|replace({(node.name~'::'): '#'})|lower -%}
{% elseif '::' in linkTag -%}
{%- set linkTag = linkTag|replace({'::': '#'})|lower -%}
{% else %}
{%- set linkTag = '#' ~ linkTag|lower -%}
{%- endif %}
{% if loop.length > 1 %} * {% endif %}{% if tag.reference is not empty -%}
[[{{linkTag}}|{{ (tag.reference)|trim('\\', 'left') }}]] {% if tag.description|trim is not empty %}: {{ tag.description|trim('\\', 'left') }} {% endif %}
{%- else -%}
{#{{ tag.description|trim('\\', 'left') }}#}
{% endif %}
{% endfor %}
{% endfor %}

View File

@@ -0,0 +1,56 @@
{% if tag is not defined -%}
{# Do not display @api if @api-advanced is also present #}
{%- set tag = "api" -%}
{%- endif %}
{% if hidden_by is not defined -%}
{# Do not display @api if @api-advanced is also present #}
{%- set hidden_by = {"api" : "api-advanced"} -%}
{%- endif %}
{% for method in methods|sort_asc
if (method.visibility == 'public')
and (
method.tags[tag] is defined
and (
hidden_by[tag] is not defined or method.tags[hidden_by[tag]] is not defined
)
)
%}
{%- if loop.first %}
{% if tag == 'api' %}
===== API synthesis =====
<WRAP>
List of the public API methods.
When manipulating {{ node.name }}, You can call those methods:
</WRAP>
{% elseif tag == 'api-advanced' %}
===== Advanced API synthesis =====
<WRAP>
List of advanced API methods
Beware they usage is recommended to advanced users only.
</WRAP>
{% elseif tag == 'overwritable-hook' %}
===== overwritable-hook synthesis =====
<WRAP >When inheriting from {{ node.name }},
you can overwrite those methods in order to add custom logic:
</WRAP>
{% elseif tag == 'extension-hook' %}
===== extension-hook synthesis =====
<WRAP >
When inheriting from {{ node.name }},
you can extend the behaviour of iTop by implementing:
</WRAP>
{% endif %}
{% endif %}
{% set sanitizedMethod = method|trim('\\', 'left')|replace({(node.name~'::'): ''}) %}
{% if '::' in sanitizedMethod -%}
{%- if node.tags['phpdoc-tuning-exclude-inherited'] is not defined %}
* [[{{sanitizedMethod|replace({'::': '#'})|lower}}|↪{{sanitizedMethod}}]] — {{ method.summary|replace({"\n":""})|raw }}
{% endif %}
{%- else %}
* [[#{{sanitizedMethod}}|{{sanitizedMethod}}]] — {{ method.summary|replace({"\n":""})|raw }}
{% endif %}
{% endfor %}

View File

@@ -0,0 +1,20 @@
{% if title_level is not defined %}
{% set title_level = '==' %}
{% endif %}
{%- for tagName,tags in structure.tags if tagName in tagsWithDescription -%}
{%- for tag in tags -%}
{%- if tag.description is not empty -%}
{%- if WRAP is defined -%}
<WRAP {{WRAP}}>
{%- endif -%}
{{title_level}} {{ tagName }} {{title_level}}
{{ tag.description|escape }}
{%- if WRAP is defined -%}
</WRAP>
{%- endif -%}
{%- endif -%}
{%- endfor -%}
{%- endfor -%}

View File

@@ -0,0 +1,22 @@
{% if title_level is not defined %}
{% set title_level='=====' %}
{% endif %}
{% if blacklist is not defined %}
{% set blacklist =['link', 'see', 'abstract', 'example', 'method', 'property', 'property-read', 'property-write', 'package', 'subpackage', 'api', 'api-advanced', 'todo', 'code-example'] %}
{% endif %}
{% if hidden_by is not defined -%}
{# Do not display @api if @api-advanced is also present #}
{%- set hidden_by = {"api" : "api-advanced"} -%}
{%- endif %}
{#^ {% for tagName,tags in structure.tags if tagName not in blacklist -%}#}
{#{{ tagName }} ^#}
{#{%- endfor %}#}
{% for tagName,tags in structure.tags if tagName not in blacklist and (hidden_by[tagName] is not defined or structure.tags[hidden_by[tagName]] is not defined) %}
{%- if loop.first %}
{{title_level}} Tags {{title_level}}
{% endif %}
^ {{ tagName }} | {% for tag in tags %}{{ tag.version ? tag.version ~ ' ' : '' }}{{ tag.description}}{% endfor %} |
{% endfor %}

View File

@@ -0,0 +1,24 @@
{% if title_level is not defined %}
{% set title_level='' %}
{% endif %}
{% for tagName,tags in structure.tags if tagName in ['used-by'] %}
{% if loop.first %}
{{title_level}} Used by {{title_level}}
{% endif %}
{% for tag in tags %}
{% if loop.length > 1 %} * {% endif %}{{ tag.reference ?: tag.link }} : {{ tag.description ?: tag.reference }}
{% endfor %}
{% endfor %}
{#{% for tagName,tags in method.tags if tagName in ['uses'] %}#}
{#{% if loop.first %}#}
{#<dt>Uses</dt>#}
{#{% endif %}#}
{#{% for tag in tags %}#}
{#<dd>{{ tag.reference|raw }}</dd>#}
{#{% endfor %}#}
{#{% endfor %}#}

View File

@@ -0,0 +1,24 @@
{% if title_level is not defined %}
{% set title_level='' %}
{% endif %}
{% for tagName,tags in structure.tags if tagName in ['uses'] %}
{% if loop.first %}
{{title_level}} Uses {{title_level}}
{% endif %}
{% for tag in tags %}
{% if loop.length > 1 %} * {% endif %}{{ tag.reference ?: tag.link }} : {{ tag.description ?: tag.reference }}
{% endfor %}
{% endfor %}
{#{% for tagName,tags in method.tags if tagName in ['uses'] %}#}
{#{% if loop.first %}#}
{#<dt>Uses</dt>#}
{#{% endif %}#}
{#{% for tag in tags %}#}
{#<dd>{{ tag.reference|raw }}</dd>#}
{#{% endfor %}#}
{#{% endfor %}#}

View File

@@ -0,0 +1,11 @@
{% if wrap is not defined -%}
{% set wrap = 'notice' %}
{%- endif -%}
{% if hidden_by is not defined -%}
{# Do not display @api if @api-advanced is also present #}
{%- set hidden_by = {"api" : "api-advanced"} -%}
{%- endif %}
{%- for tagName,tags in structure.tags if tagName in wrapTags and (hidden_by[tagName] is not defined or structure.tags[hidden_by[tagName]] is not defined) %}
<wrap {{wrap}}>{{tagName}}</wrap>
{% endfor %}

View File

@@ -0,0 +1,121 @@
{% extends 'layout.txt.twig' %}
{% block content %}
<wrap button>[[start|🔙 Back]]</wrap>
{% if node.tags['internal'] is defined %}
====== {{ node.name }} ======
<WRAP alert>This interface is "internal", and thus is not documented!</WRAP>
{% elseif node.tags['api'] is not defined and node.tags['api-advanced'] is not defined and node.tags['overwritable-hook'] is not defined and node.tags['extension-hook'] is not defined %}
====== {{ node.name }} ======
<WRAP alert>This interface is neither "api", "overwritable-hook" or "extension-hook", and thus is not documented!</WRAP>
{% else %}
====== {{ node.name }} ======
{% if node.deprecated %}<wrap danger>deprecated</wrap>{% endif %}
{% if node.abstract %}<wrap warning>abstract</wrap>{% endif %}
{% if node.final %}<wrap notice>final</wrap>{% endif %}
{% include 'includes/wrap-tags.txt.twig' with {structure:node, wrap: 'safety', wrapTags: ['api', 'api-advanced', 'overwritable-hook', 'extension-hook']} %}
{% if node.deprecated %}
=== **<del>Deprecated</del>**===
//{{ node.tags.deprecated[0].description }}//
{% endif %}
== {{ node.summary|replace({"\n":""})|raw }} ==
<html>{{ node.description|markdown|raw }}</html>
{% include 'includes/code-examples.txt.twig' with {structure:node, title_level: '====='} %}
{% set class = node.parent %}
{% block hierarchy_element %}
{% if class and class.name is defined and class.name|trim != '' %}
==== parent ====
{% set child = class %}
{% set class = class.parent %}
{{ block('hierarchy_element') }}
[[{{ child.name }}|{{ child.name }}]]
{% endif %}
{% endblock %}
{% for interface in node.interfaces|sort_asc %}
{% if loop.first %}
==== Implements ====
{% endif %}
{% if loop.length > 1 %} * {% endif %}{{ interface.fullyQualifiedStructuralElementName ?: interface }}
{% endfor %}
{% for trait in node.usedTraits|sort_asc %}
{% if loop.first %}
==== Uses traits ====
{% endif %}
{% if loop.length > 1 %} * {% endif %}{{ trait.fullyQualifiedStructuralElementName ?: trait }}
{% endfor %}
{% include 'includes/see-also.txt.twig' with {structure:node, title_level: '==='} %}
{% include 'includes/tags.txt.twig' with {structure:node, title_level: '=====', blacklist: ['link', 'see', 'abstract', 'example', 'method', 'property', 'property-read', 'property-write', 'package', 'subpackage', 'phpdoc-tuning-exclude-inherited', 'api', 'api-advanced', 'overwritable-hook', 'extension-hook', 'copyright', 'license', 'code-example']} %}
{% set methods = node.inheritedMethods.merge(node.methods) %}
{% include 'includes/tag-synthesys.txt.twig' with {methods:methods, tag:'api'} %}
{% include 'includes/tag-synthesys.txt.twig' with {methods:methods, tag:'api-advanced'} %}
{% include 'includes/tag-synthesys.txt.twig' with {methods:methods, tag:'overwritable-hook'} %}
{% include 'includes/tag-synthesys.txt.twig' with {methods:methods, tag:'extension-hook'} %}
<WRAP clear />
{% for method in methods|sort_asc if method.visibility == 'public' %}
{%- if loop.first %}
===== Public methods =====
{% endif %}
{{ block('method') }}
{% endfor %}
{% for method in methods|sort_asc if method.visibility == 'protected' %}
{%- if loop.first %}
===== Protected methods =====
{% endif %}
{{ block('method') }}
{% endfor %}
{% set constants = node.inheritedConstants.merge(node.constants) %}
{% if constants|length > 0 %}
===== Constants =====
{% for constant in constants|sort_asc %}
{{ block('constant') }}
{% endfor %}
{% endif %}
{#{% set properties = node.inheritedProperties.merge(node.properties) %}#}
{#{% for property in properties|sort_asc if property.visibility == 'public' %}#}
{#{%- if loop.first %}#}
{#===== Public properties =====#}
{#{% endif %}#}
{#{{ block('property') }}#}
{#{% endfor %}#}
{#{% for property in properties|sort_asc if property.visibility == 'protected' %}#}
{#{%- if loop.first %}#}
{#===== Protected properties =====#}
{#{% endif %}#}
{#{{ block('property') }}#}
{#{% endfor %}#}
{%- endif %} {#{% elseif node.tags['xxx'] is not defined and ... #}
<wrap button>[[start|🔙 Back]]</wrap>
{% endblock %}

View File

@@ -0,0 +1,5 @@
{% use 'elements/constant.txt.twig' %}
{% use 'elements/property.txt.twig' %}
{% use 'elements/method.txt.twig' %}
{% block content %}{% endblock %}

View File

@@ -0,0 +1,51 @@
{% extends 'layout.txt.twig' %}
{% block content %}
{% set namespace = project.namespace %}
{{ block('sidebarNamespaces') }}
{#{{ node.parent|raw }}#}
{#====== {{ node.parent.fullyQualifiedStructuralElementName }}{{ node.name }} ======#}
{% if node.children|length > 0 %}
=====Namespaces=====
{% include 'includes/namespace-structure-toc.html.twig' with {structures: node.children} %}
----
{% endif %}
{% if node.traits|length > 0 %}
===== Traits =====
{% include 'includes/namespace-structure-toc.html.twig' with {structures: node.traits} %}
----
{%- endif %}
{% if node.interfaces|length > 0 %}
===== Interfaces =====
{% include 'includes/namespace-structure-toc.html.twig' with {structures: node.interfaces} %}
----
{% endif %}
{% if node.classes|length > 0 %}
===== Classes =====
{% include 'includes/namespace-structure-toc.html.twig' with {structures: node.classes} %}
----
{% endif %}
{#{% if node.constants|length > 0 %}#}
{#===== Constants =====#}
{#{% for constant in node.constants|sort_asc %}#}
{# {{ block('constant') }}#}
{#{% endfor %}#}
{#{% endif %}#}
{#{% if node.functions|length > 0 %}#}
{#===== Functions =====#}
{#{% for method in node.functions|sort_asc %}#}
{# {{ block('method') }}#}
{#{% endfor %}#}
{#{% endif %}#}
{% endblock %}

View File

@@ -0,0 +1,49 @@
====== Deprecated elements ======
{#{% for element in project.indexes.elements if element.deprecated %}#}
{#{% if element.file.path != previousPath %}#}
{#<li><a href="#{{ element.file.path }}"><i class="icon-file"></i> {{ element.file.path }}</a></li>#}
{#{% endif %}#}
{#{% set previousPath = element.file.path %}#}
{#{% endfor %}#}
{% for element in project.indexes.elements if element.deprecated %}
{% if element.file.path != previousPath %}
{% if previousPath %}
</WRAP>{# group #}
{% endif %}
{#<a name="{{ element.file.path }}" id="{{ element.file.path }}"></a>#}
===== {{ element.file.path }} ({{ element.tags.deprecated.count }} found)=====
<WRAP group >
<WRAP third column >
Element
</WRAP>{# third column#}
<WRAP third column >
Line
</WRAP>{# third column#}
<WRAP third column >
Description
</WRAP>{# third column#}
{% endif %}
{% for tag in element.tags.deprecated %}
<WRAP group >
<WRAP third column >
{{ element.fullyQualifiedStructuralElementName }}
</WRAP>{# third column#}
<WRAP third column >
{{ element.line }}
</WRAP>{# third column#}
<WRAP third column >
{{ tag.description }}
</WRAP>{# third column#}
{% endfor %}
</WRAP>{# group #}
{% set previousPath = element.file.path %}
{% else %}
<WRAP info>No deprecated elements have been found in this project.</WRAP>
{% endfor %}

View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<template>
<author>Bruno DA SILVA</author>
<email>contact [at] combodo.com</email>
<version>1.0.0</version>
<copyright>Combodo 2018</copyright>
<description><![CDATA[
Forked from the clean theme of https://github.com/phpDocumentor/phpDocumentor2 provided under the MIT licence.
The original work is copyright "Mike van Riel".
------------------------------------------------------------------------------------------------------------------
To improve performance you can add the following to your .htaccess:
<ifModule mod_deflate.c>
<filesMatch "\.(js|css|html)$">
SetOutputFilter DEFLATE
</filesMatch>
</ifModule>
]]></description>
<transformations>
<transformation writer="twig" query="namespace" source="templates/combodo-wiki/namespace.txt.twig" artifact="start.txt"/>
<transformation writer="twig" query="indexes.classes" source="templates/combodo-wiki/class.txt.twig" artifact="{{name}}.txt"/>
<transformation writer="twig" query="indexes.interfaces" source="templates/combodo-wiki/interface.txt.twig" artifact="{{name}}.txt" />
</transformations>
</template>

View File

@@ -25,7 +25,7 @@ if (false === file_exists($sTcPdfRootFolder)) {
echo $sCurrentScriptFileName.": No TCPDF lib detected, exiting !\n"; echo $sCurrentScriptFileName.": No TCPDF lib detected, exiting !\n";
return; return;
} }
$sTcPdfFontsFolder = $sTcPdfRootFolder.'/fonts/'; $sTcPdfFontsFolder = $sTcPdfRootFolder.'/Fonts/';
/** /**

View File

@@ -199,7 +199,7 @@ class DatamodelsXmlFiles extends AbstractGlobFileVersionUpdater
libxml_clear_errors(); libxml_clear_errors();
$oFileXml->formatOutput = true; $oFileXml->formatOutput = true;
$oFileXml->preserveWhiteSpace = false; $oFileXml->preserveWhiteSpace = false;
$oFileXml->loadXML($sFileContent, LIBXML_BIGLINES); $oFileXml->loadXML($sFileContent);
$oFileItopFormat = new iTopDesignFormat($oFileXml); $oFileItopFormat = new iTopDesignFormat($oFileXml);

View File

@@ -1,9 +1,5 @@
<p align="center"><a href="https://www.combodo.com/itop-193" target="_blank"> <p align="center"><a href="https://www.combodo.com/itop-193" target="_blank">
<picture> <img src="https://www.combodo.com/logos/logo-itop-baseline.svg" width=350>
<source media="(prefers-color-scheme: dark)" srcset="/images/logos/logo-itop-baseline-light.svg">
<source media="(prefers-color-scheme: light)" srcset="/images/logos/logo-itop-baseline-dark.svg">
<img src="/images/logos/logo-itop-baseline-light.svg" width="350" alt="Logo iTop with baseline" />
</picture>
</a></p> </a></p>
@@ -110,7 +106,6 @@ We would like to give a special thank you 🤗 to the people from the community
- Raenker, Martin - Raenker, Martin
- Roháč, Richard (a.k.a [@RohacRichard](https://github.com/RohacRichard)) - Roháč, Richard (a.k.a [@RohacRichard](https://github.com/RohacRichard))
- Rosenke, Stephan - Rosenke, Stephan
- Rossi, Tommaso (a.k.a [@tomrss](https://www.github.com/tomrss))
- Rudner, Björn (a.k.a [@rudnerbjoern](https://github.com/rudnerbjoern)) - Rudner, Björn (a.k.a [@rudnerbjoern](https://github.com/rudnerbjoern))
- Šafránek, Jaroslav (a.k.a [jkcinik](https://sourceforge.net/u/jkcinik/profile/) on SourceForge) - Šafránek, Jaroslav (a.k.a [jkcinik](https://sourceforge.net/u/jkcinik/profile/) on SourceForge)
- Seki, Shoji - Seki, Shoji
@@ -120,7 +115,6 @@ We would like to give a special thank you 🤗 to the people from the community
- Tarjányi, Csaba (a.k.a [@tacsaby](https://github.com/tacsaby)) - Tarjányi, Csaba (a.k.a [@tacsaby](https://github.com/tacsaby))
- Tulio, Marco - Tulio, Marco
- Turrubiates, Miguel - Turrubiates, Miguel
- Vlk, Karel (a.k.a [@vlk-charles](https://www.github.com/vlk-charles))
### Aliases ### Aliases

View File

@@ -1,10 +1,9 @@
<?php <?php
// Copyright (C) 2010-2024 Combodo SAS // Copyright (C) 2010-2024 Combodo SAS
// //
// This file is part of iTop. // This file is part of iTop.
// //
// iTop is free software; you can redistribute it and/or modify // iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by // it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
@@ -24,29 +23,30 @@
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
*/ */
class UserRightsMatrixClassGrant extends DBObject class UserRightsMatrixClassGrant extends DBObject
{ {
public static function Init() public static function Init()
{ {
$aParams = $aParams = array
[ (
"category" => "addon/userrights", "category" => "addon/userrights",
"key_type" => "autoincrement", "key_type" => "autoincrement",
"name_attcode" => "", "name_attcode" => "",
"state_attcode" => "", "state_attcode" => "",
"reconc_keys" => [], "reconc_keys" => array(),
"db_table" => "priv_ur_matrixclasses", "db_table" => "priv_ur_matrixclasses",
"db_key_field" => "id", "db_key_field" => "id",
"db_finalclass_field" => "", "db_finalclass_field" => "",
]; );
MetaModel::Init_Params($aParams); MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes(); //MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeExternalKey("userid", ["targetclass" => "User", "jointype" => "", "allowed_values" => null, "sql" => "userid", "is_null_allowed" => false, "on_target_delete" => DEL_MANUAL, "depends_on" => []])); MetaModel::Init_AddAttribute(new AttributeExternalKey("userid", array("targetclass"=>"User", "jointype"=> "", "allowed_values"=>null, "sql"=>"userid", "is_null_allowed"=>false, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeExternalField("login", ["allowed_values" => null, "extkey_attcode" => 'userid', "target_attcode" => "login"])); MetaModel::Init_AddAttribute(new AttributeExternalField("login", array("allowed_values"=>null, "extkey_attcode"=> 'userid', "target_attcode"=>"login")));
MetaModel::Init_AddAttribute(new AttributeString("class", ["allowed_values" => null, "sql" => "class", "default_value" => null, "is_null_allowed" => false, "depends_on" => []])); MetaModel::Init_AddAttribute(new AttributeString("class", array("allowed_values"=>null, "sql"=>"class", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("action", ["allowed_values" => null, "sql" => "action", "default_value" => "", "is_null_allowed" => false, "depends_on" => []])); MetaModel::Init_AddAttribute(new AttributeString("action", array("allowed_values"=>null, "sql"=>"action", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeEnum("permission", ["allowed_values" => new ValueSetEnum('yes,no'), "sql" => "permission", "default_value" => "yes", "is_null_allowed" => false, "depends_on" => []])); MetaModel::Init_AddAttribute(new AttributeEnum("permission", array("allowed_values"=>new ValueSetEnum('yes,no'), "sql"=>"permission", "default_value"=>"yes", "is_null_allowed"=>false, "depends_on"=>array())));
} }
} }
@@ -54,25 +54,25 @@ class UserRightsMatrixClassStimulusGrant extends DBObject
{ {
public static function Init() public static function Init()
{ {
$aParams = $aParams = array
[ (
"category" => "addon/userrights", "category" => "addon/userrights",
"key_type" => "autoincrement", "key_type" => "autoincrement",
"name_attcode" => "", "name_attcode" => "",
"state_attcode" => "", "state_attcode" => "",
"reconc_keys" => [], "reconc_keys" => array(),
"db_table" => "priv_ur_matrixclassesstimulus", "db_table" => "priv_ur_matrixclassesstimulus",
"db_key_field" => "id", "db_key_field" => "id",
"db_finalclass_field" => "", "db_finalclass_field" => "",
]; );
MetaModel::Init_Params($aParams); MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes(); //MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeExternalKey("userid", ["targetclass" => "User", "jointype" => "", "allowed_values" => null, "sql" => "userid", "is_null_allowed" => false, "on_target_delete" => DEL_MANUAL, "depends_on" => []])); MetaModel::Init_AddAttribute(new AttributeExternalKey("userid", array("targetclass"=>"User", "jointype"=> "", "allowed_values"=>null, "sql"=>"userid", "is_null_allowed"=>false, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeExternalField("login", ["allowed_values" => null, "extkey_attcode" => 'userid', "target_attcode" => "login"])); MetaModel::Init_AddAttribute(new AttributeExternalField("login", array("allowed_values"=>null, "extkey_attcode"=> 'userid', "target_attcode"=>"login")));
MetaModel::Init_AddAttribute(new AttributeString("class", ["allowed_values" => null, "sql" => "class", "default_value" => null, "is_null_allowed" => false, "depends_on" => []])); MetaModel::Init_AddAttribute(new AttributeString("class", array("allowed_values"=>null, "sql"=>"class", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("stimulus", ["allowed_values" => null, "sql" => "action", "default_value" => "", "is_null_allowed" => false, "depends_on" => []])); MetaModel::Init_AddAttribute(new AttributeString("stimulus", array("allowed_values"=>null, "sql"=>"action", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeEnum("permission", ["allowed_values" => new ValueSetEnum('yes,no'), "sql" => "permission", "default_value" => "yes", "is_null_allowed" => false, "depends_on" => []])); MetaModel::Init_AddAttribute(new AttributeEnum("permission", array("allowed_values"=>new ValueSetEnum('yes,no'), "sql"=>"permission", "default_value"=>"yes", "is_null_allowed"=>false, "depends_on"=>array())));
} }
} }
@@ -80,39 +80,42 @@ class UserRightsMatrixAttributeGrant extends DBObject
{ {
public static function Init() public static function Init()
{ {
$aParams = $aParams = array
[ (
"category" => "addon/userrights", "category" => "addon/userrights",
"key_type" => "autoincrement", "key_type" => "autoincrement",
"name_attcode" => "", "name_attcode" => "",
"state_attcode" => "", "state_attcode" => "",
"reconc_keys" => [], "reconc_keys" => array(),
"db_table" => "priv_ur_matrixattributes", "db_table" => "priv_ur_matrixattributes",
"db_key_field" => "id", "db_key_field" => "id",
"db_finalclass_field" => "", "db_finalclass_field" => "",
]; );
MetaModel::Init_Params($aParams); MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes(); //MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeExternalKey("userid", ["targetclass" => "User", "jointype" => "", "allowed_values" => null, "sql" => "userid", "is_null_allowed" => false, "on_target_delete" => DEL_MANUAL, "depends_on" => []])); MetaModel::Init_AddAttribute(new AttributeExternalKey("userid", array("targetclass"=>"User", "jointype"=> "", "allowed_values"=>null, "sql"=>"userid", "is_null_allowed"=>false, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeExternalField("login", ["allowed_values" => null, "extkey_attcode" => 'userid', "target_attcode" => "login"])); MetaModel::Init_AddAttribute(new AttributeExternalField("login", array("allowed_values"=>null, "extkey_attcode"=> 'userid', "target_attcode"=>"login")));
MetaModel::Init_AddAttribute(new AttributeString("class", ["allowed_values" => null, "sql" => "class", "default_value" => null, "is_null_allowed" => false, "depends_on" => []])); MetaModel::Init_AddAttribute(new AttributeString("class", array("allowed_values"=>null, "sql"=>"class", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("attcode", ["allowed_values" => null, "sql" => "attcode", "default_value" => null, "is_null_allowed" => false, "depends_on" => []])); MetaModel::Init_AddAttribute(new AttributeString("attcode", array("allowed_values"=>null, "sql"=>"attcode", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("action", ["allowed_values" => null, "sql" => "action", "default_value" => "", "is_null_allowed" => false, "depends_on" => []])); MetaModel::Init_AddAttribute(new AttributeString("action", array("allowed_values"=>null, "sql"=>"action", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeEnum("permission", ["allowed_values" => new ValueSetEnum('yes,no'), "sql" => "permission", "default_value" => "yes", "is_null_allowed" => false, "depends_on" => []])); MetaModel::Init_AddAttribute(new AttributeEnum("permission", array("allowed_values"=>new ValueSetEnum('yes,no'), "sql"=>"permission", "default_value"=>"yes", "is_null_allowed"=>false, "depends_on"=>array())));
} }
} }
class UserRightsMatrix extends UserRightsAddOnAPI class UserRightsMatrix extends UserRightsAddOnAPI
{ {
public static $m_aActionCodes = [ static public $m_aActionCodes = array(
UR_ACTION_READ => 'read', UR_ACTION_READ => 'read',
UR_ACTION_MODIFY => 'modify', UR_ACTION_MODIFY => 'modify',
UR_ACTION_DELETE => 'delete', UR_ACTION_DELETE => 'delete',
UR_ACTION_BULK_READ => 'bulk read', UR_ACTION_BULK_READ => 'bulk read',
UR_ACTION_BULK_MODIFY => 'bulk modify', UR_ACTION_BULK_MODIFY => 'bulk modify',
UR_ACTION_BULK_DELETE => 'bulk delete', UR_ACTION_BULK_DELETE => 'bulk delete',
]; );
// Installation: create the very first user // Installation: create the very first user
public function CreateAdministrator($sAdminUser, $sAdminPwd, $sLanguage = 'EN US') public function CreateAdministrator($sAdminUser, $sAdminPwd, $sLanguage = 'EN US')
@@ -146,7 +149,8 @@ class UserRightsMatrix extends UserRightsAddOnAPI
// Users must be added manually // Users must be added manually
// This procedure will then update the matrix when a new user is found or a new class/attribute appears // This procedure will then update the matrix when a new user is found or a new class/attribute appears
$oUserSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT User")); $oUserSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT User"));
while ($oUser = $oUserSet->Fetch()) { while ($oUser = $oUserSet->Fetch())
{
$this->SetupUser($oUser->GetKey()); $this->SetupUser($oUser->GetKey());
} }
return true; return true;
@@ -154,16 +158,23 @@ class UserRightsMatrix extends UserRightsAddOnAPI
protected function SetupUser($iUserId, $bNewUser = false) protected function SetupUser($iUserId, $bNewUser = false)
{ {
foreach (['bizmodel', 'application', 'gui', 'core/cmdb'] as $sCategory) { foreach(array('bizmodel', 'application', 'gui', 'core/cmdb') as $sCategory)
foreach (MetaModel::GetClasses($sCategory) as $sClass) { {
foreach (self::$m_aActionCodes as $iActionCode => $sAction) { foreach (MetaModel::GetClasses($sCategory) as $sClass)
if ($bNewUser) { {
foreach (self::$m_aActionCodes as $iActionCode => $sAction)
{
if ($bNewUser)
{
$bAddCell = true; $bAddCell = true;
} else { }
else
{
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT UserRightsMatrixClassGrant WHERE class = '$sClass' AND action = '$sAction' AND userid = $iUserId")); $oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT UserRightsMatrixClassGrant WHERE class = '$sClass' AND action = '$sAction' AND userid = $iUserId"));
$bAddCell = ($oSet->Count() < 1); $bAddCell = ($oSet->Count() < 1);
} }
if ($bAddCell) { if ($bAddCell)
{
// Create a new entry // Create a new entry
$oMyClassGrant = MetaModel::NewObject("UserRightsMatrixClassGrant"); $oMyClassGrant = MetaModel::NewObject("UserRightsMatrixClassGrant");
$oMyClassGrant->Set("userid", $iUserId); $oMyClassGrant->Set("userid", $iUserId);
@@ -173,14 +184,19 @@ class UserRightsMatrix extends UserRightsAddOnAPI
$iId = $oMyClassGrant->DBInsertNoReload(); $iId = $oMyClassGrant->DBInsertNoReload();
} }
} }
foreach (MetaModel::EnumStimuli($sClass) as $sStimulusCode => $oStimulus) { foreach (MetaModel::EnumStimuli($sClass) as $sStimulusCode => $oStimulus)
if ($bNewUser) { {
if ($bNewUser)
{
$bAddCell = true; $bAddCell = true;
} else { }
else
{
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT UserRightsMatrixClassStimulusGrant WHERE class = '$sClass' AND stimulus = '$sStimulusCode' AND userid = $iUserId")); $oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT UserRightsMatrixClassStimulusGrant WHERE class = '$sClass' AND stimulus = '$sStimulusCode' AND userid = $iUserId"));
$bAddCell = ($oSet->Count() < 1); $bAddCell = ($oSet->Count() < 1);
} }
if ($bAddCell) { if ($bAddCell)
{
// Create a new entry // Create a new entry
$oMyClassGrant = MetaModel::NewObject("UserRightsMatrixClassStimulusGrant"); $oMyClassGrant = MetaModel::NewObject("UserRightsMatrixClassStimulusGrant");
$oMyClassGrant->Set("userid", $iUserId); $oMyClassGrant->Set("userid", $iUserId);
@@ -190,15 +206,21 @@ class UserRightsMatrix extends UserRightsAddOnAPI
$iId = $oMyClassGrant->DBInsertNoReload(); $iId = $oMyClassGrant->DBInsertNoReload();
} }
} }
foreach (MetaModel::GetAttributesList($sClass) as $sAttCode) { foreach (MetaModel::GetAttributesList($sClass) as $sAttCode)
if ($bNewUser) { {
if ($bNewUser)
{
$bAddCell = true; $bAddCell = true;
} else { }
else
{
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT UserRightsMatrixAttributeGrant WHERE class = '$sClass' AND attcode = '$sAttCode' AND userid = $iUserId")); $oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT UserRightsMatrixAttributeGrant WHERE class = '$sClass' AND attcode = '$sAttCode' AND userid = $iUserId"));
$bAddCell = ($oSet->Count() < 1); $bAddCell = ($oSet->Count() < 1);
} }
if ($bAddCell) { if ($bAddCell)
foreach (['read', 'modify'] as $sAction) { {
foreach (array('read', 'modify') as $sAction)
{
// Create a new entry // Create a new entry
$oMyAttGrant = MetaModel::NewObject("UserRightsMatrixAttributeGrant"); $oMyAttGrant = MetaModel::NewObject("UserRightsMatrixAttributeGrant");
$oMyAttGrant->Set("userid", $iUserId); $oMyAttGrant->Set("userid", $iUserId);
@@ -239,13 +261,14 @@ class UserRightsMatrix extends UserRightsAddOnAPI
*/ */
} }
public function Init() public function Init()
{ {
// Could be loaded in a shared memory (?) // Could be loaded in a shared memory (?)
return true; return true;
} }
public function GetSelectFilter($oUser, $sClass, $aSettings = []) public function GetSelectFilter($oUser, $sClass, $aSettings = array())
{ {
$oNullFilter = new DBObjectSearch($sClass); $oNullFilter = new DBObjectSearch($sClass);
return $oNullFilter; return $oNullFilter;
@@ -253,18 +276,21 @@ class UserRightsMatrix extends UserRightsAddOnAPI
public function IsActionAllowed($oUser, $sClass, $iActionCode, $oInstanceSet = null) public function IsActionAllowed($oUser, $sClass, $iActionCode, $oInstanceSet = null)
{ {
if (!array_key_exists($iActionCode, self::$m_aActionCodes)) { if (!array_key_exists($iActionCode, self::$m_aActionCodes))
{
return UR_ALLOWED_NO; return UR_ALLOWED_NO;
} }
$sAction = self::$m_aActionCodes[$iActionCode]; $sAction = self::$m_aActionCodes[$iActionCode];
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT UserRightsMatrixClassGrant WHERE class = '$sClass' AND action = '$sAction' AND userid = '{$oUser->GetKey()}'")); $oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT UserRightsMatrixClassGrant WHERE class = '$sClass' AND action = '$sAction' AND userid = '{$oUser->GetKey()}'"));
if ($oSet->Count() < 1) { if ($oSet->Count() < 1)
{
return UR_ALLOWED_NO; return UR_ALLOWED_NO;
} }
$oGrantRecord = $oSet->Fetch(); $oGrantRecord = $oSet->Fetch();
switch ($oGrantRecord->Get('permission')) { switch ($oGrantRecord->Get('permission'))
{
case 'yes': case 'yes':
$iRetCode = UR_ALLOWED_YES; $iRetCode = UR_ALLOWED_YES;
break; break;
@@ -278,18 +304,21 @@ class UserRightsMatrix extends UserRightsAddOnAPI
public function IsActionAllowedOnAttribute($oUser, $sClass, $sAttCode, $iActionCode, $oInstanceSet = null) public function IsActionAllowedOnAttribute($oUser, $sClass, $sAttCode, $iActionCode, $oInstanceSet = null)
{ {
if (!array_key_exists($iActionCode, self::$m_aActionCodes)) { if (!array_key_exists($iActionCode, self::$m_aActionCodes))
{
return UR_ALLOWED_NO; return UR_ALLOWED_NO;
} }
$sAction = self::$m_aActionCodes[$iActionCode]; $sAction = self::$m_aActionCodes[$iActionCode];
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT UserRightsMatrixAttributeGrant WHERE class = '$sClass' AND attcode = '$sAttCode' AND action = '$sAction' AND userid = '{$oUser->GetKey()}'")); $oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT UserRightsMatrixAttributeGrant WHERE class = '$sClass' AND attcode = '$sAttCode' AND action = '$sAction' AND userid = '{$oUser->GetKey()}'"));
if ($oSet->Count() < 1) { if ($oSet->Count() < 1)
{
return UR_ALLOWED_NO; return UR_ALLOWED_NO;
} }
$oGrantRecord = $oSet->Fetch(); $oGrantRecord = $oSet->Fetch();
switch ($oGrantRecord->Get('permission')) { switch ($oGrantRecord->Get('permission'))
{
case 'yes': case 'yes':
$iRetCode = UR_ALLOWED_YES; $iRetCode = UR_ALLOWED_YES;
break; break;
@@ -304,12 +333,14 @@ class UserRightsMatrix extends UserRightsAddOnAPI
public function IsStimulusAllowed($oUser, $sClass, $sStimulusCode, $oInstanceSet = null) public function IsStimulusAllowed($oUser, $sClass, $sStimulusCode, $oInstanceSet = null)
{ {
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT UserRightsMatrixClassStimulusGrant WHERE class = '$sClass' AND stimulus = '$sStimulusCode' AND userid = '{$oUser->GetKey()}'")); $oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT UserRightsMatrixClassStimulusGrant WHERE class = '$sClass' AND stimulus = '$sStimulusCode' AND userid = '{$oUser->GetKey()}'"));
if ($oSet->Count() < 1) { if ($oSet->Count() < 1)
{
return UR_ALLOWED_NO; return UR_ALLOWED_NO;
} }
$oGrantRecord = $oSet->Fetch(); $oGrantRecord = $oSet->Fetch();
switch ($oGrantRecord->Get('permission')) { switch ($oGrantRecord->Get('permission'))
{
case 'yes': case 'yes':
$iRetCode = UR_ALLOWED_YES; $iRetCode = UR_ALLOWED_YES;
break; break;
@@ -327,3 +358,5 @@ class UserRightsMatrix extends UserRightsAddOnAPI
} }
UserRights::SelectModule('UserRightsMatrix'); UserRights::SelectModule('UserRightsMatrix');
?>

View File

@@ -1,10 +1,9 @@
<?php <?php
// Copyright (C) 2010-2024 Combodo SAS // Copyright (C) 2010-2024 Combodo SAS
// //
// This file is part of iTop. // This file is part of iTop.
// //
// iTop is free software; you can redistribute it and/or modify // iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by // it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
@@ -48,7 +47,7 @@ class UserRightsNull extends UserRightsAddOnAPI
return true; return true;
} }
public function GetSelectFilter($oUser, $sClass, $aSettings = []) public function GetSelectFilter($oUser, $sClass, $aSettings = array())
{ {
$oNullFilter = new DBObjectSearch($sClass); $oNullFilter = new DBObjectSearch($sClass);
return $oNullFilter; return $oNullFilter;
@@ -75,3 +74,5 @@ class UserRightsNull extends UserRightsAddOnAPI
} }
UserRights::SelectModule('UserRightsNull'); UserRights::SelectModule('UserRightsNull');
?>

View File

@@ -1,5 +1,4 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -30,52 +29,56 @@ class UserRightsBaseClassGUI extends cmdbAbstractObject
} }
} }
class URP_Profiles extends UserRightsBaseClassGUI class URP_Profiles extends UserRightsBaseClassGUI
{ {
public static function Init() public static function Init()
{ {
$aParams = $aParams = array
[ (
"category" => "addon/userrights,grant_by_profile,filter", "category" => "addon/userrights,grant_by_profile,filter",
"key_type" => "autoincrement", "key_type" => "autoincrement",
"name_attcode" => "name", "name_attcode" => "name",
"complementary_name_attcode" => ['description'], "complementary_name_attcode" => array('description'),
"state_attcode" => "", "state_attcode" => "",
"reconc_keys" => [], "reconc_keys" => array(),
"db_table" => "priv_urp_profiles", "db_table" => "priv_urp_profiles",
"db_key_field" => "id", "db_key_field" => "id",
"db_finalclass_field" => "", "db_finalclass_field" => "",
]; );
MetaModel::Init_Params($aParams); MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes(); //MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeString("name", ["allowed_values" => null, "sql" => "name", "default_value" => null, "is_null_allowed" => false, "depends_on" => []])); MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values"=>null, "sql"=>"name", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("description", ["allowed_values" => null, "sql" => "description", "default_value" => null, "is_null_allowed" => false, "depends_on" => []])); MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values"=>null, "sql"=>"description", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect("user_list", ["linked_class" => "URP_UserProfile", "ext_key_to_me" => "profileid", "ext_key_to_remote" => "userid", "allowed_values" => null, "count_min" => 1, "count_max" => 0, "depends_on" => []])); MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect("user_list", array("linked_class"=>"URP_UserProfile", "ext_key_to_me"=>"profileid", "ext_key_to_remote"=>"userid", "allowed_values"=>null, "count_min"=>1, "count_max"=>0, "depends_on"=>array())));
// Display lists // Display lists
MetaModel::Init_SetZListItems('details', ['name', 'description', 'user_list']); // Attributes to be displayed for the complete details MetaModel::Init_SetZListItems('details', array('name', 'description', 'user_list')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', ['description']); // Attributes to be displayed for a list MetaModel::Init_SetZListItems('list', array('description')); // Attributes to be displayed for a list
// Search criteria // Search criteria
MetaModel::Init_SetZListItems('standard_search', ['name','description']); // Criteria of the std search form MetaModel::Init_SetZListItems('standard_search', array('name','description')); // Criteria of the std search form
MetaModel::Init_SetZListItems('default_search', ['name','description']); MetaModel::Init_SetZListItems('default_search', array ('name','description'));
} }
protected static $m_aCacheProfiles = null; protected static $m_aCacheProfiles = null;
public static function DoCreateProfile($sName, $sDescription) public static function DoCreateProfile($sName, $sDescription)
{ {
if (is_null(self::$m_aCacheProfiles)) { if (is_null(self::$m_aCacheProfiles))
self::$m_aCacheProfiles = []; {
self::$m_aCacheProfiles = array();
$oFilterAll = new DBObjectSearch('URP_Profiles'); $oFilterAll = new DBObjectSearch('URP_Profiles');
$oSet = new DBObjectSet($oFilterAll); $oSet = new DBObjectSet($oFilterAll);
while ($oProfile = $oSet->Fetch()) { while ($oProfile = $oSet->Fetch())
{
self::$m_aCacheProfiles[$oProfile->Get('name')] = $oProfile->GetKey(); self::$m_aCacheProfiles[$oProfile->Get('name')] = $oProfile->GetKey();
} }
} }
$sCacheKey = $sName; $sCacheKey = $sName;
if (isset(self::$m_aCacheProfiles[$sCacheKey])) { if (isset(self::$m_aCacheProfiles[$sCacheKey]))
{
return self::$m_aCacheProfiles[$sCacheKey]; return self::$m_aCacheProfiles[$sCacheKey];
} }
$oNewObj = MetaModel::NewObject("URP_Profiles"); $oNewObj = MetaModel::NewObject("URP_Profiles");
@@ -86,21 +89,27 @@ class URP_Profiles extends UserRightsBaseClassGUI
return $iId; return $iId;
} }
public function GetGrantAsHtml($oUserRights, $sClass, $sAction) function GetGrantAsHtml($oUserRights, $sClass, $sAction)
{ {
$bGrant = $oUserRights->GetProfileActionGrant($this->GetKey(), $sClass, $sAction); $bGrant = $oUserRights->GetProfileActionGrant($this->GetKey(), $sClass, $sAction);
if (is_null($bGrant)) { if (is_null($bGrant))
return '<span class="ibo-user-rights ibo-is-failure">'.Dict::S('UI:UserManagement:ActionAllowed:No').'</span>'; {
} elseif ($bGrant) { return '<span style="background-color: #ffdddd;">'.Dict::S('UI:UserManagement:ActionAllowed:No').'</span>';
return '<span class="ibo-user-rights ibo-is-success">'.Dict::S('UI:UserManagement:ActionAllowed:Yes').'</span>'; }
} else { elseif ($bGrant)
return '<span class="ibo-user-rights ibo-is-failure">'.Dict::S('UI:UserManagement:ActionAllowed:No').'</span>'; {
return '<span style="background-color: #ddffdd;">'.Dict::S('UI:UserManagement:ActionAllowed:Yes').'</span>';
}
else
{
return '<span style="background-color: #ffdddd;">'.Dict::S('UI:UserManagement:ActionAllowed:No').'</span>';
} }
} }
public function DoShowGrantSumary($oPage) function DoShowGrantSumary($oPage)
{ {
if ($this->GetRawName() == "Administrator") { if ($this->GetRawName() == "Administrator")
{
// Looks dirty, but ok that's THE ONE // Looks dirty, but ok that's THE ONE
$oPage->p(Dict::S('UI:UserManagement:AdminProfile+')); $oPage->p(Dict::S('UI:UserManagement:AdminProfile+'));
return; return;
@@ -109,18 +118,21 @@ class URP_Profiles extends UserRightsBaseClassGUI
// Note: for sure, we assume that the instance is derived from UserRightsProfile // Note: for sure, we assume that the instance is derived from UserRightsProfile
$oUserRights = UserRights::GetModuleInstance(); $oUserRights = UserRights::GetModuleInstance();
$aDisplayData = []; $aDisplayData = array();
foreach (MetaModel::GetClasses('bizmodel,grant_by_profile') as $sClass) { foreach (MetaModel::GetClasses('bizmodel,grant_by_profile') as $sClass)
$aStimuli = []; {
foreach (MetaModel::EnumStimuli($sClass) as $sStimulusCode => $oStimulus) { $aStimuli = array();
foreach (MetaModel::EnumStimuli($sClass) as $sStimulusCode => $oStimulus)
{
$bGrant = $oUserRights->GetClassStimulusGrant($this->GetKey(), $sClass, $sStimulusCode); $bGrant = $oUserRights->GetClassStimulusGrant($this->GetKey(), $sClass, $sStimulusCode);
if ($bGrant === true) { if ($bGrant === true)
{
$aStimuli[] = '<span title="'.$sStimulusCode.': '.utils::EscapeHtml($oStimulus->GetDescription()).'">'.utils::EscapeHtml($oStimulus->GetLabel()).'</span>'; $aStimuli[] = '<span title="'.$sStimulusCode.': '.utils::EscapeHtml($oStimulus->GetDescription()).'">'.utils::EscapeHtml($oStimulus->GetLabel()).'</span>';
} }
} }
$sStimuli = implode(', ', $aStimuli); $sStimuli = implode(', ', $aStimuli);
$aDisplayData[] = [ $aDisplayData[] = array(
'class' => MetaModel::GetName($sClass), 'class' => MetaModel::GetName($sClass),
'read' => $this->GetGrantAsHtml($oUserRights, $sClass, 'r'), 'read' => $this->GetGrantAsHtml($oUserRights, $sClass, 'r'),
'bulkread' => $this->GetGrantAsHtml($oUserRights, $sClass, 'br'), 'bulkread' => $this->GetGrantAsHtml($oUserRights, $sClass, 'br'),
@@ -129,22 +141,22 @@ class URP_Profiles extends UserRightsBaseClassGUI
'delete' => $this->GetGrantAsHtml($oUserRights, $sClass, 'd'), 'delete' => $this->GetGrantAsHtml($oUserRights, $sClass, 'd'),
'bulkdelete' => $this->GetGrantAsHtml($oUserRights, $sClass, 'bd'), 'bulkdelete' => $this->GetGrantAsHtml($oUserRights, $sClass, 'bd'),
'stimuli' => $sStimuli, 'stimuli' => $sStimuli,
]; );
} }
$aDisplayConfig = []; $aDisplayConfig = array();
$aDisplayConfig['class'] = ['label' => Dict::S('UI:UserManagement:Class'), 'description' => Dict::S('UI:UserManagement:Class+')]; $aDisplayConfig['class'] = array('label' => Dict::S('UI:UserManagement:Class'), 'description' => Dict::S('UI:UserManagement:Class+'));
$aDisplayConfig['read'] = ['label' => Dict::S('UI:UserManagement:Action:Read'), 'description' => Dict::S('UI:UserManagement:Action:Read+')]; $aDisplayConfig['read'] = array('label' => Dict::S('UI:UserManagement:Action:Read'), 'description' => Dict::S('UI:UserManagement:Action:Read+'));
$aDisplayConfig['bulkread'] = ['label' => Dict::S('UI:UserManagement:Action:BulkRead'), 'description' => Dict::S('UI:UserManagement:Action:BulkRead+')]; $aDisplayConfig['bulkread'] = array('label' => Dict::S('UI:UserManagement:Action:BulkRead'), 'description' => Dict::S('UI:UserManagement:Action:BulkRead+'));
$aDisplayConfig['write'] = ['label' => Dict::S('UI:UserManagement:Action:Modify'), 'description' => Dict::S('UI:UserManagement:Action:Modify+')]; $aDisplayConfig['write'] = array('label' => Dict::S('UI:UserManagement:Action:Modify'), 'description' => Dict::S('UI:UserManagement:Action:Modify+'));
$aDisplayConfig['bulkwrite'] = ['label' => Dict::S('UI:UserManagement:Action:BulkModify'), 'description' => Dict::S('UI:UserManagement:Action:BulkModify+')]; $aDisplayConfig['bulkwrite'] = array('label' => Dict::S('UI:UserManagement:Action:BulkModify'), 'description' => Dict::S('UI:UserManagement:Action:BulkModify+'));
$aDisplayConfig['delete'] = ['label' => Dict::S('UI:UserManagement:Action:Delete'), 'description' => Dict::S('UI:UserManagement:Action:Delete+')]; $aDisplayConfig['delete'] = array('label' => Dict::S('UI:UserManagement:Action:Delete'), 'description' => Dict::S('UI:UserManagement:Action:Delete+'));
$aDisplayConfig['bulkdelete'] = ['label' => Dict::S('UI:UserManagement:Action:BulkDelete'), 'description' => Dict::S('UI:UserManagement:Action:BulkDelete+')]; $aDisplayConfig['bulkdelete'] = array('label' => Dict::S('UI:UserManagement:Action:BulkDelete'), 'description' => Dict::S('UI:UserManagement:Action:BulkDelete+'));
$aDisplayConfig['stimuli'] = ['label' => Dict::S('UI:UserManagement:Action:Stimuli'), 'description' => Dict::S('UI:UserManagement:Action:Stimuli+')]; $aDisplayConfig['stimuli'] = array('label' => Dict::S('UI:UserManagement:Action:Stimuli'), 'description' => Dict::S('UI:UserManagement:Action:Stimuli+'));
$oPage->table($aDisplayConfig, $aDisplayData); $oPage->table($aDisplayConfig, $aDisplayData);
} }
public function DisplayBareRelations(WebPage $oPage, $bEditMode = false) function DisplayBareRelations(WebPage $oPage, $bEditMode = false)
{ {
parent::DisplayBareRelations($oPage, $bEditMode); parent::DisplayBareRelations($oPage, $bEditMode);
@@ -154,9 +166,10 @@ class URP_Profiles extends UserRightsBaseClassGUI
public static function GetReadOnlyAttributes() public static function GetReadOnlyAttributes()
{ {
return ['name', 'description']; return array('name', 'description');
} }
// returns an array of id => array of column => php value(so-called "real value") // returns an array of id => array of column => php value(so-called "real value")
public static function GetPredefinedObjects() public static function GetPredefinedObjects()
{ {
@@ -168,13 +181,15 @@ class URP_Profiles extends UserRightsBaseClassGUI
protected function OnDelete() protected function OnDelete()
{ {
// Don't remove admin profile // Don't remove admin profile
if ($this->Get('name') === ADMIN_PROFILE_NAME) { if ($this->Get('name') === ADMIN_PROFILE_NAME)
{
throw new SecurityException(Dict::Format('UI:Login:Error:AccessAdmin')); throw new SecurityException(Dict::Format('UI:Login:Error:AccessAdmin'));
} }
// Note: this may break the rule that says: "a user must have at least ONE profile" ! // Note: this may break the rule that says: "a user must have at least ONE profile" !
$oLnkSet = $this->Get('user_list'); $oLnkSet = $this->Get('user_list');
while ($oLnk = $oLnkSet->Fetch()) { while($oLnk = $oLnkSet->Fetch())
{
$oLnk->DBDelete(); $oLnk->DBDelete();
} }
} }
@@ -187,10 +202,11 @@ class URP_Profiles extends UserRightsBaseClassGUI
* @param $sTargetState string The target state in which to evalutate the flags, if empty the current state will be used * @param $sTargetState string The target state in which to evalutate the flags, if empty the current state will be used
* @return integer Flags: the binary combination of the flags applicable to this attribute * @return integer Flags: the binary combination of the flags applicable to this attribute
*/ */
public function GetAttributeFlags($sAttCode, &$aReasons = [], $sTargetState = '') public function GetAttributeFlags($sAttCode, &$aReasons = array(), $sTargetState = '')
{ {
$iFlags = parent::GetAttributeFlags($sAttCode, $aReasons, $sTargetState); $iFlags = parent::GetAttributeFlags($sAttCode, $aReasons, $sTargetState);
if (MetaModel::GetConfig()->Get('demo_mode')) { if (MetaModel::GetConfig()->Get('demo_mode'))
{
$aReasons[] = 'Sorry, profiles are read-only in the demonstration mode!'; $aReasons[] = 'Sorry, profiles are read-only in the demonstration mode!';
$iFlags |= OPT_ATT_READONLY; $iFlags |= OPT_ATT_READONLY;
} }
@@ -198,52 +214,52 @@ class URP_Profiles extends UserRightsBaseClassGUI
} }
} }
class URP_UserProfile extends UserRightsBaseClassGUI class URP_UserProfile extends UserRightsBaseClassGUI
{ {
public static function Init() public static function Init()
{ {
$aParams = $aParams = array
[ (
"category" => "addon/userrights,grant_by_profile,filter", "category" => "addon/userrights,grant_by_profile,filter",
"key_type" => "autoincrement", "key_type" => "autoincrement",
"name_attcode" => ["userlogin", "profile"], "name_attcode" => array("userlogin", "profile"),
"state_attcode" => "", "state_attcode" => "",
"reconc_keys" => [], "reconc_keys" => array(),
"db_table" => "priv_urp_userprofile", "db_table" => "priv_urp_userprofile",
"db_key_field" => "id", "db_key_field" => "id",
"db_finalclass_field" => "", "db_finalclass_field" => "",
"is_link" => true, /** @since 3.1.0 N°6482 */ "is_link" => true, /** @since 3.1.0 N°6482 */
'uniqueness_rules' => [ 'uniqueness_rules' => array(
'no_duplicate' => [ 'no_duplicate' => array(
'attributes' => [ 'attributes' => array(
0 => 'userid', 0 => 'userid',
1 => 'profileid', 1 => 'profileid',
], ),
'filter' => '', 'filter' => '',
'disabled' => false, 'disabled' => false,
'is_blocking' => true, 'is_blocking' => true,
], ),
], ),
]; );
MetaModel::Init_Params($aParams); MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes(); //MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeExternalKey("userid", ["targetclass" => "User", "jointype" => "", "allowed_values" => null, "sql" => "userid", "is_null_allowed" => false, "on_target_delete" => DEL_AUTO, "depends_on" => []])); MetaModel::Init_AddAttribute(new AttributeExternalKey("userid", array("targetclass" => "User", "jointype" => "", "allowed_values" => null, "sql" => "userid", "is_null_allowed" => false, "on_target_delete" => DEL_AUTO, "depends_on" => array())));
MetaModel::Init_AddAttribute(new AttributeExternalField("userlogin", ["allowed_values" => null, "extkey_attcode" => 'userid', "target_attcode" => "login"])); MetaModel::Init_AddAttribute(new AttributeExternalField("userlogin", array("allowed_values" => null, "extkey_attcode" => 'userid', "target_attcode" => "login")));
MetaModel::Init_AddAttribute(new AttributeExternalKey( MetaModel::Init_AddAttribute(new AttributeExternalKey("profileid",
"profileid", array("targetclass" => "URP_Profiles", "jointype" => "", "allowed_values" => null, "sql" => "profileid", "is_null_allowed" => false, "on_target_delete" => DEL_AUTO, "depends_on" => array(), "allow_target_creation" => false)));
["targetclass" => "URP_Profiles", "jointype" => "", "allowed_values" => null, "sql" => "profileid", "is_null_allowed" => false, "on_target_delete" => DEL_AUTO, "depends_on" => [], "allow_target_creation" => false] MetaModel::Init_AddAttribute(new AttributeExternalField("profile", array("allowed_values" => null, "extkey_attcode" => 'profileid', "target_attcode" => "name")));
));
MetaModel::Init_AddAttribute(new AttributeExternalField("profile", ["allowed_values" => null, "extkey_attcode" => 'profileid', "target_attcode" => "name"]));
MetaModel::Init_AddAttribute(new AttributeString("reason", ["allowed_values" => null, "sql" => "description", "default_value" => null, "is_null_allowed" => true, "depends_on" => []])); MetaModel::Init_AddAttribute(new AttributeString("reason", array("allowed_values" => null, "sql" => "description", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
// Display lists // Display lists
MetaModel::Init_SetZListItems('details', ['userid', 'profileid', 'reason']); // Attributes to be displayed for the complete details MetaModel::Init_SetZListItems('details', array('userid', 'profileid', 'reason')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', ['userid', 'profileid', 'reason']); // Attributes to be displayed for a list MetaModel::Init_SetZListItems('list', array('userid', 'profileid', 'reason')); // Attributes to be displayed for a list
// Search criteria // Search criteria
MetaModel::Init_SetZListItems('standard_search', ['userid', 'profileid']); // Criteria of the std search form MetaModel::Init_SetZListItems('standard_search', array('userid', 'profileid')); // Criteria of the std search form
MetaModel::Init_SetZListItems('advanced_search', ['userid', 'profileid']); // Criteria of the advanced search form MetaModel::Init_SetZListItems('advanced_search', array('userid', 'profileid')); // Criteria of the advanced search form
} }
public function CheckToDelete(&$oDeletionPlan) public function CheckToDelete(&$oDeletionPlan)
@@ -251,14 +267,15 @@ class URP_UserProfile extends UserRightsBaseClassGUI
if (MetaModel::GetConfig()->Get('demo_mode')) { if (MetaModel::GetConfig()->Get('demo_mode')) {
// Users deletion is NOT allowed in demo mode // Users deletion is NOT allowed in demo mode
$oDeletionPlan->AddToDelete($this, null); $oDeletionPlan->AddToDelete($this, null);
$oDeletionPlan->SetDeletionIssues($this, ['deletion not allowed in demo mode.'], true); $oDeletionPlan->SetDeletionIssues($this, array('deletion not allowed in demo mode.'), true);
$oDeletionPlan->ComputeResults(); $oDeletionPlan->ComputeResults();
return false; return false;
} }
try { try {
$this->CheckIfProfileIsAllowed(UR_ACTION_DELETE); $this->CheckIfProfileIsAllowed(UR_ACTION_DELETE);
} catch (SecurityException $e) { }
catch (SecurityException $e) {
// Users deletion is NOT allowed // Users deletion is NOT allowed
$oDeletionPlan->AddToDelete($this, null); $oDeletionPlan->AddToDelete($this, null);
$oDeletionPlan->SetDeletionIssues($this, [$e->getMessage()], true); $oDeletionPlan->SetDeletionIssues($this, [$e->getMessage()], true);
@@ -275,14 +292,15 @@ class URP_UserProfile extends UserRightsBaseClassGUI
if (MetaModel::GetConfig()->Get('demo_mode')) { if (MetaModel::GetConfig()->Get('demo_mode')) {
// Users deletion is NOT allowed in demo mode // Users deletion is NOT allowed in demo mode
$oDeletionPlan->AddToDelete($this, null); $oDeletionPlan->AddToDelete($this, null);
$oDeletionPlan->SetDeletionIssues($this, ['deletion not allowed in demo mode.'], true); $oDeletionPlan->SetDeletionIssues($this, array('deletion not allowed in demo mode.'), true);
$oDeletionPlan->ComputeResults(); $oDeletionPlan->ComputeResults();
return false; return false;
} }
try { try {
$this->CheckIfProfileIsAllowed(UR_ACTION_DELETE); $this->CheckIfProfileIsAllowed(UR_ACTION_DELETE);
} catch (SecurityException $e) { }
catch (SecurityException $e) {
// Users deletion is NOT allowed // Users deletion is NOT allowed
$oDeletionPlan->AddToDelete($this, null); $oDeletionPlan->AddToDelete($this, null);
$oDeletionPlan->SetDeletionIssues($this, [$e->getMessage()], true); $oDeletionPlan->SetDeletionIssues($this, [$e->getMessage()], true);
@@ -318,26 +336,29 @@ class URP_UserProfile extends UserRightsBaseClassGUI
protected function CheckIfProfileIsAllowed($iActionCode) protected function CheckIfProfileIsAllowed($iActionCode)
{ {
// When initializing or admin, we need to let everything pass trough // When initializing or admin, we need to let everything pass trough
if (!UserRights::IsLoggedIn() || UserRights::IsAdministrator()) { if (!UserRights::IsLoggedIn() || UserRights::IsAdministrator()) { return; }
return;
}
// Only administrators can manage administrators // Only administrators can manage administrators
$iOrigUserId = $this->GetOriginal('userid'); $iOrigUserId = $this->GetOriginal('userid');
if (!empty($iOrigUserId)) { if (!empty($iOrigUserId))
{
$oUser = MetaModel::GetObject('User', $iOrigUserId, true, true); $oUser = MetaModel::GetObject('User', $iOrigUserId, true, true);
if (UserRights::IsAdministrator($oUser) && !UserRights::IsAdministrator()) { if (UserRights::IsAdministrator($oUser) && !UserRights::IsAdministrator())
{
throw new SecurityException(Dict::Format('UI:Login:Error:AccessRestricted')); throw new SecurityException(Dict::Format('UI:Login:Error:AccessRestricted'));
} }
} }
$oUser = MetaModel::GetObject('User', $this->Get('userid'), true, true); $oUser = MetaModel::GetObject('User', $this->Get('userid'), true, true);
if (UserRights::IsAdministrator($oUser) && !UserRights::IsAdministrator()) { if (UserRights::IsAdministrator($oUser) && !UserRights::IsAdministrator())
{
throw new SecurityException(Dict::Format('UI:Login:Error:AccessRestricted')); throw new SecurityException(Dict::Format('UI:Login:Error:AccessRestricted'));
} }
if (!UserRights::IsActionAllowed(get_class($this), $iActionCode, DBObjectSet::FromObject($this))) { if (!UserRights::IsActionAllowed(get_class($this), $iActionCode, DBObjectSet::FromObject($this)))
{
throw new SecurityException(Dict::Format('UI:Error:ObjectCannotBeUpdated')); throw new SecurityException(Dict::Format('UI:Error:ObjectCannotBeUpdated'));
} }
if (!UserRights::IsAdministrator() && ($this->Get('profile') === ADMIN_PROFILE_NAME)) { if (!UserRights::IsAdministrator() && ($this->Get('profile') === ADMIN_PROFILE_NAME))
{
throw new SecurityException(Dict::Format('UI:Login:Error:AccessAdmin')); throw new SecurityException(Dict::Format('UI:Login:Error:AccessAdmin'));
} }
} }
@@ -348,33 +369,33 @@ class URP_UserOrg extends UserRightsBaseClassGUI
{ {
public static function Init() public static function Init()
{ {
$aParams = $aParams = array
[ (
"category" => "addon/userrights,grant_by_profile", "category" => "addon/userrights,grant_by_profile",
"key_type" => "autoincrement", "key_type" => "autoincrement",
"name_attcode" => ["userlogin", "allowed_org_name"], "name_attcode" => array("userlogin", "allowed_org_name"),
"state_attcode" => "", "state_attcode" => "",
"reconc_keys" => [], "reconc_keys" => array(),
"db_table" => "priv_urp_userorg", "db_table" => "priv_urp_userorg",
"db_key_field" => "id", "db_key_field" => "id",
"db_finalclass_field" => "", "db_finalclass_field" => "",
]; );
MetaModel::Init_Params($aParams); MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes(); //MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeExternalKey("userid", ["targetclass" => "User", "jointype" => "", "allowed_values" => null, "sql" => "userid", "is_null_allowed" => false, "on_target_delete" => DEL_AUTO, "depends_on" => []])); MetaModel::Init_AddAttribute(new AttributeExternalKey("userid", array("targetclass"=>"User", "jointype"=> "", "allowed_values"=>null, "sql"=>"userid", "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeExternalField("userlogin", ["allowed_values" => null, "extkey_attcode" => 'userid', "target_attcode" => "login"])); MetaModel::Init_AddAttribute(new AttributeExternalField("userlogin", array("allowed_values"=>null, "extkey_attcode"=> 'userid', "target_attcode"=>"login")));
MetaModel::Init_AddAttribute(new AttributeExternalKey("allowed_org_id", ["targetclass" => "Organization", "jointype" => "", "allowed_values" => null, "sql" => "allowed_org_id", "is_null_allowed" => false, "on_target_delete" => DEL_AUTO, "depends_on" => []])); MetaModel::Init_AddAttribute(new AttributeExternalKey("allowed_org_id", array("targetclass"=>"Organization", "jointype"=> "", "allowed_values"=>null, "sql"=>"allowed_org_id", "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeExternalField("allowed_org_name", ["allowed_values" => null, "extkey_attcode" => 'allowed_org_id', "target_attcode" => "name"])); MetaModel::Init_AddAttribute(new AttributeExternalField("allowed_org_name", array("allowed_values"=>null, "extkey_attcode"=> 'allowed_org_id', "target_attcode"=>"name")));
MetaModel::Init_AddAttribute(new AttributeString("reason", ["allowed_values" => null, "sql" => "reason", "default_value" => null, "is_null_allowed" => true, "depends_on" => []])); MetaModel::Init_AddAttribute(new AttributeString("reason", array("allowed_values"=>null, "sql"=>"reason", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
// Display lists // Display lists
MetaModel::Init_SetZListItems('details', ['userid', 'allowed_org_id', 'reason']); // Attributes to be displayed for the complete details MetaModel::Init_SetZListItems('details', array('userid', 'allowed_org_id', 'reason')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', ['allowed_org_id', 'reason']); // Attributes to be displayed for a list MetaModel::Init_SetZListItems('list', array('allowed_org_id', 'reason')); // Attributes to be displayed for a list
// Search criteria // Search criteria
MetaModel::Init_SetZListItems('standard_search', ['userid', 'allowed_org_id']); // Criteria of the std search form MetaModel::Init_SetZListItems('standard_search', array('userid', 'allowed_org_id')); // Criteria of the std search form
MetaModel::Init_SetZListItems('advanced_search', ['userid', 'allowed_org_id']); // Criteria of the advanced search form MetaModel::Init_SetZListItems('advanced_search', array('userid', 'allowed_org_id')); // Criteria of the advanced search form
} }
protected function OnInsert() protected function OnInsert()
@@ -397,37 +418,40 @@ class URP_UserOrg extends UserRightsBaseClassGUI
*/ */
protected function CheckIfOrgIsAllowed() protected function CheckIfOrgIsAllowed()
{ {
if (!UserRights::IsLoggedIn() || UserRights::IsAdministrator()) { if (!UserRights::IsLoggedIn() || UserRights::IsAdministrator()) { return; }
return;
}
$oUser = UserRights::GetUserObject(); $oUser = UserRights::GetUserObject();
$oAddon = UserRights::GetModuleInstance(); $oAddon = UserRights::GetModuleInstance();
$aOrgs = $oAddon->GetUserOrgs($oUser, ''); $aOrgs = $oAddon->GetUserOrgs($oUser, '');
if (count($aOrgs) > 0) { if (count($aOrgs) > 0)
{
$iOrigOrgId = $this->GetOriginal('allowed_org_id'); $iOrigOrgId = $this->GetOriginal('allowed_org_id');
if ((!empty($iOrigOrgId) && !in_array($iOrigOrgId, $aOrgs)) || !in_array($this->Get('allowed_org_id'), $aOrgs)) { if ((!empty($iOrigOrgId) && !in_array($iOrigOrgId, $aOrgs)) || !in_array($this->Get('allowed_org_id'), $aOrgs))
{
throw new SecurityException(Dict::Format('Class:User/Error:OrganizationNotAllowed')); throw new SecurityException(Dict::Format('Class:User/Error:OrganizationNotAllowed'));
} }
} }
} }
} }
class UserRightsProfile extends UserRightsAddOnAPI class UserRightsProfile extends UserRightsAddOnAPI
{ {
public static $m_aActionCodes = [ static public $m_aActionCodes = array(
UR_ACTION_READ => 'r', UR_ACTION_READ => 'r',
UR_ACTION_MODIFY => 'w', UR_ACTION_MODIFY => 'w',
UR_ACTION_DELETE => 'd', UR_ACTION_DELETE => 'd',
UR_ACTION_BULK_READ => 'br', UR_ACTION_BULK_READ => 'br',
UR_ACTION_BULK_MODIFY => 'bw', UR_ACTION_BULK_MODIFY => 'bw',
UR_ACTION_BULK_DELETE => 'bd', UR_ACTION_BULK_DELETE => 'bd',
]; );
/** /**
* @var array $aUsersProfilesList Cache of users' profiles. Hash array of user ID => [profile ID => profile friendlyname, profile ID => profile friendlyname, ...] * @var array $aUsersProfilesList Cache of users' profiles. Hash array of user ID => [profile ID => profile friendlyname, profile ID => profile friendlyname, ...]
* @since 2.7.10 3.0.4 3.1.1 3.2.0 N°6887 * @since 2.7.10 3.0.4 3.1.1 3.2.0 N°6887
*/ */
private $aUsersProfilesList = []; private $aUsersProfilesList = [];
// Installation: create the very first user // Installation: create the very first user
@@ -448,7 +472,8 @@ class UserRightsProfile extends UserRightsAddOnAPI
$oContact = MetaModel::NewObject('Person'); $oContact = MetaModel::NewObject('Person');
$oContact->Set('name', 'My last name'); $oContact->Set('name', 'My last name');
$oContact->Set('first_name', 'My first name'); $oContact->Set('first_name', 'My first name');
if (MetaModel::IsValidAttCode('Person', 'org_id')) { if (MetaModel::IsValidAttCode('Person', 'org_id'))
{
$oContact->Set('org_id', $iOrgId); $oContact->Set('org_id', $iOrgId);
} }
$oContact->Set('email', 'my.email@foo.org'); $oContact->Set('email', 'my.email@foo.org');
@@ -456,17 +481,20 @@ class UserRightsProfile extends UserRightsAddOnAPI
} }
} }
$oUser = new UserLocal(); $oUser = new UserLocal();
$oUser->Set('login', $sAdminUser); $oUser->Set('login', $sAdminUser);
$oUser->Set('password', $sAdminPwd); $oUser->Set('password', $sAdminPwd);
if (MetaModel::IsValidAttCode('UserLocal', 'contactid') && ($iContactId != 0)) { if (MetaModel::IsValidAttCode('UserLocal', 'contactid') && ($iContactId != 0))
{
$oUser->Set('contactid', $iContactId); $oUser->Set('contactid', $iContactId);
} }
$oUser->Set('language', $sLanguage); // Language was chosen during the installation $oUser->Set('language', $sLanguage); // Language was chosen during the installation
// Add this user to the very specific 'admin' profile // Add this user to the very specific 'admin' profile
$oAdminProfile = MetaModel::GetObjectFromOQL("SELECT URP_Profiles WHERE name = :name", ['name' => ADMIN_PROFILE_NAME], true /*all data*/); $oAdminProfile = MetaModel::GetObjectFromOQL("SELECT URP_Profiles WHERE name = :name", array('name' => ADMIN_PROFILE_NAME), true /*all data*/);
if (is_object($oAdminProfile)) { if (is_object($oAdminProfile))
{
$oUserProfile = new URP_UserProfile(); $oUserProfile = new URP_UserProfile();
$oUserProfile->Set('profileid', $oAdminProfile->GetKey()); $oUserProfile->Set('profileid', $oAdminProfile->GetKey());
$oUserProfile->Set('reason', 'By definition, the administrator must have the administrator profile'); $oUserProfile->Set('reason', 'By definition, the administrator must have the administrator profile');
@@ -481,11 +509,11 @@ class UserRightsProfile extends UserRightsAddOnAPI
{ {
} }
protected $m_aUserOrgs = []; // userid -> array of orgid protected $m_aUserOrgs = array(); // userid -> array of orgid
protected $m_aAdministrators = null; // [user id] protected $m_aAdministrators = null; // [user id]
// Built on demand, could be optimized if necessary (doing a query for each attribute that needs to be read) // Built on demand, could be optimized if necessary (doing a query for each attribute that needs to be read)
protected $m_aObjectActionGrants = []; protected $m_aObjectActionGrants = array();
/** /**
* Read and cache organizations allowed to the given user * Read and cache organizations allowed to the given user
@@ -500,25 +528,31 @@ class UserRightsProfile extends UserRightsAddOnAPI
public function GetUserOrgs($oUser, $sClass) public function GetUserOrgs($oUser, $sClass)
{ {
$iUser = $oUser->GetKey(); $iUser = $oUser->GetKey();
if (!array_key_exists($iUser, $this->m_aUserOrgs)) { if (!array_key_exists($iUser, $this->m_aUserOrgs))
$this->m_aUserOrgs[$iUser] = []; {
$this->m_aUserOrgs[$iUser] = array();
$sHierarchicalKeyCode = MetaModel::IsHierarchicalClass('Organization'); $sHierarchicalKeyCode = MetaModel::IsHierarchicalClass('Organization');
if ($sHierarchicalKeyCode !== false) { if ($sHierarchicalKeyCode !== false)
{
$sUserOrgQuery = 'SELECT UserOrg, Org FROM Organization AS Org JOIN Organization AS Root ON Org.'.$sHierarchicalKeyCode.' BELOW Root.id JOIN URP_UserOrg AS UserOrg ON UserOrg.allowed_org_id = Root.id WHERE UserOrg.userid = :userid'; $sUserOrgQuery = 'SELECT UserOrg, Org FROM Organization AS Org JOIN Organization AS Root ON Org.'.$sHierarchicalKeyCode.' BELOW Root.id JOIN URP_UserOrg AS UserOrg ON UserOrg.allowed_org_id = Root.id WHERE UserOrg.userid = :userid';
$oUserOrgSet = new DBObjectSet(DBObjectSearch::FromOQL_AllData($sUserOrgQuery), [], ['userid' => $iUser]); $oUserOrgSet = new DBObjectSet(DBObjectSearch::FromOQL_AllData($sUserOrgQuery), array(), array('userid' => $iUser));
while ($aRow = $oUserOrgSet->FetchAssoc()) { while ($aRow = $oUserOrgSet->FetchAssoc())
{
$oOrg = $aRow['Org']; $oOrg = $aRow['Org'];
$this->m_aUserOrgs[$iUser][] = $oOrg->GetKey(); $this->m_aUserOrgs[$iUser][] = $oOrg->GetKey();
} }
} else { }
else
{
$oSearch = new DBObjectSearch('URP_UserOrg'); $oSearch = new DBObjectSearch('URP_UserOrg');
$oSearch->AllowAllData(); $oSearch->AllowAllData();
$oCondition = new BinaryExpression(new FieldExpression('userid'), '=', new VariableExpression('userid')); $oCondition = new BinaryExpression(new FieldExpression('userid'), '=', new VariableExpression('userid'));
$oSearch->AddConditionExpression($oCondition); $oSearch->AddConditionExpression($oCondition);
$oUserOrgSet = new DBObjectSet($oSearch, [], ['userid' => $iUser]); $oUserOrgSet = new DBObjectSet($oSearch, array(), array('userid' => $iUser));
while ($oUserOrg = $oUserOrgSet->Fetch()) { while ($oUserOrg = $oUserOrgSet->Fetch())
{
$this->m_aUserOrgs[$iUser][] = $oUserOrg->Get('allowed_org_id'); $this->m_aUserOrgs[$iUser][] = $oUserOrg->Get('allowed_org_id');
} }
} }
@@ -529,19 +563,21 @@ class UserRightsProfile extends UserRightsAddOnAPI
public function ResetCache() public function ResetCache()
{ {
// Loaded by Load cache // Loaded by Load cache
$this->m_aUserOrgs = []; $this->m_aUserOrgs = array();
// Cache // Cache
$this->m_aObjectActionGrants = []; $this->m_aObjectActionGrants = array();
$this->m_aAdministrators = null; $this->m_aAdministrators = null;
} }
public function LoadCache() public function LoadCache()
{ {
static $bSharedObjectInitialized = false; static $bSharedObjectInitialized = false;
if (!$bSharedObjectInitialized) { if (!$bSharedObjectInitialized)
{
$bSharedObjectInitialized = true; $bSharedObjectInitialized = true;
if (self::HasSharing()) { if (self::HasSharing())
{
SharedObject::InitSharedClassProperties(); SharedObject::InitSharedClassProperties();
} }
} }
@@ -579,40 +615,45 @@ class UserRightsProfile extends UserRightsAddOnAPI
*/ */
public function ListProfiles($oUser) public function ListProfiles($oUser)
{ {
$aRet = []; $aRet = array();
$oSearch = new DBObjectSearch('URP_UserProfile'); $oSearch = new DBObjectSearch('URP_UserProfile');
$oSearch->AllowAllData(); $oSearch->AllowAllData();
$oSearch->NoContextParameters(); $oSearch->NoContextParameters();
$oSearch->Addcondition('userid', $oUser->GetKey(), '='); $oSearch->Addcondition('userid', $oUser->GetKey(), '=');
$oProfiles = new DBObjectSet($oSearch); $oProfiles = new DBObjectSet($oSearch);
while ($oUserProfile = $oProfiles->Fetch()) { while ($oUserProfile = $oProfiles->Fetch())
{
$aRet[$oUserProfile->Get('profileid')] = $oUserProfile->Get('profileid_friendlyname'); $aRet[$oUserProfile->Get('profileid')] = $oUserProfile->Get('profileid_friendlyname');
} }
return $aRet; return $aRet;
} }
public function GetSelectFilter($oUser, $sClass, $aSettings = []) public function GetSelectFilter($oUser, $sClass, $aSettings = array())
{ {
$this->LoadCache(); $this->LoadCache();
// Let us pass an administrator for bypassing the grant matrix check in order to test this method without the need to set up a complex profile // Let us pass an administrator for bypassing the grant matrix check in order to test this method without the need to set up a complex profile
// In the nominal case Administrators never end up here (since they completely bypass GetSelectFilter) // In the nominal case Administrators never end up here (since they completely bypass GetSelectFilter)
if (!static::IsAdministrator($oUser) && (MetaModel::HasCategory($sClass, 'silo') || MetaModel::HasCategory($sClass, 'bizmodel'))) { if (!static::IsAdministrator($oUser) && (MetaModel::HasCategory($sClass, 'silo') || MetaModel::HasCategory($sClass, 'bizmodel')))
{
// N°4354 - Categories 'silo' and 'bizmodel' do check the grant matrix. Whereas 'filter' always allows to read (but the result can be filtered) // N°4354 - Categories 'silo' and 'bizmodel' do check the grant matrix. Whereas 'filter' always allows to read (but the result can be filtered)
$aObjectPermissions = $this->GetUserActionGrant($oUser, $sClass, UR_ACTION_READ); $aObjectPermissions = $this->GetUserActionGrant($oUser, $sClass, UR_ACTION_READ);
if ($aObjectPermissions['permission'] == UR_ALLOWED_NO) { if ($aObjectPermissions['permission'] == UR_ALLOWED_NO)
{
return false; return false;
} }
} }
$oFilter = true; $oFilter = true;
$aConditions = []; $aConditions = array();
// Determine if this class is part of a silo and build the filter for it // Determine if this class is part of a silo and build the filter for it
$sAttCode = self::GetOwnerOrganizationAttCode($sClass); $sAttCode = UserRights::GetOwnerOrganizationAttCode($sClass);
if (!is_null($sAttCode)) { if (!is_null($sAttCode))
{
$aUserOrgs = $this->GetUserOrgs($oUser, $sClass); $aUserOrgs = $this->GetUserOrgs($oUser, $sClass);
if (count($aUserOrgs) > 0) { if (count($aUserOrgs) > 0)
{
$oFilter = $this->MakeSelectFilter($sClass, $aUserOrgs, $aSettings, $sAttCode); $oFilter = $this->MakeSelectFilter($sClass, $aUserOrgs, $aSettings, $sAttCode);
} }
// else: No org means 'any org' // else: No org means 'any org'
@@ -621,15 +662,20 @@ class UserRightsProfile extends UserRightsAddOnAPI
// Specific conditions to hide, for non-administrators, the Administrator Users, the Administrator Profile and related links // Specific conditions to hide, for non-administrators, the Administrator Users, the Administrator Profile and related links
// Note: when logged as an administrator, GetSelectFilter is completely bypassed. // Note: when logged as an administrator, GetSelectFilter is completely bypassed.
if ($this->AdministratorsAreHidden()) { if ($this->AdministratorsAreHidden())
if ($sClass == 'URP_Profiles') { {
if ($sClass == 'URP_Profiles')
{
$oExpression = new FieldExpression('id', $sClass); $oExpression = new FieldExpression('id', $sClass);
$oScalarExpr = new ScalarExpression(1); $oScalarExpr = new ScalarExpression(1);
$aConditions[] = new BinaryExpression($oExpression, '!=', $oScalarExpr); $aConditions[] = new BinaryExpression($oExpression, '!=', $oScalarExpr);
} elseif (($sClass == 'URP_UserProfile') || ($sClass == 'User') || (is_subclass_of($sClass, 'User'))) { }
else if (($sClass == 'URP_UserProfile') || ($sClass == 'User') || (is_subclass_of($sClass, 'User')))
{
$aAdministrators = $this->GetAdministrators(); $aAdministrators = $this->GetAdministrators();
if (count($aAdministrators) > 0) { if (count($aAdministrators) > 0)
{
$sAttCode = ($sClass == 'URP_UserProfile') ? 'userid' : 'id'; $sAttCode = ($sClass == 'URP_UserProfile') ? 'userid' : 'id';
$oExpression = new FieldExpression($sAttCode, $sClass); $oExpression = new FieldExpression($sAttCode, $sClass);
$oListExpr = ListExpression::FromScalars($aAdministrators); $oListExpr = ListExpression::FromScalars($aAdministrators);
@@ -639,14 +685,17 @@ class UserRightsProfile extends UserRightsAddOnAPI
} }
// Handling of the added conditions // Handling of the added conditions
if (count($aConditions) > 0) { if (count($aConditions) > 0)
if ($oFilter === true) { {
if($oFilter === true)
{
// No 'silo' filter, let's build a clean one // No 'silo' filter, let's build a clean one
$oFilter = new DBObjectSearch($sClass); $oFilter = new DBObjectSearch($sClass);
} }
// Add the conditions to the filter // Add the conditions to the filter
foreach ($aConditions as $oCondition) { foreach($aConditions as $oCondition)
{
$oFilter->AddConditionExpression($oCondition); $oFilter->AddConditionExpression($oCondition);
} }
} }
@@ -661,9 +710,10 @@ class UserRightsProfile extends UserRightsAddOnAPI
*/ */
private function GetAdministrators() private function GetAdministrators()
{ {
if ($this->m_aAdministrators === null) { if ($this->m_aAdministrators === null)
{
// Find all administrators // Find all administrators
$this->m_aAdministrators = []; $this->m_aAdministrators = array();
$oAdministratorsFilter = new DBObjectSearch('User'); $oAdministratorsFilter = new DBObjectSearch('User');
$oLnkFilter = new DBObjectSearch('URP_UserProfile'); $oLnkFilter = new DBObjectSearch('URP_UserProfile');
$oExpression = new FieldExpression('profileid', 'URP_UserProfile'); $oExpression = new FieldExpression('profileid', 'URP_UserProfile');
@@ -673,8 +723,9 @@ class UserRightsProfile extends UserRightsAddOnAPI
$oAdministratorsFilter->AddCondition_ReferencedBy($oLnkFilter, 'userid'); $oAdministratorsFilter->AddCondition_ReferencedBy($oLnkFilter, 'userid');
$oAdministratorsFilter->AllowAllData(true); // Mandatory to prevent infinite recursion !! $oAdministratorsFilter->AllowAllData(true); // Mandatory to prevent infinite recursion !!
$oSet = new DBObjectSet($oAdministratorsFilter); $oSet = new DBObjectSet($oAdministratorsFilter);
$oSet->OptimizeColumnLoad(['User' => ['login']]); $oSet->OptimizeColumnLoad(array('User' => array('login')));
while ($oUser = $oSet->Fetch()) { while($oUser = $oSet->Fetch())
{
$this->m_aAdministrators[] = $oUser->GetKey(); $this->m_aAdministrators[] = $oUser->GetKey();
} }
} }
@@ -690,6 +741,7 @@ class UserRightsProfile extends UserRightsAddOnAPI
return ((bool)MetaModel::GetConfig()->Get('security.hide_administrators')); return ((bool)MetaModel::GetConfig()->Get('security.hide_administrators'));
} }
// This verb has been made public to allow the development of an accurate feedback for the current configuration // This verb has been made public to allow the development of an accurate feedback for the current configuration
public function GetProfileActionGrant($iProfile, $sClass, $sAction) public function GetProfileActionGrant($iProfile, $sClass, $sAction)
{ {
@@ -706,29 +758,33 @@ class UserRightsProfile extends UserRightsAddOnAPI
// load and cache permissions for the current user on the given class // load and cache permissions for the current user on the given class
// //
$iUser = $oUser->GetKey(); $iUser = $oUser->GetKey();
if (isset($this->m_aObjectActionGrants[$iUser][$sClass][$iActionCode])) { if (isset($this->m_aObjectActionGrants[$iUser][$sClass][$iActionCode])){
$aTest = $this->m_aObjectActionGrants[$iUser][$sClass][$iActionCode]; $aTest = $this->m_aObjectActionGrants[$iUser][$sClass][$iActionCode];
if (is_array($aTest)) { if (is_array($aTest)) return $aTest;
return $aTest;
}
} }
$sAction = self::$m_aActionCodes[$iActionCode]; $sAction = self::$m_aActionCodes[$iActionCode];
$bStatus = null; $bStatus = null;
// Cache user's profiles // Cache user's profiles
if (false === array_key_exists($iUser, $this->aUsersProfilesList)) { if(false === array_key_exists($iUser, $this->aUsersProfilesList)){
$this->aUsersProfilesList[$iUser] = UserRights::ListProfiles($oUser); $this->aUsersProfilesList[$iUser] = UserRights::ListProfiles($oUser);
} }
// Call the API of UserRights because it caches the list for us // Call the API of UserRights because it caches the list for us
foreach ($this->aUsersProfilesList[$iUser] as $iProfile => $oProfile) { foreach($this->aUsersProfilesList[$iUser] as $iProfile => $oProfile)
{
$bGrant = $this->GetProfileActionGrant($iProfile, $sClass, $sAction); $bGrant = $this->GetProfileActionGrant($iProfile, $sClass, $sAction);
if (!is_null($bGrant)) { if (!is_null($bGrant))
if ($bGrant) { {
if (is_null($bStatus)) { if ($bGrant)
{
if (is_null($bStatus))
{
$bStatus = true; $bStatus = true;
} }
} else { }
else
{
$bStatus = false; $bStatus = false;
} }
} }
@@ -736,9 +792,9 @@ class UserRightsProfile extends UserRightsAddOnAPI
$iPermission = $bStatus ? UR_ALLOWED_YES : UR_ALLOWED_NO; $iPermission = $bStatus ? UR_ALLOWED_YES : UR_ALLOWED_NO;
$aRes = [ $aRes = array(
'permission' => $iPermission, 'permission' => $iPermission,
]; );
$this->m_aObjectActionGrants[$iUser][$sClass][$iActionCode] = $aRes; $this->m_aObjectActionGrants[$iUser][$sClass][$iActionCode] = $aRes;
return $aRes; return $aRes;
} }
@@ -753,46 +809,64 @@ class UserRightsProfile extends UserRightsAddOnAPI
// Note: In most cases the object set is ignored because it was interesting to optimize for huge data sets // Note: In most cases the object set is ignored because it was interesting to optimize for huge data sets
// and acceptable to consider only the root class of the object set // and acceptable to consider only the root class of the object set
if ($iPermission != UR_ALLOWED_YES) { if ($iPermission != UR_ALLOWED_YES)
{
// It is already NO for everyone... that's the final word! // It is already NO for everyone... that's the final word!
} elseif ($iActionCode == UR_ACTION_READ) { }
elseif ($iActionCode == UR_ACTION_READ)
{
// We are protected by GetSelectFilter: the object set contains objects allowed or shared for reading // We are protected by GetSelectFilter: the object set contains objects allowed or shared for reading
} elseif ($iActionCode == UR_ACTION_BULK_READ) { }
elseif ($iActionCode == UR_ACTION_BULK_READ)
{
// We are protected by GetSelectFilter: the object set contains objects allowed or shared for reading // We are protected by GetSelectFilter: the object set contains objects allowed or shared for reading
} elseif ($oInstanceSet) { }
elseif ($oInstanceSet)
{
// We are protected by GetSelectFilter: the object set contains objects allowed or shared for reading // We are protected by GetSelectFilter: the object set contains objects allowed or shared for reading
// We have to answer NO for objects shared for reading purposes // We have to answer NO for objects shared for reading purposes
if (self::HasSharing() && SharedObject::GetSharedClassProperties($sClass)) { if (self::HasSharing())
// This class is shared, GetSelectFilter may allow some objects for read only {
// But currently we are checking whether the objects might be written... $aClassProps = SharedObject::GetSharedClassProperties($sClass);
// Let's exclude the objects based on the relevant criteria if ($aClassProps)
{
// This class is shared, GetSelectFilter may allow some objects for read only
// But currently we are checking wether the objects might be written...
// Let's exclude the objects based on the relevant criteria
// Use $oInstanceSet only if sClass is the main class $sOrgAttCode = UserRights::GetOwnerOrganizationAttCode($sClass);
if (!is_a($oInstanceSet->GetClass(), $sClass, true)) { if (!is_null($sOrgAttCode))
/** @var \DBObjectSet $oInstanceSet */ {
throw new CoreException(__FUNCTION__.': Expecting object set to be of class '.$sClass.' but it is of class '.$oInstanceSet->GetClass(), ['OQL_Query' => $oInstanceSet->GetFilter()->ToOQL(), 'classes' => $oInstanceSet->GetSelectedClasses()]); $aUserOrgs = $this->GetUserOrgs($oUser, $sClass);
} if (!is_null($aUserOrgs) && count($aUserOrgs) > 0)
$sOrgAttCode = self::GetOwnerOrganizationAttCode($sClass); {
if (!is_null($sOrgAttCode)) { $iCountNO = 0;
$aUserOrgs = $this->GetUserOrgs($oUser, $sClass); $iCountYES = 0;
if (!is_null($aUserOrgs) && count($aUserOrgs) > 0) { $oInstanceSet->Rewind();
$iCountNO = 0; while($oObject = $oInstanceSet->Fetch())
$iCountYES = 0; {
$oInstanceSet->Rewind(); $iOrg = $oObject->Get($sOrgAttCode);
while ($oObject = $oInstanceSet->Fetch()) { if (in_array($iOrg, $aUserOrgs))
$iOrg = $oObject->Get($sOrgAttCode); {
if (in_array($iOrg, $aUserOrgs)) { $iCountYES++;
$iCountYES++; }
} else { else
$iCountNO++; {
$iCountNO++;
}
}
if ($iCountNO == 0)
{
$iPermission = UR_ALLOWED_YES;
}
elseif ($iCountYES == 0)
{
$iPermission = UR_ALLOWED_NO;
}
else
{
$iPermission = UR_ALLOWED_DEPENDS;
} }
}
if ($iCountNO == 0) {
$iPermission = UR_ALLOWED_YES;
} elseif ($iCountYES == 0) {
$iPermission = UR_ALLOWED_NO;
} else {
$iPermission = UR_ALLOWED_DEPENDS;
} }
} }
} }
@@ -823,8 +897,8 @@ class UserRightsProfile extends UserRightsAddOnAPI
// Note: this code is VERY close to the code of IsActionAllowed() // Note: this code is VERY close to the code of IsActionAllowed()
$iUser = $oUser->GetKey(); $iUser = $oUser->GetKey();
// Cache user's profiles // Cache user's profiles
if (false === array_key_exists($iUser, $this->aUsersProfilesList)) { if(false === array_key_exists($iUser, $this->aUsersProfilesList)){
$this->aUsersProfilesList[$iUser] = UserRights::ListProfiles($oUser); $this->aUsersProfilesList[$iUser] = UserRights::ListProfiles($oUser);
} }
@@ -832,14 +906,20 @@ class UserRightsProfile extends UserRightsAddOnAPI
// and acceptable to consider only the root class of the object set // and acceptable to consider only the root class of the object set
$bStatus = null; $bStatus = null;
// Call the API of UserRights because it caches the list for us // Call the API of UserRights because it caches the list for us
foreach ($this->aUsersProfilesList[$iUser] as $iProfile => $oProfile) { foreach($this->aUsersProfilesList[$iUser] as $iProfile => $oProfile)
{
$bGrant = $this->GetClassStimulusGrant($iProfile, $sClass, $sStimulusCode); $bGrant = $this->GetClassStimulusGrant($iProfile, $sClass, $sStimulusCode);
if (!is_null($bGrant)) { if (!is_null($bGrant))
if ($bGrant) { {
if (is_null($bStatus)) { if ($bGrant)
{
if (is_null($bStatus))
{
$bStatus = true; $bStatus = true;
} }
} else { }
else
{
$bStatus = false; $bStatus = false;
} }
} }
@@ -858,25 +938,11 @@ class UserRightsProfile extends UserRightsAddOnAPI
* @param string $sClass * @param string $sClass
* @return string|null Find out which attribute is corresponding the dimension 'owner org' * @return string|null Find out which attribute is corresponding the dimension 'owner org'
* returns null if no such attribute has been found (no filtering should occur) * returns null if no such attribute has been found (no filtering should occur)
* @deprecated 3.3.0 use @UserRights::GetOwnerOrganizationAttCode instead
*/ */
public static function GetOwnerOrganizationAttCode($sClass) public static function GetOwnerOrganizationAttCode($sClass)
{ {
$sAttCode = null; return UserRights::GetOwnerOrganizationAttCode($sClass);
$aCallSpec = [$sClass, 'MapContextParam'];
if (($sClass == 'Organization') || is_subclass_of($sClass, 'Organization')) {
$sAttCode = 'id';
} elseif (is_callable($aCallSpec)) {
$sAttCode = call_user_func($aCallSpec, 'org_id'); // Returns null when there is no mapping for this parameter
if (!MetaModel::IsValidAttCode($sClass, $sAttCode)) {
// Skip silently. The data model checker will tell you something about this...
$sAttCode = null;
}
} elseif (MetaModel::IsValidAttCode($sClass, 'org_id')) {
$sAttCode = 'org_id';
}
return $sAttCode;
} }
/** /**
@@ -885,11 +951,15 @@ class UserRightsProfile extends UserRightsAddOnAPI
protected static function HasSharing() protected static function HasSharing()
{ {
static $bHasSharing; static $bHasSharing;
if (!isset($bHasSharing)) { if (!isset($bHasSharing))
{
$bHasSharing = class_exists('SharedObject'); $bHasSharing = class_exists('SharedObject');
} }
return $bHasSharing; return $bHasSharing;
} }
} }
UserRights::SelectModule('UserRightsProfile'); UserRights::SelectModule('UserRightsProfile');
?>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,4 @@
<?php <?php
/** /**
* Copyright (C) 2013-2024 Combodo SAS * Copyright (C) 2013-2024 Combodo SAS
* *
@@ -26,5 +25,5 @@ require_once('approot.inc.php');
require_once('application/startup.inc.php'); require_once('application/startup.inc.php');
return function (array $context) { return function (array $context) {
return new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']); return new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']);
}; };

View File

@@ -1,5 +1,4 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -49,7 +48,8 @@ class DBSearchHelper
$oHKFilter->AddCondition_PointingTo($oFilter, $sHierarchicalKeyCode, TREE_OPERATOR_BELOW); $oHKFilter->AddCondition_PointingTo($oFilter, $sHierarchicalKeyCode, TREE_OPERATOR_BELOW);
$oSearch->AddCondition_PointingTo($oHKFilter, $sAttCode); $oSearch->AddCondition_PointingTo($oHKFilter, $sAttCode);
} }
} catch (Exception $e) { }
catch (Exception $e) {
// If filtering fails just ignore it // If filtering fails just ignore it
} }
} }
@@ -57,4 +57,4 @@ class DBSearchHelper
} }
} }
} }
} }

View File

@@ -1,5 +1,4 @@
<?php <?php
/** /**
* @deprecated 3.0.0 will be removed in 3.1.0 - moved to sources/Application/WebPage/AjaxPage.php, now loadable using autoloader * @deprecated 3.0.0 will be removed in 3.1.0 - moved to sources/Application/WebPage/AjaxPage.php, now loadable using autoloader
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -17,9 +16,10 @@ use Combodo\iTop\Application\WebPage\AjaxPage;
*/ */
class ajax_page extends AjaxPage class ajax_page extends AjaxPage
{ {
public function __construct($s_title) function __construct($s_title)
{ {
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('ajax_page is deprecated. Please use AjaxPage instead'); DeprecatedCallsLog::NotifyDeprecatedPhpMethod('ajax_page is deprecated. Please use AjaxPage instead');
parent::__construct($s_title); parent::__construct($s_title);
} }
} }

View File

@@ -1,5 +1,4 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0

View File

@@ -1,10 +1,9 @@
<?php <?php
// Copyright (C) 2010-2024 Combodo SAS // Copyright (C) 2010-2024 Combodo SAS
// //
// This file is part of iTop. // This file is part of iTop.
// //
// iTop is free software; you can redistribute it and/or modify // iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by // it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
@@ -17,6 +16,7 @@
// You should have received a copy of the GNU Affero General Public License // You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with iTop. If not, see <http://www.gnu.org/licenses/>
/** /**
* Class ApplicationContext * Class ApplicationContext
* *
@@ -47,16 +47,16 @@ interface iDBObjectURLMaker
/** /**
* Direct end-users to the standard iTop application: UI.php * Direct end-users to the standard iTop application: UI.php
*/ */
class iTopStandardURLMaker implements iDBObjectURLMaker class iTopStandardURLMaker implements iDBObjectURLMaker
{ {
/** /**
* @param string $sClass * @param string $sClass
* @param string $iId * @param string $iId
* *
* @return string * @return string
* @throws \Exception * @throws \Exception
*/ */
public static function MakeObjectURL($sClass, $iId) public static function MakeObjectURL($sClass, $iId)
{ {
$sPage = DBObject::ComputeStandardUIPage($sClass); $sPage = DBObject::ComputeStandardUIPage($sClass);
@@ -68,16 +68,16 @@ class iTopStandardURLMaker implements iDBObjectURLMaker
/** /**
* Direct end-users to the standard Portal application * Direct end-users to the standard Portal application
*/ */
class PortalURLMaker implements iDBObjectURLMaker class PortalURLMaker implements iDBObjectURLMaker
{ {
/** /**
* @param string $sClass * @param string $sClass
* @param string $iId * @param string $iId
* *
* @return string * @return string
* @throws \Exception * @throws \Exception
*/ */
public static function MakeObjectURL($sClass, $iId) public static function MakeObjectURL($sClass, $iId)
{ {
$sAbsoluteUrl = utils::GetAbsoluteUrlAppRoot(); $sAbsoluteUrl = utils::GetAbsoluteUrlAppRoot();
@@ -86,6 +86,7 @@ class PortalURLMaker implements iDBObjectURLMaker
} }
} }
/** /**
* Helper class to store and manipulate the parameters that make the application's context * Helper class to store and manipulate the parameters that make the application's context
* *
@@ -98,117 +99,112 @@ class PortalURLMaker implements iDBObjectURLMaker
*/ */
class ApplicationContext class ApplicationContext
{ {
public static $m_sUrlMakerClass = null; public static $m_sUrlMakerClass = null;
protected static $m_aPluginProperties = null; protected static $m_aPluginProperties = null;
protected static $aDefaultValues; // Cache shared among all instances protected static $aDefaultValues; // Cache shared among all instances
protected $aNames; protected $aNames;
protected $aValues; protected $aValues;
/** /**
* ApplicationContext constructor. * ApplicationContext constructor.
* *
* @param bool $bReadContext * @param bool $bReadContext
* *
* @throws \Exception * @throws \Exception
*/ */
public function __construct($bReadContext = true) public function __construct($bReadContext = true)
{ {
$this->aNames = [ $this->aNames = array(
'org_id', 'menu', 'org_id', 'menu'
]; );
if ($bReadContext) { if ($bReadContext)
$this->ReadContext(); {
$this->ReadContext();
} }
} }
/** /**
* Read the context directly in the PHP parameters (either POST or GET) * Read the context directly in the PHP parameters (either POST or GET)
* return nothing * return nothing
* *
* @throws \Exception * @throws \Exception
*/ */
protected function ReadContext() protected function ReadContext()
{ {
if (!isset(self::$aDefaultValues)) { if (!isset(self::$aDefaultValues))
self::$aDefaultValues = []; {
$aContext = utils::ReadParam('c', [], false, 'context_param'); self::$aDefaultValues = array();
foreach ($this->aNames as $sName) { $aContext = utils::ReadParam('c', array(), false, 'context_param');
foreach($this->aNames as $sName)
{
$sValue = isset($aContext[$sName]) ? $aContext[$sName] : ''; $sValue = isset($aContext[$sName]) ? $aContext[$sName] : '';
// TO DO: check if some of the context parameters are mandatory (or have default values) // TO DO: check if some of the context parameters are mandatory (or have default values)
if (!empty($sValue)) { if (!empty($sValue))
{
self::$aDefaultValues[$sName] = $sValue; self::$aDefaultValues[$sName] = $sValue;
} }
// Hmm, there must be a better (more generic) way to handle the case below: // Hmm, there must be a better (more generic) way to handle the case below:
// When there is only one possible (allowed) organization, the context must be // When there is only one possible (allowed) organization, the context must be
// fixed to this org unless there is only one organization in the system then // fixed to this org unless there is only one organization in the system then
// no filter is applied // no filter is applied
if ($sName == 'org_id') { if ($sName == 'org_id')
if (MetaModel::IsValidClass('Organization')) { {
if (MetaModel::IsValidClass('Organization'))
{
$oSearchFilter = new DBObjectSearch('Organization'); $oSearchFilter = new DBObjectSearch('Organization');
$oSet = new CMDBObjectSet($oSearchFilter); $oSet = new CMDBObjectSet($oSearchFilter);
$iCount = $oSet->CountWithLimit(2); $iCount = $oSet->CountWithLimit(2);
if ($iCount > 1) { if ($iCount > 1)
{
$oSearchFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', true); $oSearchFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', true);
$oSet = new CMDBObjectSet($oSearchFilter); $oSet = new CMDBObjectSet($oSearchFilter);
$iCount = $oSet->CountWithLimit(2); $iCount = $oSet->CountWithLimit(2);
if ($iCount == 1) { if ($iCount == 1)
{
// Only one possible value for org_id, set it in the context // Only one possible value for org_id, set it in the context
$oOrg = $oSet->Fetch(); $oOrg = $oSet->Fetch();
self::$aDefaultValues[$sName] = $oOrg->GetKey(); self::$aDefaultValues[$sName] = $oOrg->GetKey();
} }
} }
} }
} }
} }
} }
$this->aValues = self::$aDefaultValues; $this->aValues = self::$aDefaultValues;
} }
/** /**
* Returns the current value for the given parameter * Returns the current value for the given parameter
* *
* @param string $sParamName Name of the parameter to read * @param string $sParamName Name of the parameter to read
* @param string $defaultValue * @param string $defaultValue
* *
* @return mixed The value for this parameter * @return mixed The value for this parameter
*/ */
public function GetCurrentValue($sParamName, $defaultValue = '') public function GetCurrentValue($sParamName, $defaultValue = '')
{ {
if (isset($this->aValues[$sParamName])) { if (isset($this->aValues[$sParamName]))
{
return $this->aValues[$sParamName]; return $this->aValues[$sParamName];
} }
return $defaultValue; return $defaultValue;
} }
/** /**
* Returns the context as string with the format name1=value1&name2=value2.... * Returns the context as string with the format name1=value1&name2=value2....
* @return string The context as a string to be appended to an href property * @return string The context as a string to be appended to an href property
*
*/ */
public function GetForLink(bool $bWithLeadingAmpersand = false) public function GetForLink()
{ {
// If there are no parameters, return an empty string $aParams = array();
if (empty($this->aValues)) { foreach($this->aValues as $sName => $sValue)
return ''; {
}
// Build the query string with ampersand separated parameters
$aParams = [];
foreach ($this->aValues as $sName => $sValue) {
$aParams[] = "c[$sName]".'='.urlencode($sValue); $aParams[] = "c[$sName]".'='.urlencode($sValue);
} }
$sReturnValue = implode('&', $aParams); return implode("&", $aParams);
// add the leading ampersand if requested
if ($bWithLeadingAmpersand) {
$sReturnValue = '&'.$sReturnValue;
}
return $sReturnValue;
} }
/** /**
* @since 3.0.0 N°2534 - dashboard: bug with autorefresh that deactivates filtering on organisation * @since 3.0.0 N°2534 - dashboard: bug with autorefresh that deactivates filtering on organisation
* Returns the params as c[menu]:..., c[org_id]:.... * Returns the params as c[menu]:..., c[org_id]:....
@@ -267,13 +263,14 @@ class ApplicationContext
*/ */
public function GetAsHash() public function GetAsHash()
{ {
$aReturn = []; $aReturn = array();
foreach ($this->aValues as $sName => $sValue) { foreach($this->aValues as $sName => $sValue)
{
$aReturn["c[$sName]"] = $sValue; $aReturn["c[$sName]"] = $sValue;
} }
return $aReturn; return $aReturn;
} }
/** /**
* Returns an array of the context parameters NAMEs * Returns an array of the context parameters NAMEs
* @return array The list of context parameters * @return array The list of context parameters
@@ -286,10 +283,11 @@ class ApplicationContext
* Removes the specified parameter from the context, for example when the same parameter * Removes the specified parameter from the context, for example when the same parameter
* is already a search parameter * is already a search parameter
* @param string $sParamName Name of the parameter to remove * @param string $sParamName Name of the parameter to remove
*/ */
public function Reset($sParamName) public function Reset($sParamName)
{ {
if (isset($this->aValues[$sParamName])) { if (isset($this->aValues[$sParamName]))
{
unset($this->aValues[$sParamName]); unset($this->aValues[$sParamName]);
} }
} }
@@ -305,22 +303,27 @@ class ApplicationContext
public function InitObjectFromContext(DBObject &$oObj) public function InitObjectFromContext(DBObject &$oObj)
{ {
$sClass = get_class($oObj); $sClass = get_class($oObj);
foreach ($this->GetNames() as $key) { foreach($this->GetNames() as $key)
$aCallSpec = [$sClass, 'MapContextParam']; {
if (is_callable($aCallSpec)) { $aCallSpec = array($sClass, 'MapContextParam');
$sAttCode = call_user_func($aCallSpec, $key); // Returns null when there is no mapping for this parameter if (is_callable($aCallSpec))
{
$sAttCode = call_user_func($aCallSpec, $key); // Returns null when there is no mapping for this parameter
if (MetaModel::IsValidAttCode($sClass, $sAttCode)) { if (MetaModel::IsValidAttCode($sClass, $sAttCode))
{
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode); $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
if ($oAttDef->IsWritable()) { if ($oAttDef->IsWritable())
{
$value = $this->GetCurrentValue($key, null); $value = $this->GetCurrentValue($key, null);
if (!is_null($value)) { if (!is_null($value))
{
$oObj->Set($sAttCode, $value); $oObj->Set($sAttCode, $value);
} }
} }
} }
} }
} }
} }
/** /**
@@ -344,10 +347,14 @@ class ApplicationContext
*/ */
public static function GetUrlMakerClass() public static function GetUrlMakerClass()
{ {
if (is_null(self::$m_sUrlMakerClass)) { if (is_null(self::$m_sUrlMakerClass))
if (Session::IsSet('UrlMakerClass')) { {
if (Session::IsSet('UrlMakerClass'))
{
self::$m_sUrlMakerClass = Session::Get('UrlMakerClass'); self::$m_sUrlMakerClass = Session::Get('UrlMakerClass');
} else { }
else
{
self::$m_sUrlMakerClass = 'iTopStandardURLMaker'; self::$m_sUrlMakerClass = 'iTopStandardURLMaker';
} }
} }
@@ -365,23 +372,23 @@ class ApplicationContext
* @return string the name of the class * @return string the name of the class
* @throws \Exception * @throws \Exception
*/ */
public static function MakeObjectUrl($sObjClass, $sObjKey, $sUrlMakerClass = null, $bWithNavigationContext = true) public static function MakeObjectUrl($sObjClass, $sObjKey, $sUrlMakerClass = null, $bWithNavigationContext = true)
{ {
$oAppContext = new ApplicationContext(); $oAppContext = new ApplicationContext();
if (is_null($sUrlMakerClass)) { if (is_null($sUrlMakerClass)) {
$sUrlMakerClass = self::GetUrlMakerClass(); $sUrlMakerClass = self::GetUrlMakerClass();
} }
$sUrl = call_user_func([$sUrlMakerClass, 'MakeObjectUrl'], $sObjClass, $sObjKey); $sUrl = call_user_func(array($sUrlMakerClass, 'MakeObjectUrl'), $sObjClass, $sObjKey);
if (utils::StrLen($sUrl) > 0) { if (utils::StrLen($sUrl) > 0) {
if ($bWithNavigationContext) { if ($bWithNavigationContext) {
return $sUrl.$oAppContext->GetForLink(true); return $sUrl."&".$oAppContext->GetForLink();
} else { } else {
return $sUrl; return $sUrl;
} }
} else { } else {
return ''; return '';
} }
} }
/** /**
@@ -390,10 +397,13 @@ class ApplicationContext
*/ */
protected static function LoadPluginProperties() protected static function LoadPluginProperties()
{ {
if (Session::IsSet('PluginProperties')) { if (Session::IsSet('PluginProperties'))
{
self::$m_aPluginProperties = Session::Get('PluginProperties'); self::$m_aPluginProperties = Session::Get('PluginProperties');
} else { }
self::$m_aPluginProperties = []; else
{
self::$m_aPluginProperties = array();
} }
} }
@@ -406,9 +416,7 @@ class ApplicationContext
*/ */
public static function SetPluginProperty($sPluginClass, $sProperty, $value) public static function SetPluginProperty($sPluginClass, $sProperty, $value)
{ {
if (is_null(self::$m_aPluginProperties)) { if (is_null(self::$m_aPluginProperties)) self::LoadPluginProperties();
self::LoadPluginProperties();
}
self::$m_aPluginProperties[$sPluginClass][$sProperty] = $value; self::$m_aPluginProperties[$sPluginClass][$sProperty] = $value;
Session::Set(['PluginProperties', $sPluginClass, $sProperty], $value); Session::Set(['PluginProperties', $sPluginClass, $sProperty], $value);
@@ -421,14 +429,15 @@ class ApplicationContext
*/ */
public static function GetPluginProperties($sPluginClass) public static function GetPluginProperties($sPluginClass)
{ {
if (is_null(self::$m_aPluginProperties)) { if (is_null(self::$m_aPluginProperties)) self::LoadPluginProperties();
self::LoadPluginProperties();
}
if (array_key_exists($sPluginClass, self::$m_aPluginProperties)) { if (array_key_exists($sPluginClass, self::$m_aPluginProperties))
{
return self::$m_aPluginProperties[$sPluginClass]; return self::$m_aPluginProperties[$sPluginClass];
} else { }
return []; else
{
return array();
} }
} }

View File

@@ -524,7 +524,7 @@ abstract class AbstractApplicationUIExtension implements iApplicationUIExtension
*/ */
public function EnumUsedAttributes($oObject) public function EnumUsedAttributes($oObject)
{ {
return []; return array();
} }
/** /**
@@ -548,7 +548,7 @@ abstract class AbstractApplicationUIExtension implements iApplicationUIExtension
*/ */
public function EnumAllowedActions(DBObjectSet $oSet) public function EnumAllowedActions(DBObjectSet $oSet)
{ {
return []; return array();
} }
} }
@@ -686,7 +686,7 @@ abstract class AbstractApplicationObjectExtension implements iApplicationObjectE
*/ */
public function OnCheckToWrite($oObject) public function OnCheckToWrite($oObject)
{ {
return []; return array();
} }
/** /**
@@ -694,7 +694,7 @@ abstract class AbstractApplicationObjectExtension implements iApplicationObjectE
*/ */
public function OnCheckToDelete($oObject) public function OnCheckToDelete($oObject)
{ {
return []; return array();
} }
/** /**
@@ -739,21 +739,21 @@ interface iPopupMenuExtension
* $param is a DBObjectSet containing the list of objects * $param is a DBObjectSet containing the list of objects
* @api * @api
*/ */
public const MENU_OBJLIST_ACTIONS = 1; const MENU_OBJLIST_ACTIONS = 1;
/** /**
* Insert an item into the Toolkit menu of a list * Insert an item into the Toolkit menu of a list
* *
* $param is a DBObjectSet containing the list of objects * $param is a DBObjectSet containing the list of objects
* @api * @api
*/ */
public const MENU_OBJLIST_TOOLKIT = 2; const MENU_OBJLIST_TOOLKIT = 2;
/** /**
* Insert an item into the Actions menu on an object details page * Insert an item into the Actions menu on an object details page
* *
* $param is a DBObject instance: the object currently displayed * $param is a DBObject instance: the object currently displayed
* @api * @api
*/ */
public const MENU_OBJDETAILS_ACTIONS = 3; const MENU_OBJDETAILS_ACTIONS = 3;
/** /**
* Insert an item into the Dashboard menu * Insert an item into the Dashboard menu
* *
@@ -763,14 +763,14 @@ interface iPopupMenuExtension
* $param is a Dashboard instance: the dashboard currently displayed * $param is a Dashboard instance: the dashboard currently displayed
* @api * @api
*/ */
public const MENU_DASHBOARD_ACTIONS = 4; const MENU_DASHBOARD_ACTIONS = 4;
/** /**
* Insert an item into the User menu (upper right corner) * Insert an item into the User menu (upper right corner)
* *
* $param is null * $param is null
* @api * @api
*/ */
public const MENU_USER_ACTIONS = 5; const MENU_USER_ACTIONS = 5;
/** /**
* Insert an item into the Action menu on an object item in an objects list in the portal * Insert an item into the Action menu on an object item in an objects list in the portal
* *
@@ -778,7 +778,7 @@ interface iPopupMenuExtension
* the current line) * the current line)
* @api * @api
*/ */
public const PORTAL_OBJLISTITEM_ACTIONS = 7; const PORTAL_OBJLISTITEM_ACTIONS = 7;
/** /**
* Insert an item into the Action menu on an object details page in the portal * Insert an item into the Action menu on an object details page in the portal
* *
@@ -786,7 +786,7 @@ interface iPopupMenuExtension
* currently displayed) * currently displayed)
* @api * @api
*/ */
public const PORTAL_OBJDETAILS_ACTIONS = 8; const PORTAL_OBJDETAILS_ACTIONS = 8;
/** /**
* Insert an item into the Actions menu of a list in the portal * Insert an item into the Actions menu of a list in the portal
@@ -796,7 +796,7 @@ interface iPopupMenuExtension
* *
* @todo * @todo
*/ */
public const PORTAL_OBJLIST_ACTIONS = 6; const PORTAL_OBJLIST_ACTIONS = 6;
/** /**
* Insert an item into the user menu of the portal * Insert an item into the user menu of the portal
* Note: This is not implemented yet ! * Note: This is not implemented yet !
@@ -805,7 +805,7 @@ interface iPopupMenuExtension
* *
* @todo * @todo
*/ */
public const PORTAL_USER_ACTIONS = 9; const PORTAL_USER_ACTIONS = 9;
/** /**
* Insert an item into the navigation menu of the portal * Insert an item into the navigation menu of the portal
* Note: This is not implemented yet ! * Note: This is not implemented yet !
@@ -814,7 +814,7 @@ interface iPopupMenuExtension
* *
* @todo * @todo
*/ */
public const PORTAL_MENU_ACTIONS = 10; const PORTAL_MENU_ACTIONS = 10;
/** /**
* Get the list of items to be added to a menu. * Get the list of items to be added to a menu.
@@ -864,7 +864,7 @@ abstract class ApplicationPopupMenuItem
$this->sLabel = $sLabel; $this->sLabel = $sLabel;
$this->sTooltip = ''; $this->sTooltip = '';
$this->sIconClass = ''; $this->sIconClass = '';
$this->aCssClasses = []; $this->aCssClasses = array();
} }
/** /**
@@ -920,6 +920,7 @@ abstract class ApplicationPopupMenuItem
$this->aCssClasses[] = $sCssClass; $this->aCssClasses[] = $sCssClass;
} }
/** /**
* @param $sTooltip * @param $sTooltip
* *
@@ -975,7 +976,7 @@ abstract class ApplicationPopupMenuItem
/** @ignore */ /** @ignore */
public function GetLinkedScripts() public function GetLinkedScripts()
{ {
return []; return array();
} }
} }
@@ -1014,13 +1015,13 @@ class URLPopupMenuItem extends ApplicationPopupMenuItem
/** @ignore */ /** @ignore */
public function GetMenuItem() public function GetMenuItem()
{ {
return ['label' => $this->GetLabel(), return array('label' => $this->GetLabel(),
'url' => $this->GetUrl(), 'url' => $this->GetUrl(),
'target' => $this-> GetTarget(), 'target' => $this-> GetTarget(),
'css_classes' => $this->aCssClasses, 'css_classes' => $this->aCssClasses,
'icon_class' => $this->sIconClass, 'icon_class' => $this->sIconClass,
'tooltip' => $this->sTooltip, 'tooltip' => $this->sTooltip
]; );
} }
/** @ignore */ /** @ignore */
@@ -1064,7 +1065,7 @@ class JSPopupMenuItem extends ApplicationPopupMenuItem
* ans $sTarget will be ignored * ans $sTarget will be ignored
* @param array $aIncludeJSFiles An array of file URLs to be included (once) to provide some JS libraries for the page. * @param array $aIncludeJSFiles An array of file URLs to be included (once) to provide some JS libraries for the page.
*/ */
public function __construct($sUID, $sLabel, $sJSCode, $aIncludeJSFiles = []) public function __construct($sUID, $sLabel, $sJSCode, $aIncludeJSFiles = array())
{ {
parent::__construct($sUID, $sLabel); parent::__construct($sUID, $sLabel);
$this->sJsCode = $sJSCode; $this->sJsCode = $sJSCode;
@@ -1076,14 +1077,14 @@ class JSPopupMenuItem extends ApplicationPopupMenuItem
public function GetMenuItem() public function GetMenuItem()
{ {
// Note: the semicolumn is a must here! // Note: the semicolumn is a must here!
return [ return array(
'label' => $this->GetLabel(), 'label' => $this->GetLabel(),
'onclick' => $this->GetJsCode().'; return false;', 'onclick' => $this->GetJsCode().'; return false;',
'url' => $this->GetUrl(), 'url' => $this->GetUrl(),
'css_classes' => $this->GetCssClasses(), 'css_classes' => $this->GetCssClasses(),
'icon_class' => $this->sIconClass, 'icon_class' => $this->sIconClass,
'tooltip' => $this->sTooltip, 'tooltip' => $this->sTooltip
]; );
} }
/** @ignore */ /** @ignore */
@@ -1115,7 +1116,7 @@ class JSPopupMenuItem extends ApplicationPopupMenuItem
*/ */
class SeparatorPopupMenuItem extends ApplicationPopupMenuItem class SeparatorPopupMenuItem extends ApplicationPopupMenuItem
{ {
public static $idx = 0; static $idx = 0;
/** /**
* Constructor * Constructor
@@ -1129,7 +1130,7 @@ class SeparatorPopupMenuItem extends ApplicationPopupMenuItem
/** @ignore */ /** @ignore */
public function GetMenuItem() public function GetMenuItem()
{ {
return ['label' => '<hr class="menu-separator">', 'url' => '', 'css_classes' => $this->aCssClasses]; return array('label' => '<hr class="menu-separator">', 'url' => '', 'css_classes' => $this->aCssClasses);
} }
} }
@@ -1142,6 +1143,7 @@ class SeparatorPopupMenuItem extends ApplicationPopupMenuItem
*/ */
class URLButtonItem extends URLPopupMenuItem class URLButtonItem extends URLPopupMenuItem
{ {
} }
/** /**
@@ -1153,6 +1155,7 @@ class URLButtonItem extends URLPopupMenuItem
*/ */
class JSButtonItem extends JSPopupMenuItem class JSButtonItem extends JSPopupMenuItem
{ {
} }
/** /**
@@ -1501,9 +1504,9 @@ interface iBackofficeDictEntriesPrefixesExtension
*/ */
interface iPortalUIExtension interface iPortalUIExtension
{ {
public const ENUM_PORTAL_EXT_UI_BODY = 'Body'; const ENUM_PORTAL_EXT_UI_BODY = 'Body';
public const ENUM_PORTAL_EXT_UI_NAVIGATION_MENU = 'NavigationMenu'; const ENUM_PORTAL_EXT_UI_NAVIGATION_MENU = 'NavigationMenu';
public const ENUM_PORTAL_EXT_UI_MAIN_CONTENT = 'MainContent'; const ENUM_PORTAL_EXT_UI_MAIN_CONTENT = 'MainContent';
/** /**
* Returns an array of CSS file urls * Returns an array of CSS file urls
@@ -1590,7 +1593,7 @@ abstract class AbstractPortalUIExtension implements iPortalUIExtension
*/ */
public function GetCSSFiles(Container $oContainer) public function GetCSSFiles(Container $oContainer)
{ {
return []; return array();
} }
/** /**
@@ -1606,7 +1609,7 @@ abstract class AbstractPortalUIExtension implements iPortalUIExtension
*/ */
public function GetJSFiles(Container $oContainer) public function GetJSFiles(Container $oContainer)
{ {
return []; return array();
} }
/** /**
@@ -1708,11 +1711,6 @@ interface iRestServiceProvider
public function ExecOperation($sVersion, $sVerb, $aParams); public function ExecOperation($sVersion, $sVerb, $aParams);
} }
interface iRestInputSanitizer
{
public function SanitizeJsonInput(string $sJsonInput): string;
}
/** /**
* Minimal REST response structure. Derive this structure to add response data and error codes. * Minimal REST response structure. Derive this structure to add response data and error codes.
* *
@@ -1726,62 +1724,62 @@ class RestResult
* Result: no issue has been encountered * Result: no issue has been encountered
* @api * @api
*/ */
public const OK = 0; const OK = 0;
/** /**
* Result: missing/wrong credentials or the user does not have enough rights to perform the requested operation * Result: missing/wrong credentials or the user does not have enough rights to perform the requested operation
* @api * @api
*/ */
public const UNAUTHORIZED = 1; const UNAUTHORIZED = 1;
/** /**
* Result: the parameter 'version' is missing * Result: the parameter 'version' is missing
* @api * @api
*/ */
public const MISSING_VERSION = 2; const MISSING_VERSION = 2;
/** /**
* Result: the parameter 'json_data' is missing * Result: the parameter 'json_data' is missing
* @api * @api
*/ */
public const MISSING_JSON = 3; const MISSING_JSON = 3;
/** /**
* Result: the input structure is not a valid JSON string * Result: the input structure is not a valid JSON string
* @api * @api
*/ */
public const INVALID_JSON = 4; const INVALID_JSON = 4;
/** /**
* Result: the parameter 'auth_user' is missing, authentication aborted * Result: the parameter 'auth_user' is missing, authentication aborted
* @api * @api
*/ */
public const MISSING_AUTH_USER = 5; const MISSING_AUTH_USER = 5;
/** /**
* Result: the parameter 'auth_pwd' is missing, authentication aborted * Result: the parameter 'auth_pwd' is missing, authentication aborted
* @api * @api
*/ */
public const MISSING_AUTH_PWD = 6; const MISSING_AUTH_PWD = 6;
/** /**
* Result: no operation is available for the specified version * Result: no operation is available for the specified version
* @api * @api
*/ */
public const UNSUPPORTED_VERSION = 10; const UNSUPPORTED_VERSION = 10;
/** /**
* Result: the requested operation is not valid for the specified version * Result: the requested operation is not valid for the specified version
* @api * @api
*/ */
public const UNKNOWN_OPERATION = 11; const UNKNOWN_OPERATION = 11;
/** /**
* Result: the requested operation cannot be performed because it can cause data (integrity) loss * Result: the requested operation cannot be performed because it can cause data (integrity) loss
* @api * @api
*/ */
public const UNSAFE = 12; const UNSAFE = 12;
/** /**
* Result: the request page number is not valid. It must be an integer greater than 0 * Result: the request page number is not valid. It must be an integer greater than 0
* @api * @api
*/ */
public const INVALID_PAGE = 13; const INVALID_PAGE = 13;
/** /**
* Result: the operation could not be performed, see the message for troubleshooting * Result: the operation could not be performed, see the message for troubleshooting
* @api * @api
*/ */
public const INTERNAL_ERROR = 100; const INTERNAL_ERROR = 100;
/** /**
* Default constructor - ok! * Default constructor - ok!
@@ -1804,14 +1802,6 @@ class RestResult
* @api * @api
*/ */
public $message; public $message;
/**
* Sanitize the content of this result to hide sensitive information
*/
public function SanitizeContent()
{
// The default implementation does nothing
}
} }
/** /**
@@ -1851,13 +1841,17 @@ class RestUtils
*/ */
public static function GetMandatoryParam($oData, $sParamName) public static function GetMandatoryParam($oData, $sParamName)
{ {
if (isset($oData->$sParamName)) { if (isset($oData->$sParamName))
{
return $oData->$sParamName; return $oData->$sParamName;
} else { }
else
{
throw new Exception("Missing parameter '$sParamName'"); throw new Exception("Missing parameter '$sParamName'");
} }
} }
/** /**
* Read an optional parameter from a Rest/Json structure. * Read an optional parameter from a Rest/Json structure.
* *
@@ -1872,13 +1866,17 @@ class RestUtils
*/ */
public static function GetOptionalParam($oData, $sParamName, $default) public static function GetOptionalParam($oData, $sParamName, $default)
{ {
if (isset($oData->$sParamName)) { if (isset($oData->$sParamName))
{
return $oData->$sParamName; return $oData->$sParamName;
} else { }
else
{
return $default; return $default;
} }
} }
/** /**
* Read a class from a Rest/Json structure. * Read a class from a Rest/Json structure.
* *
@@ -1892,13 +1890,15 @@ class RestUtils
public static function GetClass($oData, $sParamName) public static function GetClass($oData, $sParamName)
{ {
$sClass = self::GetMandatoryParam($oData, $sParamName); $sClass = self::GetMandatoryParam($oData, $sParamName);
if (!MetaModel::IsValidClass($sClass)) { if (!MetaModel::IsValidClass($sClass))
{
throw new Exception("$sParamName: '$sClass' is not a valid class'"); throw new Exception("$sParamName: '$sClass' is not a valid class'");
} }
return $sClass; return $sClass;
} }
/** /**
* Read a list of attribute codes from a Rest/Json structure. * Read a list of attribute codes from a Rest/Json structure.
* *
@@ -1914,21 +1914,31 @@ class RestUtils
public static function GetFieldList($sClass, $oData, $sParamName) public static function GetFieldList($sClass, $oData, $sParamName)
{ {
$sFields = self::GetOptionalParam($oData, $sParamName, '*'); $sFields = self::GetOptionalParam($oData, $sParamName, '*');
$aShowFields = []; $aShowFields = array();
if ($sFields == '*') { if ($sFields == '*')
foreach (MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef) { {
foreach (MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef)
{
$aShowFields[$sClass][] = $sAttCode; $aShowFields[$sClass][] = $sAttCode;
} }
} elseif ($sFields == '*+') { }
foreach (MetaModel::EnumChildClasses($sClass, ENUM_CHILD_CLASSES_ALL) as $sRefClass) { elseif ($sFields == '*+')
foreach (MetaModel::ListAttributeDefs($sRefClass) as $sAttCode => $oAttDef) { {
foreach (MetaModel::EnumChildClasses($sClass, ENUM_CHILD_CLASSES_ALL) as $sRefClass)
{
foreach (MetaModel::ListAttributeDefs($sRefClass) as $sAttCode => $oAttDef)
{
$aShowFields[$sRefClass][] = $sAttCode; $aShowFields[$sRefClass][] = $sAttCode;
} }
} }
} else { }
foreach (explode(',', $sFields) as $sAttCode) { else
{
foreach (explode(',', $sFields) as $sAttCode)
{
$sAttCode = trim($sAttCode); $sAttCode = trim($sAttCode);
if (($sAttCode != 'id') && (!MetaModel::IsValidAttCode($sClass, $sAttCode))) { if (($sAttCode != 'id') && (!MetaModel::IsValidAttCode($sClass, $sAttCode)))
{
throw new Exception("$sParamName: invalid attribute code '$sAttCode'"); throw new Exception("$sParamName: invalid attribute code '$sAttCode'");
} }
$aShowFields[$sClass][] = $sAttCode; $aShowFields[$sClass][] = $sAttCode;
@@ -1951,30 +1961,38 @@ class RestUtils
*/ */
protected static function FindObjectFromCriteria($sClass, $oCriteria) protected static function FindObjectFromCriteria($sClass, $oCriteria)
{ {
$aCriteriaReport = []; $aCriteriaReport = array();
if (isset($oCriteria->finalclass)) { if (isset($oCriteria->finalclass))
if (!MetaModel::IsValidClass($oCriteria->finalclass)) { {
if (!MetaModel::IsValidClass($oCriteria->finalclass))
{
throw new Exception("finalclass: Unknown class '".$oCriteria->finalclass."'"); throw new Exception("finalclass: Unknown class '".$oCriteria->finalclass."'");
} }
if (!MetaModel::IsParentClass($sClass, $oCriteria->finalclass)) { if (!MetaModel::IsParentClass($sClass, $oCriteria->finalclass))
{
throw new Exception("finalclass: '".$oCriteria->finalclass."' is not a child class of '$sClass'"); throw new Exception("finalclass: '".$oCriteria->finalclass."' is not a child class of '$sClass'");
} }
$sClass = $oCriteria->finalclass; $sClass = $oCriteria->finalclass;
} }
$oSearch = new DBObjectSearch($sClass); $oSearch = new DBObjectSearch($sClass);
foreach ($oCriteria as $sAttCode => $value) { foreach ($oCriteria as $sAttCode => $value)
{
$realValue = static::MakeValue($sClass, $sAttCode, $value); $realValue = static::MakeValue($sClass, $sAttCode, $value);
$oSearch->AddCondition($sAttCode, $realValue, '='); $oSearch->AddCondition($sAttCode, $realValue, '=');
if (is_object($value) || is_array($value)) { if (is_object($value) || is_array($value))
{
$value = json_encode($value); $value = json_encode($value);
} }
$aCriteriaReport[] = "$sAttCode: $value ($realValue)"; $aCriteriaReport[] = "$sAttCode: $value ($realValue)";
} }
$oSet = new DBObjectSet($oSearch); $oSet = new DBObjectSet($oSearch);
$iCount = $oSet->Count(); $iCount = $oSet->Count();
if ($iCount == 0) { if ($iCount == 0)
{
throw new Exception("No item found with criteria: ".implode(', ', $aCriteriaReport)); throw new Exception("No item found with criteria: ".implode(', ', $aCriteriaReport));
} elseif ($iCount > 1) { }
elseif ($iCount > 1)
{
throw new Exception("Several items found ($iCount) with criteria: ".implode(', ', $aCriteriaReport)); throw new Exception("Several items found ($iCount) with criteria: ".implode(', ', $aCriteriaReport));
} }
$res = $oSet->Fetch(); $res = $oSet->Fetch();
@@ -1982,6 +2000,7 @@ class RestUtils
return $res; return $res;
} }
/** /**
* Find an object from a polymorph search specification (Rest/Json) * Find an object from a polymorph search specification (Rest/Json)
* *
@@ -1997,29 +2016,43 @@ class RestUtils
*/ */
public static function FindObjectFromKey($sClass, $key, $bAllowNullValue = false) public static function FindObjectFromKey($sClass, $key, $bAllowNullValue = false)
{ {
if (is_object($key)) { if (is_object($key))
{
$res = static::FindObjectFromCriteria($sClass, $key); $res = static::FindObjectFromCriteria($sClass, $key);
} elseif (is_numeric($key)) { }
if ($bAllowNullValue && ($key == 0)) { elseif (is_numeric($key))
{
if ($bAllowNullValue && ($key == 0))
{
$res = null; $res = null;
} else { }
else
{
$res = MetaModel::GetObject($sClass, $key, false); $res = MetaModel::GetObject($sClass, $key, false);
if (is_null($res)) { if (is_null($res))
{
throw new Exception("Invalid object $sClass::$key"); throw new Exception("Invalid object $sClass::$key");
} }
} }
} elseif (is_string($key)) { }
elseif (is_string($key))
{
// OQL // OQL
$oSearch = DBObjectSearch::FromOQL($key); $oSearch = DBObjectSearch::FromOQL($key);
$oSet = new DBObjectSet($oSearch); $oSet = new DBObjectSet($oSearch);
$iCount = $oSet->Count(); $iCount = $oSet->Count();
if ($iCount == 0) { if ($iCount == 0)
{
throw new Exception("No item found for query: $key"); throw new Exception("No item found for query: $key");
} elseif ($iCount > 1) { }
elseif ($iCount > 1)
{
throw new Exception("Several items found ($iCount) for query: $key"); throw new Exception("Several items found ($iCount) for query: $key");
} }
$res = $oSet->Fetch(); $res = $oSet->Fetch();
} else { }
else
{
throw new Exception("Wrong format for key"); throw new Exception("Wrong format for key");
} }
@@ -2040,37 +2073,47 @@ class RestUtils
*/ */
public static function GetObjectSetFromKey($sClass, $key, $iLimit = 0, $iOffset = 0) public static function GetObjectSetFromKey($sClass, $key, $iLimit = 0, $iOffset = 0)
{ {
if (is_object($key)) { if (is_object($key))
if (isset($key->finalclass)) { {
if (isset($key->finalclass))
{
$sClass = $key->finalclass; $sClass = $key->finalclass;
if (!MetaModel::IsValidClass($sClass)) { if (!MetaModel::IsValidClass($sClass))
{
throw new Exception("finalclass: Unknown class '$sClass'"); throw new Exception("finalclass: Unknown class '$sClass'");
} }
} }
$oSearch = new DBObjectSearch($sClass); $oSearch = new DBObjectSearch($sClass);
foreach ($key as $sAttCode => $value) { foreach ($key as $sAttCode => $value)
{
$realValue = static::MakeValue($sClass, $sAttCode, $value); $realValue = static::MakeValue($sClass, $sAttCode, $value);
$oSearch->AddCondition($sAttCode, $realValue, '='); $oSearch->AddCondition($sAttCode, $realValue, '=');
} }
} elseif (is_numeric($key)) { }
elseif (is_numeric($key))
{
$oSearch = new DBObjectSearch($sClass); $oSearch = new DBObjectSearch($sClass);
$oSearch->AddCondition('id', $key); $oSearch->AddCondition('id', $key);
} elseif (is_string($key)) { }
elseif (is_string($key))
{
// OQL // OQL
try { try {
$oSearch = DBObjectSearch::FromOQL($key); $oSearch = DBObjectSearch::FromOQL($key);
} catch (Exception $e) { } catch (Exception $e) {
throw new CoreOqlException('Query failed to execute', [ throw new CoreOqlException('Query failed to execute', [
'query' => $key, 'query' => $key,
'exception_class' => get_class($e), 'exception_class' => get_class($e),
'exception_message' => $e->getMessage(), 'exception_message' => $e->getMessage(),
]); ]);
} }
} else { }
else
{
throw new Exception("Wrong format for key"); throw new Exception("Wrong format for key");
} }
$oObjectSet = new DBObjectSet($oSearch, [], [], null, $iLimit, $iOffset); $oObjectSet = new DBObjectSet($oSearch, array(), array(), null, $iLimit, $iOffset);
return $oObjectSet; return $oObjectSet;
} }
@@ -2088,38 +2131,53 @@ class RestUtils
*/ */
public static function MakeValue($sClass, $sAttCode, $value) public static function MakeValue($sClass, $sAttCode, $value)
{ {
try { try
if (!MetaModel::IsValidAttCode($sClass, $sAttCode)) { {
if (!MetaModel::IsValidAttCode($sClass, $sAttCode))
{
throw new Exception("Unknown attribute"); throw new Exception("Unknown attribute");
} }
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode); $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
if ($oAttDef instanceof AttributeExternalKey) { if ($oAttDef instanceof AttributeExternalKey)
{
$oExtKeyObject = static::FindObjectFromKey($oAttDef->GetTargetClass(), $value, true /* allow null */); $oExtKeyObject = static::FindObjectFromKey($oAttDef->GetTargetClass(), $value, true /* allow null */);
$value = ($oExtKeyObject != null) ? $oExtKeyObject->GetKey() : 0; $value = ($oExtKeyObject != null) ? $oExtKeyObject->GetKey() : 0;
} elseif ($oAttDef instanceof AttributeLinkedSet) { }
if (!is_array($value)) { elseif ($oAttDef instanceof AttributeLinkedSet)
{
if (!is_array($value))
{
throw new Exception("A link set must be defined by an array of objects"); throw new Exception("A link set must be defined by an array of objects");
} }
$sLnkClass = $oAttDef->GetLinkedClass(); $sLnkClass = $oAttDef->GetLinkedClass();
$aLinks = []; $aLinks = array();
foreach ($value as $oValues) { foreach ($value as $oValues)
{
$oLnk = static::MakeObjectFromFields($sLnkClass, $oValues); $oLnk = static::MakeObjectFromFields($sLnkClass, $oValues);
// Fix for N°1939 // Fix for N°1939
if (($oAttDef instanceof AttributeLinkedSetIndirect) && ($oLnk->Get($oAttDef->GetExtKeyToRemote()) == 0)) { if (($oAttDef instanceof AttributeLinkedSetIndirect) && ($oLnk->Get($oAttDef->GetExtKeyToRemote()) == 0))
{
continue; continue;
} }
$aLinks[] = $oLnk; $aLinks[] = $oLnk;
} }
$value = DBObjectSet::FromArray($sLnkClass, $aLinks); $value = DBObjectSet::FromArray($sLnkClass, $aLinks);
} elseif ($oAttDef instanceof AttributeTagSet) { }
if (!is_array($value)) { elseif ($oAttDef instanceof AttributeTagSet)
{
if (!is_array($value))
{
throw new Exception("A tag set must be defined by an array of tag codes"); throw new Exception("A tag set must be defined by an array of tag codes");
} }
$value = $oAttDef->FromJSONToValue($value); $value = $oAttDef->FromJSONToValue($value);
} else { }
else
{
$value = $oAttDef->FromJSONToValue($value); $value = $oAttDef->FromJSONToValue($value);
} }
} catch (Exception $e) { }
catch (Exception $e)
{
throw new Exception("$sAttCode: ".$e->getMessage(), $e->getCode()); throw new Exception("$sAttCode: ".$e->getMessage(), $e->getCode());
} }
@@ -2139,11 +2197,15 @@ class RestUtils
public static function MakeObjectFromFields($sClass, $aFields) public static function MakeObjectFromFields($sClass, $aFields)
{ {
$oObject = MetaModel::NewObject($sClass); $oObject = MetaModel::NewObject($sClass);
foreach ($aFields as $sAttCode => $value) { foreach ($aFields as $sAttCode => $value)
{
$realValue = static::MakeValue($sClass, $sAttCode, $value); $realValue = static::MakeValue($sClass, $sAttCode, $value);
try { try
{
$oObject->Set($sAttCode, $realValue); $oObject->Set($sAttCode, $realValue);
} catch (Exception $e) { }
catch (Exception $e)
{
throw new Exception("$sAttCode: ".$e->getMessage(), $e->getCode()); throw new Exception("$sAttCode: ".$e->getMessage(), $e->getCode());
} }
} }
@@ -2164,11 +2226,15 @@ class RestUtils
public static function UpdateObjectFromFields($oObject, $aFields) public static function UpdateObjectFromFields($oObject, $aFields)
{ {
$sClass = get_class($oObject); $sClass = get_class($oObject);
foreach ($aFields as $sAttCode => $value) { foreach ($aFields as $sAttCode => $value)
{
$realValue = static::MakeValue($sClass, $sAttCode, $value); $realValue = static::MakeValue($sClass, $sAttCode, $value);
try { try
{
$oObject->Set($sAttCode, $realValue); $oObject->Set($sAttCode, $realValue);
} catch (Exception $e) { }
catch (Exception $e)
{
throw new Exception("$sAttCode: ".$e->getMessage(), $e->getCode()); throw new Exception("$sAttCode: ".$e->getMessage(), $e->getCode());
} }
} }
@@ -2177,6 +2243,7 @@ class RestUtils
} }
} }
/** /**
* Helpers for modules extensibility, with discover performed by the MetaModel. * Helpers for modules extensibility, with discover performed by the MetaModel.
* *
@@ -2199,21 +2266,21 @@ interface iModuleExtension
*/ */
interface iKPILoggerExtension interface iKPILoggerExtension
{ {
/** /**
* Init the statistics collected * Init the statistics collected
* *
* @return void * @return void
*/ */
public function InitStats(); public function InitStats();
/** /**
* Add a new KPI to the stats * Add a new KPI to the stats
* *
* @param \Combodo\iTop\Core\Kpi\KpiLogData $oKpiLogData * @param \Combodo\iTop\Core\Kpi\KpiLogData $oKpiLogData
* *
* @return mixed * @return mixed
*/ */
public function LogOperation($oKpiLogData); public function LogOperation($oKpiLogData);
} }
/** /**
@@ -2231,6 +2298,7 @@ interface iBackupExtraFilesExtension
public function GetExtraFilesRelPaths(): array; public function GetExtraFilesRelPaths(): array;
} }
/** /**
* Interface to provide messages to be displayed in the "Welcome Popup" * Interface to provide messages to be displayed in the "Welcome Popup"
* *
@@ -2291,7 +2359,7 @@ abstract class AbstractWelcomePopupExtension implements iWelcomePopupExtension
{ {
return []; return [];
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
@@ -2300,4 +2368,4 @@ abstract class AbstractWelcomePopupExtension implements iWelcomePopupExtension
// No need to process the acknowledgment notice by default // No need to process the acknowledgment notice by default
return; return;
} }
} }

View File

@@ -1,10 +1,9 @@
<?php <?php
// Copyright (C) 2010-2024 Combodo SAS // Copyright (C) 2010-2024 Combodo SAS
// //
// This file is part of iTop. // This file is part of iTop.
// //
// iTop is free software; you can redistribute it and/or modify // iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by // it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
@@ -17,6 +16,7 @@
// You should have received a copy of the GNU Affero General Public License // You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with iTop. If not, see <http://www.gnu.org/licenses/>
/** /**
* This class manages the audit "categories". Each category defines a set of objects * This class manages the audit "categories". Each category defines a set of objects
* to check and is linked to a set of rules that determine the valid or invalid objects * to check and is linked to a set of rules that determine the valid or invalid objects
@@ -32,36 +32,34 @@ class AuditCategory extends cmdbAbstractObject
{ {
public static function Init() public static function Init()
{ {
$aParams = $aParams = array
[ (
"category" => "application,grant_by_profile", "category" => "application,grant_by_profile",
"key_type" => "autoincrement", "key_type" => "autoincrement",
"name_attcode" => "name", "name_attcode" => "name",
"state_attcode" => "", "state_attcode" => "",
"reconc_keys" => ['name'], "reconc_keys" => array('name'),
"db_table" => "priv_auditcategory", "db_table" => "priv_auditcategory",
"db_key_field" => "id", "db_key_field" => "id",
"db_finalclass_field" => "", "db_finalclass_field" => "",
'style' => new ormStyle(null, null, null, null, null, '../images/icons/icons8-audit-folder.svg'), 'style' => new ormStyle(null, null, null, null, null, '../images/icons/icons8-audit-folder.svg'),
]; );
MetaModel::Init_Params($aParams); MetaModel::Init_Params($aParams);
MetaModel::Init_AddAttribute(new AttributeString("name", ["description" => "Short name for this category", "allowed_values" => null, "sql" => "name", "default_value" => "", "is_null_allowed" => false, "depends_on" => []])); MetaModel::Init_AddAttribute(new AttributeString("name", array("description"=>"Short name for this category", "allowed_values"=>null, "sql"=>"name", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("description", ["allowed_values" => null, "sql" => "description", "default_value" => "", "is_null_allowed" => true, "depends_on" => []])); MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values"=>null, "sql"=>"description", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeOQL("definition_set", ["allowed_values" => null, "sql" => "definition_set", "default_value" => "", "is_null_allowed" => false, "depends_on" => []])); MetaModel::Init_AddAttribute(new AttributeOQL("definition_set", array("allowed_values"=>null, "sql"=>"definition_set", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeLinkedSet("rules_list", ["linked_class" => "AuditRule", "ext_key_to_me" => "category_id", "allowed_values" => null, "count_min" => 0, "count_max" => 0, "depends_on" => [], "edit_mode" => LINKSET_EDITMODE_INPLACE, "tracking_level" => LINKSET_TRACKING_ALL])); MetaModel::Init_AddAttribute(new AttributeLinkedSet("rules_list", array("linked_class"=>"AuditRule", "ext_key_to_me"=>"category_id", "allowed_values"=>null, "count_min"=>0, "count_max"=>0, "depends_on"=>array(), "edit_mode" => LINKSET_EDITMODE_INPLACE, "tracking_level" => LINKSET_TRACKING_ALL)));
MetaModel::Init_AddAttribute(new AttributeInteger("ok_error_tolerance", ["allowed_values" => null, "sql" => "ok_error_tolerance", "default_value" => 5, "is_null_allowed" => true, "depends_on" => []])); MetaModel::Init_AddAttribute(new AttributeInteger("ok_error_tolerance", array("allowed_values"=>null, "sql"=>"ok_error_tolerance", "default_value"=>5, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeInteger("warning_error_tolerance", ["allowed_values" => null, "sql" => "warning_error_tolerance", "default_value" => 25, "is_null_allowed" => true, "depends_on" => []])); MetaModel::Init_AddAttribute(new AttributeInteger("warning_error_tolerance", array("allowed_values" => null, "sql" => "warning_error_tolerance", "default_value" => 25, "is_null_allowed" => true, "depends_on" => array())));
MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect( MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect("domains_list",
"domains_list", array("linked_class" => "lnkAuditCategoryToAuditDomain", "ext_key_to_me" => "category_id", "ext_key_to_remote" => "domain_id", "allowed_values" => null, "count_min" => 0, "count_max" => 0, "depends_on" => array(), "display_style" => 'property')));
["linked_class" => "lnkAuditCategoryToAuditDomain", "ext_key_to_me" => "category_id", "ext_key_to_remote" => "domain_id", "allowed_values" => null, "count_min" => 0, "count_max" => 0, "depends_on" => [], "display_style" => 'property']
));
// Display lists // Display lists
MetaModel::Init_SetZListItems('details', ['name', 'description', 'definition_set', 'ok_error_tolerance', 'warning_error_tolerance', 'rules_list', 'domains_list']); // Attributes to be displayed for the complete details MetaModel::Init_SetZListItems('details', array('name', 'description', 'definition_set', 'ok_error_tolerance', 'warning_error_tolerance', 'rules_list', 'domains_list')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', ['description', ]); // Attributes to be displayed for a list MetaModel::Init_SetZListItems('list', array('description', )); // Attributes to be displayed for a list
// Search criteria // Search criteria
MetaModel::Init_SetZListItems('standard_search', ['description', 'definition_set']); // Criteria of the std search form MetaModel::Init_SetZListItems('standard_search', array('description', 'definition_set')); // Criteria of the std search form
MetaModel::Init_SetZListItems('default_search', ['name', 'description']); // Criteria of the default search form MetaModel::Init_SetZListItems('default_search', array('name', 'description')); // Criteria of the default search form
} }
/** /**
@@ -76,9 +74,9 @@ class AuditCategory extends cmdbAbstractObject
public function GetReportColor($iTotal, $iErrors) public function GetReportColor($iTotal, $iErrors)
{ {
$sResult = 'red'; $sResult = 'red';
if (($iTotal == 0) || ($iErrors / $iTotal) <= ($this->Get('ok_error_tolerance') / 100)) { if ( ($iTotal == 0) || ($iErrors / $iTotal) <= ($this->Get('ok_error_tolerance') / 100) ) {
$sResult = 'green'; $sResult = 'green';
} elseif (($iErrors / $iTotal) <= ($this->Get('warning_error_tolerance') / 100)) { } else if (($iErrors / $iTotal) <= ($this->Get('warning_error_tolerance') / 100)) {
$sResult = 'orange'; $sResult = 'orange';
} }
@@ -95,3 +93,4 @@ class AuditCategory extends cmdbAbstractObject
return $aShortcutActions; return $aShortcutActions;
} }
} }
?>

View File

@@ -1,5 +1,4 @@
<?php <?php
// Copyright (C) 2010-2024 Combodo SAS // Copyright (C) 2010-2024 Combodo SAS
// //
// This file is part of iTop. // This file is part of iTop.
@@ -17,6 +16,7 @@
// You should have received a copy of the GNU Affero General Public License // You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with iTop. If not, see <http://www.gnu.org/licenses/>
/** /**
* This class manages the audit "categories". Each category defines a set of objects * This class manages the audit "categories". Each category defines a set of objects
* to check and is linked to a set of rules that determine the valid or invalid objects * to check and is linked to a set of rules that determine the valid or invalid objects
@@ -33,34 +33,32 @@ class AuditDomain extends cmdbAbstractObject
{ {
public static function Init() public static function Init()
{ {
$aParams = $aParams = array
[ (
"category" => "application,grant_by_profile", "category" => "application,grant_by_profile",
"key_type" => "autoincrement", "key_type" => "autoincrement",
"name_attcode" => "name", "name_attcode" => "name",
"complementary_name_attcode" => ['description'], "complementary_name_attcode" => array('description'),
"state_attcode" => "", "state_attcode" => "",
"reconc_keys" => ['name'], "reconc_keys" => array('name'),
"db_table" => "priv_auditdomain", "db_table" => "priv_auditdomain",
"db_key_field" => "id", "db_key_field" => "id",
"db_finalclass_field" => "", "db_finalclass_field" => "",
'style' => new ormStyle(null, null, null, null, null, '../images/icons/icons8-audit-album.svg'), 'style' => new ormStyle(null, null, null, null, null, '../images/icons/icons8-audit-album.svg'),
]; );
MetaModel::Init_Params($aParams); MetaModel::Init_Params($aParams);
MetaModel::Init_AddAttribute(new AttributeString("name", ["description" => "Short name for this category", "allowed_values" => null, "sql" => "name", "default_value" => "", "is_null_allowed" => false, "depends_on" => []])); MetaModel::Init_AddAttribute(new AttributeString("name", array("description" => "Short name for this category", "allowed_values" => null, "sql" => "name", "default_value" => "", "is_null_allowed" => false, "depends_on" => array())));
MetaModel::Init_AddAttribute(new AttributeString("description", ["allowed_values" => null, "sql" => "description", "default_value" => "", "is_null_allowed" => true, "depends_on" => []])); MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values" => null, "sql" => "description", "default_value" => "", "is_null_allowed" => true, "depends_on" => array())));
MetaModel::Init_AddAttribute(new AttributeImage("icon", ["is_null_allowed" => true, "depends_on" => [], "display_max_width" => 96, "display_max_height" => 96, "storage_max_width" => 256, "storage_max_height" => 256, "default_image" => null, "always_load_in_tables" => false])); MetaModel::Init_AddAttribute(new AttributeImage("icon", array("is_null_allowed" => true, "depends_on" => array(), "display_max_width" => 96, "display_max_height" => 96, "storage_max_width" => 256, "storage_max_height" => 256, "default_image" => null, "always_load_in_tables" => false)));
MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect( MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect("categories_list",
"categories_list", array("linked_class" => "lnkAuditCategoryToAuditDomain", "ext_key_to_me" => "domain_id", "ext_key_to_remote" => "category_id", "allowed_values" => null, "count_min" => 0, "count_max" => 0, "depends_on" => array())));
["linked_class" => "lnkAuditCategoryToAuditDomain", "ext_key_to_me" => "domain_id", "ext_key_to_remote" => "category_id", "allowed_values" => null, "count_min" => 0, "count_max" => 0, "depends_on" => []]
));
// Display lists // Display lists
MetaModel::Init_SetZListItems('details', ['name', 'description', 'icon', 'categories_list']); // Attributes to be displayed for the complete details MetaModel::Init_SetZListItems('details', array('name', 'description', 'icon', 'categories_list')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', ['description',]); // Attributes to be displayed for a list MetaModel::Init_SetZListItems('list', array('description',)); // Attributes to be displayed for a list
// Search criteria // Search criteria
MetaModel::Init_SetZListItems('standard_search', ['description']); // Criteria of the std search form MetaModel::Init_SetZListItems('standard_search', array('description')); // Criteria of the std search form
MetaModel::Init_SetZListItems('default_search', ['name', 'description']); // Criteria of the default search form MetaModel::Init_SetZListItems('default_search', array('name', 'description')); // Criteria of the default search form
} }
public static function GetShortcutActions($sFinalClass) public static function GetShortcutActions($sFinalClass)
@@ -86,39 +84,40 @@ class lnkAuditCategoryToAuditDomain extends cmdbAbstractObject
*/ */
public static function Init() public static function Init()
{ {
$aParams = $aParams = array
[ (
"category" => "application,grant_by_profile", "category" => "application,grant_by_profile",
"key_type" => "autoincrement", "key_type" => "autoincrement",
"name_attcode" => "", "name_attcode" => "",
"state_attcode" => "", "state_attcode" => "",
"reconc_keys" => ['category_id', 'domain_id'], "reconc_keys" => array('category_id', 'domain_id'),
"db_table" => "priv_link_audit_category_domain", "db_table" => "priv_link_audit_category_domain",
"db_key_field" => "id", "db_key_field" => "id",
"db_finalclass_field" => "", "db_finalclass_field" => "",
"is_link" => true, "is_link" => true,
'uniqueness_rules' => [ 'uniqueness_rules' => array(
'no_duplicate' => [ 'no_duplicate' => array(
'attributes' => [ 'attributes' => array(
0 => 'category_id', 0 => 'category_id',
1 => 'domain_id', 1 => 'domain_id',
], ),
'filter' => '', 'filter' => '',
'disabled' => false, 'disabled' => false,
'is_blocking' => true, 'is_blocking' => true,
], ),
], ),
]; );
MetaModel::Init_Params($aParams); MetaModel::Init_Params($aParams);
MetaModel::Init_AddAttribute(new AttributeExternalKey("category_id", ["targetclass" => "AuditCategory", "jointype" => '', "allowed_values" => null, "sql" => "category_id", "is_null_allowed" => false, "on_target_delete" => DEL_AUTO, "depends_on" => []])); MetaModel::Init_AddAttribute(new AttributeExternalKey("category_id", array("targetclass" => "AuditCategory", "jointype" => '', "allowed_values" => null, "sql" => "category_id", "is_null_allowed" => false, "on_target_delete" => DEL_AUTO, "depends_on" => array())));
MetaModel::Init_AddAttribute(new AttributeExternalField("category_name", ["allowed_values" => null, "extkey_attcode" => 'category_id', "target_attcode" => "name"])); MetaModel::Init_AddAttribute(new AttributeExternalField("category_name", array("allowed_values" => null, "extkey_attcode" => 'category_id', "target_attcode" => "name")));
MetaModel::Init_AddAttribute(new AttributeExternalKey("domain_id", ["targetclass" => "AuditDomain", "jointype" => '', "allowed_values" => null, "sql" => "domain_id", "is_null_allowed" => false, "on_target_delete" => DEL_AUTO, "depends_on" => []])); MetaModel::Init_AddAttribute(new AttributeExternalKey("domain_id", array("targetclass" => "AuditDomain", "jointype" => '', "allowed_values" => null, "sql" => "domain_id", "is_null_allowed" => false, "on_target_delete" => DEL_AUTO, "depends_on" => array())));
MetaModel::Init_AddAttribute(new AttributeExternalField("domain_name", ["allowed_values" => null, "extkey_attcode" => 'domain_id', "target_attcode" => "name"])); MetaModel::Init_AddAttribute(new AttributeExternalField("domain_name", array("allowed_values" => null, "extkey_attcode" => 'domain_id', "target_attcode" => "name")));
// Display lists // Display lists
MetaModel::Init_SetZListItems('details', ['category_id', 'domain_id']); MetaModel::Init_SetZListItems('details', array('category_id', 'domain_id'));
MetaModel::Init_SetZListItems('list', ['category_id', 'domain_id']); MetaModel::Init_SetZListItems('list', array('category_id', 'domain_id'));
// Search criteria // Search criteria
MetaModel::Init_SetZListItems('standard_search', ['category_id', 'domain_id']); MetaModel::Init_SetZListItems('standard_search', array('category_id', 'domain_id'));
} }
} }

View File

@@ -1,10 +1,9 @@
<?php <?php
// Copyright (C) 2010-2024 Combodo SAS // Copyright (C) 2010-2024 Combodo SAS
// //
// This file is part of iTop. // This file is part of iTop.
// //
// iTop is free software; you can redistribute it and/or modify // iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by // it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
@@ -17,6 +16,7 @@
// You should have received a copy of the GNU Affero General Public License // You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with iTop. If not, see <http://www.gnu.org/licenses/>
/** /**
* This class manages the audit "rule" linked to a given audit category. * This class manages the audit "rule" linked to a given audit category.
* Each rule is based on an OQL expression that returns either the "good" objects * Each rule is based on an OQL expression that returns either the "good" objects
@@ -33,34 +33,35 @@ class AuditRule extends cmdbAbstractObject
{ {
public static function Init() public static function Init()
{ {
$aParams = $aParams = array
[ (
"category" => "application,grant_by_profile", "category" => "application,grant_by_profile",
"key_type" => "autoincrement", "key_type" => "autoincrement",
"name_attcode" => "name", "name_attcode" => "name",
"state_attcode" => "", "state_attcode" => "",
"reconc_keys" => ['name'], "reconc_keys" => array('name'),
"db_table" => "priv_auditrule", "db_table" => "priv_auditrule",
"db_key_field" => "id", "db_key_field" => "id",
"db_finalclass_field" => "", "db_finalclass_field" => "",
'style' => new ormStyle(null, null, null, null, null, '../images/icons/icons8-audit.svg'), 'style' => new ormStyle(null, null, null, null, null, '../images/icons/icons8-audit.svg'),
]; );
MetaModel::Init_Params($aParams); MetaModel::Init_Params($aParams);
MetaModel::Init_AddAttribute(new AttributeString("name", ["allowed_values" => null, "sql" => "name", "default_value" => "", "is_null_allowed" => false, "depends_on" => []])); MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values" => null, "sql" => "name", "default_value" => "", "is_null_allowed" => false, "depends_on" => array())));
MetaModel::Init_AddAttribute(new AttributeString("description", ["allowed_values" => null, "sql" => "description", "default_value" => "", "is_null_allowed" => true, "depends_on" => []])); MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values" => null, "sql" => "description", "default_value" => "", "is_null_allowed" => true, "depends_on" => array())));
MetaModel::Init_AddAttribute(new AttributeOQL("query", ["allowed_values" => null, "sql" => "query", "default_value" => "", "is_null_allowed" => false, "depends_on" => []])); MetaModel::Init_AddAttribute(new AttributeOQL("query", array("allowed_values" => null, "sql" => "query", "default_value" => "", "is_null_allowed" => false, "depends_on" => array())));
MetaModel::Init_AddAttribute(new AttributeEnum("valid_flag", ["allowed_values" => new ValueSetEnum('true,false'), "sql" => "valid_flag", "default_value" => "true", "is_null_allowed" => false, "depends_on" => []])); MetaModel::Init_AddAttribute(new AttributeEnum("valid_flag", array("allowed_values" => new ValueSetEnum('true,false'), "sql" => "valid_flag", "default_value" => "true", "is_null_allowed" => false, "depends_on" => array())));
MetaModel::Init_AddAttribute(new AttributeExternalKey("category_id", ["allowed_values" => null, "sql" => "category_id", "targetclass" => "AuditCategory", "is_null_allowed" => false, "on_target_delete" => DEL_MANUAL, "depends_on" => []])); MetaModel::Init_AddAttribute(new AttributeExternalKey("category_id", array("allowed_values" => null, "sql" => "category_id", "targetclass" => "AuditCategory", "is_null_allowed" => false, "on_target_delete" => DEL_MANUAL, "depends_on" => array())));
MetaModel::Init_AddAttribute(new AttributeExternalField("category_name", ["allowed_values" => null, "extkey_attcode" => 'category_id', "target_attcode" => "name"])); MetaModel::Init_AddAttribute(new AttributeExternalField("category_name", array("allowed_values" => null, "extkey_attcode" => 'category_id', "target_attcode" => "name")));
// Display lists // Display lists
MetaModel::Init_SetZListItems('details', ['category_id', 'name', 'description', 'query', 'valid_flag']); // Attributes to be displayed for the complete details MetaModel::Init_SetZListItems('details', array('category_id', 'name', 'description', 'query', 'valid_flag')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', ['category_id', 'description', 'valid_flag']); // Attributes to be displayed for a list MetaModel::Init_SetZListItems('list', array('category_id', 'description', 'valid_flag')); // Attributes to be displayed for a list
// Search criteria // Search criteria
MetaModel::Init_SetZListItems('standard_search', ['category_id', 'name', 'description', 'valid_flag', 'query']); // Criteria of the std search form MetaModel::Init_SetZListItems('standard_search', array('category_id', 'name', 'description', 'valid_flag', 'query')); // Criteria of the std search form
MetaModel::Init_SetZListItems('default_search', ['name', 'description', 'category_id']); // Criteria of the advanced search form MetaModel::Init_SetZListItems('default_search', array('name', 'description', 'category_id')); // Criteria of the advanced search form
} }
public static function GetShortcutActions($sFinalClass) public static function GetShortcutActions($sFinalClass)
{ {
$aShortcutActions = parent::GetShortcutActions($sFinalClass); $aShortcutActions = parent::GetShortcutActions($sFinalClass);
@@ -71,3 +72,4 @@ class AuditRule extends cmdbAbstractObject
return $aShortcutActions; return $aShortcutActions;
} }
} }
?>

View File

@@ -1,9 +1,8 @@
<?php <?php
/** /**
* @deprecated 3.0.0 will be removed in 3.1.0 - moved to sources/Application/WebPage/CaptureWebPage.php, now loadable using autoloader * @deprecated 3.0.0 will be removed in 3.1.0 - moved to sources/Application/WebPage/CaptureWebPage.php, now loadable using autoloader
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
*/ */
DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/Application/WebPage/CaptureWebPage.php, now loadable using autoloader'); DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/Application/WebPage/CaptureWebPage.php, now loadable using autoloader');

View File

@@ -1,9 +1,8 @@
<?php <?php
/** /**
* @deprecated 3.0.0 will be removed in 3.1.0 - moved to sources/Application/WebPage/CLIPage.php, now loadable using autoloader * @deprecated 3.0.0 will be removed in 3.1.0 - moved to sources/Application/WebPage/CLIPage.php, now loadable using autoloader
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
*/ */
DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/Application/WebPage/CLIPage.php, now loadable using autoloader'); DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/Application/WebPage/CLIPage.php, now loadable using autoloader');

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,4 @@
<?php <?php
/** /**
* Copyright (C) 2013-2024 Combodo SAS * Copyright (C) 2013-2024 Combodo SAS
* *
@@ -33,8 +32,7 @@ class CompileCSSService
{ {
} }
public function CompileCSSFromSASS($sSassContent, $aImportPaths = [], $aVariables = []) public function CompileCSSFromSASS($sSassContent, $aImportPaths = [], $aVariables = []){
{
return utils::CompileCSSFromSASS($sSassContent, $aImportPaths, $aVariables); return utils::CompileCSSFromSASS($sSassContent, $aImportPaths, $aVariables);
} }
} }

View File

@@ -1,9 +1,8 @@
<?php <?php
/** /**
* @deprecated 3.0.0 will be removed in 3.1.0 - moved to sources/Application/WebPage/CSVPage.php, now loadable using autoloader * @deprecated 3.0.0 will be removed in 3.1.0 - moved to sources/Application/WebPage/CSVPage.php, now loadable using autoloader
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
*/ */
DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/Application/WebPage/CSVPage.php, now loadable using autoloader'); DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/Application/WebPage/CSVPage.php, now loadable using autoloader');

View File

@@ -1,5 +1,4 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -54,7 +53,7 @@ abstract class Dashboard
$this->sLayoutClass = 'DashboardLayoutOneCol'; $this->sLayoutClass = 'DashboardLayoutOneCol';
$this->bAutoReload = false; $this->bAutoReload = false;
$this->iAutoReloadSec = MetaModel::GetConfig()->GetStandardReloadInterval(); $this->iAutoReloadSec = MetaModel::GetConfig()->GetStandardReloadInterval();
$this->aCells = []; $this->aCells = array();
$this->oDOMNode = null; $this->oDOMNode = null;
$this->sId = $sId; $this->sId = $sId;
} }
@@ -66,8 +65,8 @@ abstract class Dashboard
*/ */
public function FromXml($sXml) public function FromXml($sXml)
{ {
$this->aCells = []; // reset the content of the dashboard $this->aCells = array(); // reset the content of the dashboard
set_error_handler(['Dashboard', 'ErrorHandler']); set_error_handler(array('Dashboard', 'ErrorHandler'));
$oDoc = new DOMDocument(); $oDoc = new DOMDocument();
$oDoc->loadXML($sXml); $oDoc->loadXML($sXml);
restore_error_handler(); restore_error_handler();
@@ -80,69 +79,87 @@ abstract class Dashboard
public function FromDOMDocument(DOMDocument $oDoc) public function FromDOMDocument(DOMDocument $oDoc)
{ {
$this->oDOMNode = $oDoc->getElementsByTagName('dashboard')->item(0); $this->oDOMNode = $oDoc->getElementsByTagName('dashboard')->item(0);
if ($oLayoutNode = $this->oDOMNode->getElementsByTagName('layout')->item(0)) { if ($oLayoutNode = $this->oDOMNode->getElementsByTagName('layout')->item(0))
{
$this->sLayoutClass = $oLayoutNode->textContent; $this->sLayoutClass = $oLayoutNode->textContent;
} else { }
else
{
$this->sLayoutClass = 'DashboardLayoutOneCol'; $this->sLayoutClass = 'DashboardLayoutOneCol';
} }
if ($oTitleNode = $this->oDOMNode->getElementsByTagName('title')->item(0)) { if ($oTitleNode = $this->oDOMNode->getElementsByTagName('title')->item(0))
{
$this->sTitle = $oTitleNode->textContent; $this->sTitle = $oTitleNode->textContent;
} else { }
else
{
$this->sTitle = ''; $this->sTitle = '';
} }
$this->bAutoReload = false; $this->bAutoReload = false;
$this->iAutoReloadSec = MetaModel::GetConfig()->GetStandardReloadInterval(); $this->iAutoReloadSec = MetaModel::GetConfig()->GetStandardReloadInterval();
if ($oAutoReloadNode = $this->oDOMNode->getElementsByTagName('auto_reload')->item(0)) { if ($oAutoReloadNode = $this->oDOMNode->getElementsByTagName('auto_reload')->item(0))
if ($oAutoReloadEnabled = $oAutoReloadNode->getElementsByTagName('enabled')->item(0)) { {
if ($oAutoReloadEnabled = $oAutoReloadNode->getElementsByTagName('enabled')->item(0))
{
$this->bAutoReload = ($oAutoReloadEnabled->textContent == 'true'); $this->bAutoReload = ($oAutoReloadEnabled->textContent == 'true');
} }
if ($oAutoReloadInterval = $oAutoReloadNode->getElementsByTagName('interval')->item(0)) { if ($oAutoReloadInterval = $oAutoReloadNode->getElementsByTagName('interval')->item(0))
{
$this->iAutoReloadSec = max(MetaModel::GetConfig()->Get('min_reload_interval'), (int)$oAutoReloadInterval->textContent); $this->iAutoReloadSec = max(MetaModel::GetConfig()->Get('min_reload_interval'), (int)$oAutoReloadInterval->textContent);
} }
} }
if ($oCellsNode = $this->oDOMNode->getElementsByTagName('cells')->item(0)) { if ($oCellsNode = $this->oDOMNode->getElementsByTagName('cells')->item(0))
{
$oCellsList = $oCellsNode->getElementsByTagName('cell'); $oCellsList = $oCellsNode->getElementsByTagName('cell');
$aCellOrder = []; $aCellOrder = array();
$iCellRank = 0; $iCellRank = 0;
/** @var \DOMElement $oCellNode */ /** @var \DOMElement $oCellNode */
foreach ($oCellsList as $oCellNode) { foreach($oCellsList as $oCellNode)
{
$oCellRank = $oCellNode->getElementsByTagName('rank')->item(0); $oCellRank = $oCellNode->getElementsByTagName('rank')->item(0);
if ($oCellRank) { if ($oCellRank)
{
$iCellRank = (float)$oCellRank->textContent; $iCellRank = (float)$oCellRank->textContent;
} }
$oDashletsNode = $oCellNode->getElementsByTagName('dashlets')->item(0); $oDashletsNode = $oCellNode->getElementsByTagName('dashlets')->item(0);
{ {
$oDashletList = $oDashletsNode->getElementsByTagName('dashlet'); $oDashletList = $oDashletsNode->getElementsByTagName('dashlet');
$iRank = 0; $iRank = 0;
$aDashletOrder = []; $aDashletOrder = array();
/** @var \DOMElement $oDomNode */ /** @var \DOMElement $oDomNode */
foreach ($oDashletList as $oDomNode) { foreach($oDashletList as $oDomNode)
{
$oRank = $oDomNode->getElementsByTagName('rank')->item(0); $oRank = $oDomNode->getElementsByTagName('rank')->item(0);
if ($oRank) { if ($oRank)
{
$iRank = (float)$oRank->textContent; $iRank = (float)$oRank->textContent;
} }
$oNewDashlet = $this->InitDashletFromDOMNode($oDomNode); $oNewDashlet = $this->InitDashletFromDOMNode($oDomNode);
$aDashletOrder[] = ['rank' => $iRank, 'dashlet' => $oNewDashlet]; $aDashletOrder[] = array('rank' => $iRank, 'dashlet' => $oNewDashlet);
} }
usort($aDashletOrder, [get_class($this), 'SortOnRank']); usort($aDashletOrder, array(get_class($this), 'SortOnRank'));
$aDashletList = []; $aDashletList = array();
foreach ($aDashletOrder as $aItem) { foreach($aDashletOrder as $aItem)
{
$aDashletList[] = $aItem['dashlet']; $aDashletList[] = $aItem['dashlet'];
} }
$aCellOrder[] = ['rank' => $iCellRank, 'dashlets' => $aDashletList]; $aCellOrder[] = array('rank' => $iCellRank, 'dashlets' => $aDashletList);
} }
} }
usort($aCellOrder, [get_class($this), 'SortOnRank']); usort($aCellOrder, array(get_class($this), 'SortOnRank'));
foreach ($aCellOrder as $aItem) { foreach($aCellOrder as $aItem)
{
$this->aCells[] = $aItem['dashlets']; $this->aCells[] = $aItem['dashlets'];
} }
} else { }
$this->aCells = []; else
{
$this->aCells = array();
} }
} }
@@ -152,20 +169,20 @@ abstract class Dashboard
* @return mixed * @return mixed
*/ */
protected function InitDashletFromDOMNode($oDomNode) protected function InitDashletFromDOMNode($oDomNode)
{ {
$sId = $oDomNode->getAttribute('id'); $sId = $oDomNode->getAttribute('id');
$sDashletType = $oDomNode->getAttribute('xsi:type'); $sDashletType = $oDomNode->getAttribute('xsi:type');
// Test if dashlet can be instantiated, otherwise (uninstalled, broken, ...) we display a placeholder // Test if dashlet can be instantiated, otherwise (uninstalled, broken, ...) we display a placeholder
$sClass = static::GetDashletClassFromType($sDashletType); $sClass = static::GetDashletClassFromType($sDashletType);
/** @var \Dashlet $oNewDashlet */ /** @var \Dashlet $oNewDashlet */
$oNewDashlet = new $sClass($this->oMetaModel, $sId); $oNewDashlet = new $sClass($this->oMetaModel, $sId);
$oNewDashlet->SetDashletType($sDashletType); $oNewDashlet->SetDashletType($sDashletType);
$oNewDashlet->FromDOMNode($oDomNode); $oNewDashlet->FromDOMNode($oDomNode);
return $oNewDashlet; return $oNewDashlet;
} }
/** /**
* @param array $aItem1 * @param array $aItem1
@@ -191,9 +208,12 @@ abstract class Dashboard
*/ */
public static function ErrorHandler($errno, $errstr, $errfile, $errline) public static function ErrorHandler($errno, $errstr, $errfile, $errline)
{ {
if ($errno == E_WARNING && (substr_count($errstr, "DOMDocument::loadXML()") > 0)) { if ($errno == E_WARNING && (substr_count($errstr,"DOMDocument::loadXML()")>0))
{
throw new DOMException($errstr); throw new DOMException($errstr);
} else { }
else
{
return false; return false;
} }
} }
@@ -211,7 +231,7 @@ abstract class Dashboard
$oMainNode = $oDoc->createElement('dashboard'); $oMainNode = $oDoc->createElement('dashboard');
$oMainNode->setAttribute('xmlns:xsi', "http://www.w3.org/2001/XMLSchema-instance"); $oMainNode->setAttribute('xmlns:xsi', "http://www.w3.org/2001/XMLSchema-instance");
$oDoc->appendChild($oMainNode); $oDoc->appendChild($oMainNode);
$this->ToDOMNode($oMainNode); $this->ToDOMNode($oMainNode);
$sXml = $oDoc->saveXML(); $sXml = $oDoc->saveXML();
@@ -241,21 +261,23 @@ abstract class Dashboard
$oCellsNode = $oDoc->createElement('cells'); $oCellsNode = $oDoc->createElement('cells');
$oDefinition->appendChild($oCellsNode); $oDefinition->appendChild($oCellsNode);
$iCellRank = 0; $iCellRank = 0;
foreach ($this->aCells as $aCell) { foreach ($this->aCells as $aCell)
{
$oCellNode = $oDoc->createElement('cell'); $oCellNode = $oDoc->createElement('cell');
$oCellNode->setAttribute('id', $iCellRank); $oCellNode->setAttribute('id', $iCellRank);
$oCellsNode->appendChild($oCellNode); $oCellsNode->appendChild($oCellNode);
$oCellRank = $oDoc->createElement('rank', $iCellRank); $oCellRank = $oDoc->createElement('rank', $iCellRank);
$oCellNode->appendChild($oCellRank); $oCellNode->appendChild($oCellRank);
$iCellRank++; $iCellRank++;
$iDashletRank = 0; $iDashletRank = 0;
$oDashletsNode = $oDoc->createElement('dashlets'); $oDashletsNode = $oDoc->createElement('dashlets');
$oCellNode->appendChild($oDashletsNode); $oCellNode->appendChild($oDashletsNode);
/** @var \Dashlet $oDashlet */ /** @var \Dashlet $oDashlet */
foreach ($aCell as $oDashlet) { foreach ($aCell as $oDashlet)
{
$oNode = $oDoc->createElement('dashlet'); $oNode = $oDoc->createElement('dashlet');
$oDashletsNode->appendChild($oNode); $oDashletsNode->appendChild($oNode);
$oNode->setAttribute('id', $oDashlet->GetID()); $oNode->setAttribute('id', $oDashlet->GetID());
@@ -277,15 +299,18 @@ abstract class Dashboard
$this->sTitle = $aParams['title']; $this->sTitle = $aParams['title'];
$this->bAutoReload = $aParams['auto_reload'] == 'true'; $this->bAutoReload = $aParams['auto_reload'] == 'true';
$this->iAutoReloadSec = max(MetaModel::GetConfig()->Get('min_reload_interval'), (int) $aParams['auto_reload_sec']); $this->iAutoReloadSec = max(MetaModel::GetConfig()->Get('min_reload_interval'), (int) $aParams['auto_reload_sec']);
foreach ($aParams['cells'] as $aCell) { foreach($aParams['cells'] as $aCell)
$aCellDashlets = []; {
foreach ($aCell as $aDashletParams) { $aCellDashlets = array();
foreach($aCell as $aDashletParams)
{
$sDashletClass = $aDashletParams['dashlet_class']; $sDashletClass = $aDashletParams['dashlet_class'];
$sId = $aDashletParams['dashlet_id']; $sId = $aDashletParams['dashlet_id'];
/** @var \Dashlet $oNewDashlet */ /** @var \Dashlet $oNewDashlet */
$oNewDashlet = new $sDashletClass($this->oMetaModel, $sId); $oNewDashlet = new $sDashletClass($this->oMetaModel, $sId);
if (isset($aDashletParams['dashlet_type'])) { if (isset($aDashletParams['dashlet_type']))
{
$oNewDashlet->SetDashletType($aDashletParams['dashlet_type']); $oNewDashlet->SetDashletType($aDashletParams['dashlet_type']);
} }
$oForm = $oNewDashlet->GetForm(); $oForm = $oNewDashlet->GetForm();
@@ -297,12 +322,12 @@ abstract class Dashboard
} }
$this->aCells[] = $aCellDashlets; $this->aCells[] = $aCellDashlets;
} }
} }
public function Save() public function Save()
{ {
} }
/** /**
@@ -395,7 +420,7 @@ abstract class Dashboard
{ {
$sId = $this->GetNewDashletId(); $sId = $this->GetNewDashletId();
$oDashlet->SetId($sId); $oDashlet->SetId($sId);
$this->aCells[] = [$oDashlet]; $this->aCells[] = array($oDashlet);
} }
/** /**
@@ -405,7 +430,7 @@ abstract class Dashboard
* @throws \ReflectionException * @throws \ReflectionException
* @throws \Exception * @throws \Exception
*/ */
public function RenderProperties($oPage, $aExtraParams = []) public function RenderProperties($oPage, $aExtraParams = array())
{ {
// menu to pick a layout and edit other properties of the dashboard // menu to pick a layout and edit other properties of the dashboard
$oPage->add('<div class="ui-widget-content ui-corner-all ibo-dashboard-editor--properties"><div class="ui-widget-header ui-corner-all ibo-dashboard-editor--properties-title">'.Dict::S('UI:DashboardEdit:Properties').'</div>'); $oPage->add('<div class="ui-widget-content ui-corner-all ibo-dashboard-editor--properties"><div class="ui-widget-header ui-corner-all ibo-dashboard-editor--properties-title">'.Dict::S('UI:DashboardEdit:Properties').'</div>');
@@ -417,7 +442,7 @@ abstract class Dashboard
if (is_subclass_of($sLayoutClass, 'DashboardLayout')) { if (is_subclass_of($sLayoutClass, 'DashboardLayout')) {
$oReflection = new ReflectionClass($sLayoutClass); $oReflection = new ReflectionClass($sLayoutClass);
if (!$oReflection->isAbstract()) { if (!$oReflection->isAbstract()) {
$aCallSpec = [$sLayoutClass, 'GetInfo']; $aCallSpec = array($sLayoutClass, 'GetInfo');
$aInfo = call_user_func($aCallSpec); $aInfo = call_user_func($aCallSpec);
$sChecked = ($this->sLayoutClass == $sLayoutClass) ? 'checked' : ''; $sChecked = ($this->sLayoutClass == $sLayoutClass) ? 'checked' : '';
$oPage->add('<input type="radio" name="layout_class" '.$sChecked.' value="'.$sLayoutClass.'" id="layout_'.$sLayoutClass.'"><label for="layout_'.$sLayoutClass.'"><img src="'.$sUrl.$aInfo['icon'].'" class="ibo-dashboard--properties--icon" data-role="ibo-dashboard--properties--icon"/></label>'); // title="" on either the img or the label does nothing ! $oPage->add('<input type="radio" name="layout_class" '.$sChecked.' value="'.$sLayoutClass.'" id="layout_'.$sLayoutClass.'"><label for="layout_'.$sLayoutClass.'"><img src="'.$sUrl.$aInfo['icon'].'" class="ibo-dashboard--properties--icon" data-role="ibo-dashboard--properties--icon"/></label>'); // title="" on either the img or the label does nothing !
@@ -441,6 +466,7 @@ abstract class Dashboard
$oField->SetBoundaries(MetaModel::GetConfig()->Get('min_reload_interval'), null); // no upper limit $oField->SetBoundaries(MetaModel::GetConfig()->Get('min_reload_interval'), null); // no upper limit
$oForm->AddField($oField); $oForm->AddField($oField);
$this->SetFormParams($oForm, $aExtraParams); $this->SetFormParams($oForm, $aExtraParams);
$oForm->RenderAsPropertySheet($oPage, false, '.itop-dashboard'); $oForm->RenderAsPropertySheet($oPage, false, '.itop-dashboard');
@@ -448,7 +474,7 @@ abstract class Dashboard
$sRateTitle = addslashes(Dict::Format('UI:DashboardEdit:AutoReloadSec+', MetaModel::GetConfig()->Get('min_reload_interval'))); $sRateTitle = addslashes(Dict::Format('UI:DashboardEdit:AutoReloadSec+', MetaModel::GetConfig()->Get('min_reload_interval')));
$oPage->add_ready_script( $oPage->add_ready_script(
<<<EOF <<<EOF
// Note: the title gets deleted by the validation mechanism // Note: the title gets deleted by the validation mechanism
$("#attr_auto_reload_sec").attr('data-tooltip-content', '$sRateTitle'); $("#attr_auto_reload_sec").attr('data-tooltip-content', '$sRateTitle');
CombodoTooltip.InitTooltipFromMarkup($("#attr_auto_reload_sec")); CombodoTooltip.InitTooltipFromMarkup($("#attr_auto_reload_sec"));
@@ -496,9 +522,11 @@ EOF
* *
* @return \Combodo\iTop\Application\UI\Base\Layout\Dashboard\DashboardLayout * @return \Combodo\iTop\Application\UI\Base\Layout\Dashboard\DashboardLayout
*/ */
public function Render($oPage, $bEditMode = false, $aExtraParams = [], $bCanEdit = true) public function Render($oPage, $bEditMode = false, $aExtraParams = array(), $bCanEdit = true)
{ {
$aExtraParams['dashboard_div_id'] = utils::Sanitize($aExtraParams['dashboard_div_id'] ?? null, $this->GetId(), utils::ENUM_SANITIZATION_FILTER_ELEMENT_IDENTIFIER); if (!array_key_exists('dashboard_div_id', $aExtraParams)) {
$aExtraParams['dashboard_div_id'] = utils::Sanitize($this->GetId(), '', 'element_identifier');
}
/** @var \DashboardLayoutMultiCol $oLayout */ /** @var \DashboardLayoutMultiCol $oLayout */
$oLayout = new $this->sLayoutClass(); $oLayout = new $this->sLayoutClass();
@@ -525,8 +553,7 @@ EOF
$oToolbar->AddHtml($sHtml); $oToolbar->AddHtml($sHtml);
} else { } else {
$oPage->add_script( $oPage->add_script(<<<JS
<<<JS
$(".ibo-top-bar--toolbar-dashboard-title").html("$sTitleForHTML").attr("title", $('<div>').html("$sTitleForHTML").text()); $(".ibo-top-bar--toolbar-dashboard-title").html("$sTitleForHTML").attr("title", $('<div>').html("$sTitleForHTML").text());
JS JS
); );
@@ -570,7 +597,7 @@ JS
* @param WebPage $oPage * @param WebPage $oPage
* @param array $aExtraParams * @param array $aExtraParams
*/ */
public function RenderDashletsProperties(WebPage $oPage, $aExtraParams = []) public function RenderDashletsProperties(WebPage $oPage, $aExtraParams = array())
{ {
// Toolbox/palette to edit the properties of each dashlet // Toolbox/palette to edit the properties of each dashlet
$oPage->add('<div class="ui-widget-content ui-corner-all ibo-dashlet--properties"><div class="ui-widget-header ui-corner-all ibo-dashlet--properties--title">'.Dict::S('UI:DashboardEdit:DashletProperties').'</div>'); $oPage->add('<div class="ui-widget-content ui-corner-all ibo-dashlet--properties"><div class="ui-widget-header ui-corner-all ibo-dashlet--properties--title">'.Dict::S('UI:DashboardEdit:DashletProperties').'</div>');
@@ -579,10 +606,13 @@ JS
$oLayout = new $this->sLayoutClass(); $oLayout = new $this->sLayoutClass();
$oPage->add('<div id="dashlet_properties">'); $oPage->add('<div id="dashlet_properties">');
foreach ($this->aCells as $iCellIdx => $aCell) { foreach($this->aCells as $iCellIdx => $aCell)
{
/** @var \Dashlet $oDashlet */ /** @var \Dashlet $oDashlet */
foreach ($aCell as $oDashlet) { foreach($aCell as $oDashlet)
if ($oDashlet->IsVisible()) { {
if ($oDashlet->IsVisible())
{
$oPage->add('<div class="dashlet_properties" id="dashlet_properties_'.$oDashlet->GetID().'" style="display:none">'); $oPage->add('<div class="dashlet_properties" id="dashlet_properties_'.$oDashlet->GetID().'" style="display:none">');
$oForm = $oDashlet->GetForm(); $oForm = $oDashlet->GetForm();
$this->SetFormParams($oForm, $aExtraParams); $this->SetFormParams($oForm, $aExtraParams);
@@ -604,17 +634,18 @@ JS
*/ */
protected function GetAvailableDashlets() protected function GetAvailableDashlets()
{ {
$aDashlets = []; $aDashlets = array();
foreach (get_declared_classes() as $sDashletClass) { foreach( get_declared_classes() as $sDashletClass)
{
// DashletUnknown is not among the selection as it is just a fallback for dashlets that can't instantiated. // DashletUnknown is not among the selection as it is just a fallback for dashlets that can't instantiated.
if (is_subclass_of($sDashletClass, 'Dashlet') && !in_array($sDashletClass, ['DashletUnknown', 'DashletProxy'])) { if (is_subclass_of($sDashletClass, 'Dashlet') && !in_array($sDashletClass, array('DashletUnknown', 'DashletProxy'))) {
$oReflection = new ReflectionClass($sDashletClass); $oReflection = new ReflectionClass($sDashletClass);
if (!$oReflection->isAbstract()) { if (!$oReflection->isAbstract()) {
$aCallSpec = [$sDashletClass, 'IsVisible']; $aCallSpec = array($sDashletClass, 'IsVisible');
$bVisible = call_user_func($aCallSpec); $bVisible = call_user_func($aCallSpec);
if ($bVisible) { if ($bVisible) {
$aCallSpec = [$sDashletClass, 'GetInfo']; $aCallSpec = array($sDashletClass, 'GetInfo');
$aInfo = call_user_func($aCallSpec); $aInfo = call_user_func($aCallSpec);
$aDashlets[$sDashletClass] = $aInfo; $aDashlets[$sDashletClass] = $aInfo;
} }
@@ -631,9 +662,11 @@ JS
protected function GetNewDashletId() protected function GetNewDashletId()
{ {
$iNewId = 0; $iNewId = 0;
foreach ($this->aCells as $aDashlets) { foreach($this->aCells as $aDashlets)
{
/** @var \Dashlet $oDashlet */ /** @var \Dashlet $oDashlet */
foreach ($aDashlets as $oDashlet) { foreach($aDashlets as $oDashlet)
{
$iNewId = max($iNewId, (int)$oDashlet->GetID()); $iNewId = max($iNewId, (int)$oDashlet->GetID());
} }
} }
@@ -650,15 +683,15 @@ JS
* *
* @return void * @return void
*/ */
abstract protected function PrepareDashletForRendering(Dashlet $oDashlet, $aCoordinates, $aExtraParams = []); abstract protected function PrepareDashletForRendering(Dashlet $oDashlet, $aCoordinates, $aExtraParams = array());
/** /**
* @param \DesignerForm $oForm * @param \DesignerForm $oForm
* @param array $aExtraParams * @param array $aExtraParams
* *
* @return mixed * @return mixed
*/ */
abstract protected function SetFormParams($oForm, $aExtraParams = []); abstract protected function SetFormParams($oForm, $aExtraParams = array());
/** /**
* @param string $sType * @param string $sType
@@ -668,7 +701,8 @@ JS
*/ */
public static function GetDashletClassFromType($sType, $oFactory = null) public static function GetDashletClassFromType($sType, $oFactory = null)
{ {
if (is_subclass_of($sType, 'Dashlet')) { if (is_subclass_of($sType, 'Dashlet'))
{
return $sType; return $sType;
} }
return 'DashletUnknown'; return 'DashletUnknown';
@@ -691,12 +725,14 @@ JS
*/ */
public static function GetDashletUniqueId($bIsCustomized, $sDashboardDivId, $iRow, $iCol, $sDashletOrigId) public static function GetDashletUniqueId($bIsCustomized, $sDashboardDivId, $iRow, $iCol, $sDashletOrigId)
{ {
if (strpos($sDashletOrigId, '_ID_row') !== false) { if(strpos($sDashletOrigId, '_ID_row') !== false)
{
return $sDashletOrigId; return $sDashletOrigId;
} }
$sDashletId = $sDashboardDivId."_ID_row".$iRow."_col".$iCol."_".$sDashletOrigId; $sDashletId = $sDashboardDivId."_ID_row".$iRow."_col".$iCol."_".$sDashletOrigId;
if ($bIsCustomized) { if ($bIsCustomized)
{
$sDashletId = 'CUSTOM_'.$sDashletId; $sDashletId = 'CUSTOM_'.$sDashletId;
} }
@@ -748,9 +784,9 @@ class RuntimeDashboard extends Dashboard
* @inheritDoc * @inheritDoc
* @throws \Exception * @throws \Exception
*/ */
protected function SetFormParams($oForm, $aExtraParams = []) protected function SetFormParams($oForm, $aExtraParams = array())
{ {
$oForm->SetSubmitParams(utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php', ['operation' => 'update_dashlet_property', 'extra_params' => $aExtraParams]); $oForm->SetSubmitParams(utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php', array('operation' => 'update_dashlet_property', 'extra_params' => $aExtraParams));
} }
/** /**
@@ -766,11 +802,14 @@ class RuntimeDashboard extends Dashboard
$oUDSearch->AddCondition('menu_code', $this->sId, '='); $oUDSearch->AddCondition('menu_code', $this->sId, '=');
$oUDSet = new DBObjectSet($oUDSearch); $oUDSet = new DBObjectSet($oUDSearch);
$bIsNew = false; $bIsNew = false;
if ($oUDSet->Count() > 0) { if ($oUDSet->Count() > 0)
{
// Assuming there is at most one couple {user, menu}! // Assuming there is at most one couple {user, menu}!
$oUserDashboard = $oUDSet->Fetch(); $oUserDashboard = $oUDSet->Fetch();
$oUserDashboard->Set('contents', $sXml); $oUserDashboard->Set('contents', $sXml);
} else { }
else
{
// No such customized dashboard for the current user, let's create a new record // No such customized dashboard for the current user, let's create a new record
$oUserDashboard = new UserDashboard(); $oUserDashboard = new UserDashboard();
$oUserDashboard->Set('user_id', UserRights::GetUserId()); $oUserDashboard->Set('user_id', UserRights::GetUserId());
@@ -801,7 +840,8 @@ class RuntimeDashboard extends Dashboard
$oUDSearch->AddCondition('user_id', UserRights::GetUserId(), '='); $oUDSearch->AddCondition('user_id', UserRights::GetUserId(), '=');
$oUDSearch->AddCondition('menu_code', $this->sId, '='); $oUDSearch->AddCondition('menu_code', $this->sId, '=');
$oUDSet = new DBObjectSet($oUDSearch); $oUDSet = new DBObjectSet($oUDSearch);
if ($oUDSet->Count() > 0) { if ($oUDSet->Count() > 0)
{
// Assuming there is at most one couple {user, menu}! // Assuming there is at most one couple {user, menu}!
$oUserDashboard = $oUDSet->Fetch(); $oUserDashboard = $oUDSet->Fetch();
utils::PushArchiveMode(false); utils::PushArchiveMode(false);
@@ -845,11 +885,14 @@ class RuntimeDashboard extends Dashboard
} else { } else {
$sDashboardDefinition = @file_get_contents($sDashboardFileSanitized); $sDashboardDefinition = @file_get_contents($sDashboardFileSanitized);
} }
} else { }
else
{
$sDashboardDefinition = @file_get_contents($sDashboardFileSanitized); $sDashboardDefinition = @file_get_contents($sDashboardFileSanitized);
} }
if ($sDashboardDefinition !== false) { if ($sDashboardDefinition !== false)
{
$oDashboard = new RuntimeDashboard($sDashBoardId); $oDashboard = new RuntimeDashboard($sDashBoardId);
$oDashboard->FromXml($sDashboardDefinition); $oDashboard->FromXml($sDashboardDefinition);
$oDashboard->SetCustomFlag($bCustomized); $oDashboard->SetCustomFlag($bCustomized);
@@ -896,6 +939,7 @@ class RuntimeDashboard extends Dashboard
$sDashboardDefinition = @file_get_contents($sDashboardFileSanitized); $sDashboardDefinition = @file_get_contents($sDashboardFileSanitized);
} }
if ($sDashboardDefinition !== false) { if ($sDashboardDefinition !== false) {
$oDashboard = new RuntimeDashboard($sDashBoardId); $oDashboard = new RuntimeDashboard($sDashBoardId);
$oDashboard->FromXml($sDashboardDefinition); $oDashboard->FromXml($sDashboardDefinition);
@@ -912,11 +956,11 @@ class RuntimeDashboard extends Dashboard
* @inheritDoc * @inheritDoc
* @throws \Exception * @throws \Exception
*/ */
public function Render($oPage, $bEditMode = false, $aExtraParams = [], $bCanEdit = true) public function Render($oPage, $bEditMode = false, $aExtraParams = array(), $bCanEdit = true)
{ {
if (!isset($aExtraParams['query_params']) && isset($aExtraParams['this->class'])) { if (!isset($aExtraParams['query_params']) && isset($aExtraParams['this->class'])) {
$oObj = MetaModel::GetObject($aExtraParams['this->class'], $aExtraParams['this->id']); $oObj = MetaModel::GetObject($aExtraParams['this->class'], $aExtraParams['this->id']);
$aRenderParams = ['query_params' => $oObj->ToArgsForQuery()]; $aRenderParams = array('query_params' => $oObj->ToArgsForQuery());
} else { } else {
$aRenderParams = $aExtraParams; $aRenderParams = $aExtraParams;
} }
@@ -926,7 +970,7 @@ class RuntimeDashboard extends Dashboard
if (isset($aExtraParams['query_params']['this->object()'])) { if (isset($aExtraParams['query_params']['this->object()'])) {
/** @var \DBObject $oObj */ /** @var \DBObject $oObj */
$oObj = $aExtraParams['query_params']['this->object()']; $oObj = $aExtraParams['query_params']['this->object()'];
$aAjaxParams = ['this->class' => get_class($oObj), 'this->id' => $oObj->GetKey()]; $aAjaxParams = array('this->class' => get_class($oObj), 'this->id' => $oObj->GetKey());
if (isset($aExtraParams['from_dashboard_page'])) { if (isset($aExtraParams['from_dashboard_page'])) {
$aAjaxParams['from_dashboard_page'] = $aExtraParams['from_dashboard_page']; $aAjaxParams['from_dashboard_page'] = $aExtraParams['from_dashboard_page'];
} }
@@ -959,7 +1003,9 @@ class RuntimeDashboard extends Dashboard
} }
JS JS
); );
} else { }
else
{
$oPage->add_script( $oPage->add_script(
<<<EOF <<<EOF
if (typeof(AutoReloadDashboardId$sDivId) !== 'undefined') if (typeof(AutoReloadDashboardId$sDivId) !== 'undefined')
@@ -988,7 +1034,7 @@ EOF
* @throws \CoreUnexpectedValue * @throws \CoreUnexpectedValue
* @throws \MySQLException * @throws \MySQLException
*/ */
protected function RenderSelector(WebPage $oPage, DashboardLayoutUIBlock $oDashboard, $aAjaxParams = []) protected function RenderSelector(WebPage $oPage, DashboardLayoutUIBlock $oDashboard, $aAjaxParams = array())
{ {
if (!$this->HasCustomDashboard()) { if (!$this->HasCustomDashboard()) {
return; return;
@@ -1006,7 +1052,7 @@ EOF
$sSelectorHtml .= '</div>'; $sSelectorHtml .= '</div>';
$sFile = addslashes($this->GetDefinitionFile()); $sFile = addslashes($this->GetDefinitionFile());
$sReloadURL = json_encode($this->GetReloadURL()); $sReloadURL = $this->GetReloadURL();
$bFromDashboardPage = isset($aAjaxParams['from_dashboard_page']) ? isset($aAjaxParams['from_dashboard_page']) : false; $bFromDashboardPage = isset($aAjaxParams['from_dashboard_page']) ? isset($aAjaxParams['from_dashboard_page']) : false;
if ($bFromDashboardPage) { if ($bFromDashboardPage) {
@@ -1048,7 +1094,8 @@ JS
*/ */
protected function HasCustomDashboard() protected function HasCustomDashboard()
{ {
try { try
{
// Search for an eventual user defined dashboard // Search for an eventual user defined dashboard
$oUDSearch = new DBObjectSearch('UserDashboard'); $oUDSearch = new DBObjectSearch('UserDashboard');
$oUDSearch->AddCondition('user_id', UserRights::GetUserId(), '='); $oUDSearch->AddCondition('user_id', UserRights::GetUserId(), '=');
@@ -1056,7 +1103,9 @@ JS
$oUDSet = new DBObjectSet($oUDSearch); $oUDSet = new DBObjectSet($oUDSearch);
return ($oUDSet->Count() > 0); return ($oUDSet->Count() > 0);
} catch (Exception $e) { }
catch (Exception $e)
{
return false; return false;
} }
} }
@@ -1092,23 +1141,22 @@ JS
->AddCSSClass('ibo-action-button'); ->AddCSSClass('ibo-action-button');
$oToolbar->AddSubBlock($oActionButton); $oToolbar->AddSubBlock($oActionButton);
$aActions = [];
$aActions = array();
$sFile = addslashes(utils::LocalPath($this->sDefinitionFile)); $sFile = addslashes(utils::LocalPath($this->sDefinitionFile));
$sJSExtraParams = json_encode($aExtraParams); $sJSExtraParams = json_encode($aExtraParams);
if ($this->HasCustomDashboard()) { if ($this->HasCustomDashboard()) {
$oEdit = new JSPopupMenuItem('UI:Dashboard:Edit', Dict::S('UI:Dashboard:EditCustom'), "return EditDashboard('{$this->sId}', '$sFile', $sJSExtraParams)"); $oEdit = new JSPopupMenuItem('UI:Dashboard:Edit', Dict::S('UI:Dashboard:EditCustom'), "return EditDashboard('{$this->sId}', '$sFile', $sJSExtraParams)");
$aActions[$oEdit->GetUID()] = $oEdit->GetMenuItem(); $aActions[$oEdit->GetUID()] = $oEdit->GetMenuItem();
$oRevert = new JSPopupMenuItem( $oRevert = new JSPopupMenuItem('UI:Dashboard:RevertConfirm', Dict::S('UI:Dashboard:DeleteCustom'),
'UI:Dashboard:RevertConfirm', "if (confirm('".addslashes(Dict::S('UI:Dashboard:RevertConfirm'))."')) return RevertDashboard('{$this->sId}', $sJSExtraParams); else return false");
Dict::S('UI:Dashboard:DeleteCustom'),
"if (confirm('".addslashes(Dict::S('UI:Dashboard:RevertConfirm'))."')) return RevertDashboard('{$this->sId}', $sJSExtraParams); else return false"
);
$aActions[$oRevert->GetUID()] = $oRevert->GetMenuItem(); $aActions[$oRevert->GetUID()] = $oRevert->GetMenuItem();
} else { } else {
$oEdit = new JSPopupMenuItem('UI:Dashboard:Edit', Dict::S('UI:Dashboard:CreateCustom'), "return EditDashboard('{$this->sId}', '$sFile', $sJSExtraParams)"); $oEdit = new JSPopupMenuItem('UI:Dashboard:Edit', Dict::S('UI:Dashboard:CreateCustom'), "return EditDashboard('{$this->sId}', '$sFile', $sJSExtraParams)");
$aActions[$oEdit->GetUID()] = $oEdit->GetMenuItem(); $aActions[$oEdit->GetUID()] = $oEdit->GetMenuItem();
} }
utils::GetPopupMenuItems($oPage, iPopupMenuExtension::MENU_DASHBOARD_ACTIONS, $this, $aActions); utils::GetPopupMenuItems($oPage, iPopupMenuExtension::MENU_DASHBOARD_ACTIONS, $this, $aActions);
$oActionsMenu = $oPage->GetPopoverMenu($sPopoverMenuId, $aActions) $oActionsMenu = $oPage->GetPopoverMenu($sPopoverMenuId, $aActions)
@@ -1118,7 +1166,7 @@ JS
$oToolbar->AddSubBlock($oActionButton) $oToolbar->AddSubBlock($oActionButton)
->AddSubBlock($oActionsMenu); ->AddSubBlock($oActionsMenu);
$sReloadURL = json_encode($this->GetReloadURL()); $sReloadURL = $this->GetReloadURL();
$oPage->add_script( $oPage->add_script(
<<<EOF <<<EOF
function EditDashboard(sId, sDashboardFile, aExtraParams) function EditDashboard(sId, sDashboardFile, aExtraParams)
@@ -1148,12 +1196,12 @@ EOF
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function RenderProperties($oPage, $aExtraParams = []) public function RenderProperties($oPage, $aExtraParams = array())
{ {
parent::RenderProperties($oPage, $aExtraParams); parent::RenderProperties($oPage, $aExtraParams);
$oPage->add_ready_script( $oPage->add_ready_script(
<<<EOF <<<EOF
$('#select_layout input').on('click', function() { $('#select_layout input').on('click', function() {
var sLayoutClass = $(this).val(); var sLayoutClass = $(this).val();
$('.itop-dashboard').runtimedashboard('option', {layout_class: sLayoutClass}); $('.itop-dashboard').runtimedashboard('option', {layout_class: sLayoutClass});
@@ -1180,6 +1228,7 @@ EOF
); );
} }
/** /**
* @param WebPage $oPage * @param WebPage $oPage
* *
@@ -1190,11 +1239,11 @@ EOF
* @throws \ReflectionException * @throws \ReflectionException
* @throws \Exception * @throws \Exception
*/ */
public function RenderEditor($oPage, $aExtraParams = []) public function RenderEditor($oPage, $aExtraParams = array())
{ {
if (isset($aExtraParams['this->class'])) { if (isset($aExtraParams['this->class'])) {
$oObj = MetaModel::GetObject($aExtraParams['this->class'], $aExtraParams['this->id']); $oObj = MetaModel::GetObject($aExtraParams['this->class'], $aExtraParams['this->id']);
$aRenderParams = ['query_params' => $oObj->ToArgsForQuery()]; $aRenderParams = array('query_params' => $oObj->ToArgsForQuery());
} else { } else {
$aRenderParams = $aExtraParams; $aRenderParams = $aExtraParams;
} }
@@ -1216,22 +1265,23 @@ EOF
$sDialogTitle = Dict::S('UI:DashboardEdit:Title'); $sDialogTitle = Dict::S('UI:DashboardEdit:Title');
$sOkButtonLabel = Dict::S('UI:Button:Save'); $sOkButtonLabel = Dict::S('UI:Button:Save');
$sCancelButtonLabel = Dict::S('UI:Button:Cancel'); $sCancelButtonLabel = Dict::S('UI:Button:Cancel');
$sId = json_encode($this->sId); $sId = utils::HtmlEntities($this->sId);
$sLayoutClass = json_encode($this->sLayoutClass); $sLayoutClass = utils::HtmlEntities($this->sLayoutClass);
$sAutoReload = $this->bAutoReload ? 'true' : 'false'; $sAutoReload = $this->bAutoReload ? 'true' : 'false';
$sAutoReloadSec = (string) $this->iAutoReloadSec; $sAutoReloadSec = (string) $this->iAutoReloadSec;
$sTitle = json_encode($this->sTitle); $sTitle = utils::HtmlEntities($this->sTitle);
$sFile = json_encode($this->GetDefinitionFile()); $sFile = utils::HtmlEntities($this->GetDefinitionFile());
$sFileForJS = json_encode($this->GetDefinitionFile());
$sUrl = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php'; $sUrl = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php';
$sReloadURL = json_encode($this->GetReloadURL()); $sReloadURL = $this->GetReloadURL();
$sExitConfirmationMessage = addslashes(Dict::S('UI:NavigateAwayConfirmationMessage')); $sExitConfirmationMessage = addslashes(Dict::S('UI:NavigateAwayConfirmationMessage'));
$sCancelConfirmationMessage = addslashes(Dict::S('UI:CancelConfirmationMessage')); $sCancelConfirmationMessage = addslashes(Dict::S('UI:CancelConfirmationMessage'));
$sAutoApplyConfirmationMessage = addslashes(Dict::S('UI:AutoApplyConfirmationMessage')); $sAutoApplyConfirmationMessage = addslashes(Dict::S('UI:AutoApplyConfirmationMessage'));
$oPage->add_ready_script( $oPage->add_ready_script(
<<<JS <<<JS
window.bLeavingOnUserAction = false; window.bLeavingOnUserAction = false;
$('#dashboard_editor').dialog({ $('#dashboard_editor').dialog({
@@ -1278,15 +1328,15 @@ $('#dashboard_editor').dialog({
}); });
$('#dashboard_editor .ui-layout-center').runtimedashboard({ $('#dashboard_editor .ui-layout-center').runtimedashboard({
dashboard_id: $sId, dashboard_id: '$sId',
layout_class: $sLayoutClass, layout_class: '$sLayoutClass',
title: $sTitle, title: '$sTitle',
auto_reload: $sAutoReload, auto_reload: $sAutoReload,
auto_reload_sec: $sAutoReloadSec, auto_reload_sec: $sAutoReloadSec,
submit_to: '$sUrl', submit_to: '$sUrl',
submit_parameters: {operation: 'save_dashboard', file: $sFile, extra_params: $sJSExtraParams, reload_url: '$sReloadURL'}, submit_parameters: {operation: 'save_dashboard', file: {$sFileForJS}, extra_params: $sJSExtraParams, reload_url: '$sReloadURL'},
render_to: '$sUrl', render_to: '$sUrl',
render_parameters: {operation: 'render_dashboard', file: $sFile, extra_params: $sJSExtraParams, reload_url: '$sReloadURL'}, render_parameters: {operation: 'render_dashboard', file: {$sFileForJS}, extra_params: $sJSExtraParams, reload_url: '$sReloadURL'},
new_dashlet_parameters: {operation: 'new_dashlet'} new_dashlet_parameters: {operation: 'new_dashlet'}
}); });
@@ -1339,89 +1389,104 @@ JS
$sContextMenuId = $oAppContext->GetCurrentValue('menu', null); $sContextMenuId = $oAppContext->GetCurrentValue('menu', null);
$oForm = new DesignerForm(); $oForm = new DesignerForm();
// Get the list of all 'dashboard' menus in which we can insert a dashlet // Get the list of all 'dashboard' menus in which we can insert a dashlet
$aAllMenus = ApplicationMenu::ReflectionMenuNodes(); $aAllMenus = ApplicationMenu::ReflectionMenuNodes();
$sRootMenuId = ApplicationMenu::GetRootMenuId($sContextMenuId); $sRootMenuId = ApplicationMenu::GetRootMenuId($sContextMenuId);
$aAllowedDashboards = []; $aAllowedDashboards = array();
$sDefaultDashboard = null; $sDefaultDashboard = null;
// Store the parent menus for acces check // Store the parent menus for acces check
$aParentMenus = []; $aParentMenus = array();
foreach ($aAllMenus as $idx => $aMenu) { foreach($aAllMenus as $idx => $aMenu)
/** @var MenuNode $oMenu */ {
$oMenu = $aMenu['node']; /** @var MenuNode $oMenu */
if (count(ApplicationMenu::GetChildren($oMenu->GetIndex())) > 0) { $oMenu = $aMenu['node'];
$aParentMenus[$oMenu->GetMenuId()] = $aMenu; if (count(ApplicationMenu::GetChildren($oMenu->GetIndex())) > 0)
} {
} $aParentMenus[$oMenu->GetMenuId()] = $aMenu;
}
}
foreach ($aAllMenus as $idx => $aMenu) { foreach($aAllMenus as $idx => $aMenu)
{
$oMenu = $aMenu['node']; $oMenu = $aMenu['node'];
if ($oMenu instanceof DashboardMenuNode) { if ($oMenu instanceof DashboardMenuNode)
// Get the root parent for access check {
$sParentId = $aMenu['parent']; // Get the root parent for access check
$aParentMenu = $aParentMenus[$sParentId]; $sParentId = $aMenu['parent'];
while (isset($aParentMenus[$aParentMenu['parent']])) { $aParentMenu = $aParentMenus[$sParentId];
// grand parent exists while (isset($aParentMenus[$aParentMenu['parent']]))
$sParentId = $aParentMenu['parent']; {
$aParentMenu = $aParentMenus[$sParentId]; // grand parent exists
} $sParentId = $aParentMenu['parent'];
/** @var \MenuNode $oParentMenu */ $aParentMenu = $aParentMenus[$sParentId];
$oParentMenu = $aParentMenu['node']; }
if ($oMenu->IsEnabled() && $oParentMenu->IsEnabled()) { /** @var \MenuNode $oParentMenu */
$sMenuLabel = $oMenu->GetTitle(); $oParentMenu = $aParentMenu['node'];
$sParentLabel = Dict::S('Menu:'.$sParentId); if ($oMenu->IsEnabled() && $oParentMenu->IsEnabled())
if ($sParentLabel != $sMenuLabel) { {
$aAllowedDashboards[$oMenu->GetMenuId()] = $sParentLabel.' - '.$sMenuLabel; $sMenuLabel = $oMenu->GetTitle();
} else { $sParentLabel = Dict::S('Menu:'.$sParentId);
$aAllowedDashboards[$oMenu->GetMenuId()] = $sMenuLabel; if ($sParentLabel != $sMenuLabel)
} {
if (empty($sDefaultDashboard) && ($sRootMenuId == ApplicationMenu::GetRootMenuId($oMenu->GetMenuId()))) { $aAllowedDashboards[$oMenu->GetMenuId()] = $sParentLabel.' - '.$sMenuLabel;
$sDefaultDashboard = $oMenu->GetMenuId(); }
} else
} {
} $aAllowedDashboards[$oMenu->GetMenuId()] = $sMenuLabel;
}
if (empty($sDefaultDashboard) && ($sRootMenuId == ApplicationMenu::GetRootMenuId($oMenu->GetMenuId())))
{
$sDefaultDashboard = $oMenu->GetMenuId();
}
}
}
} }
asort($aAllowedDashboards); asort($aAllowedDashboards);
$oField = new DesignerComboField('menu_id', Dict::S('UI:DashletCreation:Dashboard'), $sDefaultDashboard); $oField = new DesignerComboField('menu_id', Dict::S('UI:DashletCreation:Dashboard'), $sDefaultDashboard);
$oField->SetAllowedValues($aAllowedDashboards); $oField->SetAllowedValues($aAllowedDashboards);
$oField->SetMandatory(true); $oField->SetMandatory(true);
$oForm->AddField($oField); $oForm->AddField($oField);
// Get the list of possible dashlets that support a creation from // Get the list of possible dashlets that support a creation from
// an OQL // an OQL
$aDashlets = []; $aDashlets = array();
foreach (get_declared_classes() as $sDashletClass) { foreach(get_declared_classes() as $sDashletClass)
if (is_subclass_of($sDashletClass, 'Dashlet')) { {
if (is_subclass_of($sDashletClass, 'Dashlet'))
{
$oReflection = new ReflectionClass($sDashletClass); $oReflection = new ReflectionClass($sDashletClass);
if (!$oReflection->isAbstract()) { if (!$oReflection->isAbstract())
$aCallSpec = [$sDashletClass, 'CanCreateFromOQL']; {
$aCallSpec = array($sDashletClass, 'CanCreateFromOQL');
$bShorcutMode = call_user_func($aCallSpec); $bShorcutMode = call_user_func($aCallSpec);
if ($bShorcutMode) { if ($bShorcutMode)
$aCallSpec = [$sDashletClass, 'GetInfo']; {
$aCallSpec = array($sDashletClass, 'GetInfo');
$aInfo = call_user_func($aCallSpec); $aInfo = call_user_func($aCallSpec);
$aDashlets[$sDashletClass] = ['label' => $aInfo['label'], 'class' => $sDashletClass, 'icon' => $aInfo['icon']]; $aDashlets[$sDashletClass] = array('label' => $aInfo['label'], 'class' => $sDashletClass, 'icon' => $aInfo['icon']);
} }
} }
} }
} }
$oSelectorField = new DesignerFormSelectorField('dashlet_class', Dict::S('UI:DashletCreation:DashletType'), ''); $oSelectorField = new DesignerFormSelectorField('dashlet_class', Dict::S('UI:DashletCreation:DashletType'), '');
$oForm->AddField($oSelectorField); $oForm->AddField($oSelectorField);
foreach ($aDashlets as $sDashletClass => $aDashletInfo) { foreach($aDashlets as $sDashletClass => $aDashletInfo)
{
$oSubForm = new DesignerForm(); $oSubForm = new DesignerForm();
$oMetaModel = new ModelReflectionRuntime(); $oMetaModel = new ModelReflectionRuntime();
/** @var \Dashlet $oDashlet */ /** @var \Dashlet $oDashlet */
$oDashlet = new $sDashletClass($oMetaModel, 0); $oDashlet = new $sDashletClass($oMetaModel, 0);
$oDashlet->GetPropertiesFieldsFromOQL($oSubForm, $sOQL); $oDashlet->GetPropertiesFieldsFromOQL($oSubForm, $sOQL);
$oSelectorField->AddSubForm($oSubForm, $aDashletInfo['label'], $aDashletInfo['class']); $oSelectorField->AddSubForm($oSubForm, $aDashletInfo['label'], $aDashletInfo['class']);
} }
$oField = new DesignerBooleanField('open_editor', Dict::S('UI:DashletCreation:EditNow'), true); $oField = new DesignerBooleanField('open_editor', Dict::S('UI:DashletCreation:EditNow'), true);
$oForm->AddField($oField); $oForm->AddField($oField);
return $oForm; return $oForm;
} }
@@ -1440,11 +1505,11 @@ JS
$oForm->Render($oPage); $oForm->Render($oPage);
$oPage->add('</div>'); $oPage->add('</div>');
$sDialogTitle = Dict::S('UI:DashletCreation:Title'); $sDialogTitle = Dict::S('UI:DashletCreation:Title');
$sOkButtonLabel = Dict::S('UI:Button:Ok'); $sOkButtonLabel = Dict::S('UI:Button:Ok');
$sCancelButtonLabel = Dict::S('UI:Button:Cancel'); $sCancelButtonLabel = Dict::S('UI:Button:Cancel');
$oPage->add_ready_script( $oPage->add_ready_script(
<<<JS <<<JS
$('#dashlet_creation_dlg').dialog({ $('#dashlet_creation_dlg').dialog({
@@ -1542,7 +1607,7 @@ JS
/** /**
* @inheritDoc * @inheritDoc
*/ */
protected function PrepareDashletForRendering(Dashlet $oDashlet, $aCoordinates, $aExtraParams = []) protected function PrepareDashletForRendering(Dashlet $oDashlet, $aCoordinates, $aExtraParams = array())
{ {
$sDashletIdOrig = $oDashlet->GetID(); $sDashletIdOrig = $oDashlet->GetID();
$sDashboardSanitizedId = $this->GetSanitizedId(); $sDashboardSanitizedId = $this->GetSanitizedId();
@@ -1569,27 +1634,31 @@ JS
private function UpdateDashletUserPrefs(Dashlet $oDashlet, $sDashletIdOrig, array $aExtraParams) private function UpdateDashletUserPrefs(Dashlet $oDashlet, $sDashletIdOrig, array $aExtraParams)
{ {
$bIsDashletWithListPref = ($oDashlet instanceof DashletObjectList); $bIsDashletWithListPref = ($oDashlet instanceof DashletObjectList);
if (!$bIsDashletWithListPref) { if (!$bIsDashletWithListPref)
{
return; return;
} }
/** @var \DashletObjectList $oDashlet */ /** @var \DashletObjectList $oDashlet */
$bDashletIdInNewFormat = ($sDashletIdOrig === $oDashlet->GetID()); $bDashletIdInNewFormat = ($sDashletIdOrig === $oDashlet->GetID());
if ($bDashletIdInNewFormat) { if ($bDashletIdInNewFormat)
{
return; return;
} }
$sNewPrefKey = $this->GetDashletObjectListAppUserPreferencesPrefix($oDashlet, $aExtraParams, $oDashlet->GetID()); $sNewPrefKey = $this->GetDashletObjectListAppUserPreferencesPrefix($oDashlet, $aExtraParams, $oDashlet->GetID());
$sPrefValueForNewKey = appUserPreferences::GetPref($sNewPrefKey, null); $sPrefValueForNewKey = appUserPreferences::GetPref($sNewPrefKey, null);
$bHasPrefInNewFormat = ($sPrefValueForNewKey !== null); $bHasPrefInNewFormat = ($sPrefValueForNewKey !== null);
if ($bHasPrefInNewFormat) { if ($bHasPrefInNewFormat)
{
return; return;
} }
$sOldPrefKey = $this->GetDashletObjectListAppUserPreferencesPrefix($oDashlet, $aExtraParams, $sDashletIdOrig); $sOldPrefKey = $this->GetDashletObjectListAppUserPreferencesPrefix($oDashlet, $aExtraParams, $sDashletIdOrig);
$sPrefValueForOldKey = appUserPreferences::GetPref($sOldPrefKey, null); $sPrefValueForOldKey = appUserPreferences::GetPref($sOldPrefKey, null);
$bHasPrefInOldFormat = ($sPrefValueForOldKey !== null); $bHasPrefInOldFormat = ($sPrefValueForOldKey !== null);
if (!$bHasPrefInOldFormat) { if (!$bHasPrefInOldFormat)
{
return; return;
} }
@@ -1608,7 +1677,7 @@ JS
private function GetDashletObjectListAppUserPreferencesPrefix(DashletObjectList $oDashlet, $aExtraParams, $sDashletId) private function GetDashletObjectListAppUserPreferencesPrefix(DashletObjectList $oDashlet, $aExtraParams, $sDashletId)
{ {
$sDataTableId = Dashlet::APPUSERPREFERENCES_PREFIX.$sDashletId; $sDataTableId = Dashlet::APPUSERPREFERENCES_PREFIX.$sDashletId;
$aClassAliases = []; $aClassAliases = array();
try { try {
$oFilter = $oDashlet->GetDBSearch($aExtraParams); $oFilter = $oDashlet->GetDBSearch($aExtraParams);
$aClassAliases = $oFilter->GetSelectedClasses(); $aClassAliases = $oFilter->GetSelectedClasses();

View File

@@ -1,10 +1,9 @@
<?php <?php
// Copyright (C) 2010-2024 Combodo SAS // Copyright (C) 2010-2024 Combodo SAS
// //
// This file is part of iTop. // This file is part of iTop.
// //
// iTop is free software; you can redistribute it and/or modify // iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by // it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
@@ -39,21 +38,21 @@ abstract class DashboardLayout
* @since 2.7.0 * @since 2.7.0
*/ */
abstract public function GetDashletCoordinates($iCellIdx); abstract public function GetDashletCoordinates($iCellIdx);
public static function GetInfo() public static function GetInfo()
{ {
return [ return array(
'label' => '', 'label' => '',
'icon' => '', 'icon' => '',
'description' => '', 'description' => '',
]; );
} }
} }
abstract class DashboardLayoutMultiCol extends DashboardLayout abstract class DashboardLayoutMultiCol extends DashboardLayout
{ {
protected $iNbCols; protected $iNbCols;
public function __construct() public function __construct()
{ {
$this->iNbCols = 1; $this->iNbCols = 1;
@@ -64,38 +63,47 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
$aKeys = array_reverse(array_keys($aDashlets)); $aKeys = array_reverse(array_keys($aDashlets));
$idx = 0; $idx = 0;
$bNoVisibleFound = true; $bNoVisibleFound = true;
while ($idx < count($aKeys) && $bNoVisibleFound) { while($idx < count($aKeys) && $bNoVisibleFound)
{
/** @var \Dashlet $oDashlet */ /** @var \Dashlet $oDashlet */
$oDashlet = $aDashlets[$aKeys[$idx]]; $oDashlet = $aDashlets[$aKeys[$idx]];
if ($oDashlet::IsVisible()) { if ($oDashlet::IsVisible())
{
$bNoVisibleFound = false; $bNoVisibleFound = false;
} else { }
else
{
unset($aDashlets[$aKeys[$idx]]); unset($aDashlets[$aKeys[$idx]]);
} }
$idx++; $idx++;
} }
return $aDashlets; return $aDashlets;
} }
protected function TrimCellsArray($aCells) protected function TrimCellsArray($aCells)
{ {
foreach ($aCells as $key => $aDashlets) { foreach($aCells as $key => $aDashlets)
{
$aCells[$key] = $this->TrimCell($aDashlets); $aCells[$key] = $this->TrimCell($aDashlets);
} }
$aKeys = array_reverse(array_keys($aCells)); $aKeys = array_reverse(array_keys($aCells));
$idx = 0; $idx = 0;
$bNoVisibleFound = true; $bNoVisibleFound = true;
while ($idx < count($aKeys) && $bNoVisibleFound) { while($idx < count($aKeys) && $bNoVisibleFound)
{
$aDashlets = $aCells[$aKeys[$idx]]; $aDashlets = $aCells[$aKeys[$idx]];
if (count($aDashlets) > 0) { if (count($aDashlets) > 0)
{
$bNoVisibleFound = false; $bNoVisibleFound = false;
} else { }
else
{
unset($aCells[$aKeys[$idx]]); unset($aCells[$aKeys[$idx]]);
} }
$idx++; $idx++;
} }
return $aCells; return $aCells;
} }
/** /**
@@ -104,7 +112,7 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
* @param bool $bEditMode * @param bool $bEditMode
* @param array $aExtraParams * @param array $aExtraParams
*/ */
public function Render($oPage, $aCells, $bEditMode = false, $aExtraParams = []) public function Render($oPage, $aCells, $bEditMode = false, $aExtraParams = array())
{ {
// Trim the list of cells to remove the invisible/empty ones at the end of the array // Trim the list of cells to remove the invisible/empty ones at the end of the array
$aCells = $this->TrimCellsArray($aCells); $aCells = $this->TrimCellsArray($aCells);
@@ -149,7 +157,8 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
$oPage->add_script("function updateDashboard".$aExtraParams['dashboard_div_id']."(){".$sJSReload."}"); $oPage->add_script("function updateDashboard".$aExtraParams['dashboard_div_id']."(){".$sJSReload."}");
if ($bEditMode) { // Add one row for extensibility if ($bEditMode) // Add one row for extensibility
{
$oDashboardRow = new DashboardRow(); $oDashboardRow = new DashboardRow();
$oDashboardLayout->AddDashboardRow($oDashboardRow); $oDashboardLayout->AddDashboardRow($oDashboardRow);
@@ -171,7 +180,7 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
$iColNumber = (int) $iCellIdx % $this->iNbCols; $iColNumber = (int) $iCellIdx % $this->iNbCols;
$iRowNumber = (int) floor($iCellIdx / $this->iNbCols); $iRowNumber = (int) floor($iCellIdx / $this->iNbCols);
return [$iColNumber, $iRowNumber]; return array($iColNumber, $iRowNumber);
} }
} }
@@ -182,13 +191,13 @@ class DashboardLayoutOneCol extends DashboardLayoutMultiCol
parent::__construct(); parent::__construct();
$this->iNbCols = 1; $this->iNbCols = 1;
} }
public static function GetInfo() static public function GetInfo()
{ {
return [ return array(
'label' => 'One Column', 'label' => 'One Column',
'icon' => 'images/layout_1col.png', 'icon' => 'images/layout_1col.png',
'description' => '', 'description' => '',
]; );
} }
} }
@@ -199,13 +208,13 @@ class DashboardLayoutTwoCols extends DashboardLayoutMultiCol
parent::__construct(); parent::__construct();
$this->iNbCols = 2; $this->iNbCols = 2;
} }
public static function GetInfo() static public function GetInfo()
{ {
return [ return array(
'label' => 'Two Columns', 'label' => 'Two Columns',
'icon' => 'images/layout_2col.png', 'icon' => 'images/layout_2col.png',
'description' => '', 'description' => '',
]; );
} }
} }
@@ -216,12 +225,12 @@ class DashboardLayoutThreeCols extends DashboardLayoutMultiCol
parent::__construct(); parent::__construct();
$this->iNbCols = 3; $this->iNbCols = 3;
} }
public static function GetInfo() static public function GetInfo()
{ {
return [ return array(
'label' => 'Two Columns', 'label' => 'Two Columns',
'icon' => 'images/layout_3col.png', 'icon' => 'images/layout_3col.png',
'description' => '', 'description' => '',
]; );
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -238,10 +238,6 @@ The object can be modified.]]></description>
<description>Creation flag</description> <description>Creation flag</description>
<type>boolean</type> <type>boolean</type>
</event_datum> </event_datum>
<event_datum id="stimulus_applied">
<description>Life cycle stimulus applied (null if not within a transition)</description>
<type>string</type>
</event_datum>
<event_datum id="debug_info"> <event_datum id="debug_info">
<description>Debug string</description> <description>Debug string</description>
<type>string</type> <type>string</type>
@@ -267,10 +263,6 @@ Call $this->AddCheckWarning($sWarningMessage) to display a warning.
<description>Creation flag</description> <description>Creation flag</description>
<type>boolean</type> <type>boolean</type>
</event_datum> </event_datum>
<event_datum id="stimulus_applied">
<description>Life cycle stimulus applied (null if not within a transition)</description>
<type>string</type>
</event_datum>
<event_datum id="debug_info"> <event_datum id="debug_info">
<description>Debug string</description> <description>Debug string</description>
<type>string</type> <type>string</type>
@@ -298,10 +290,6 @@ The modifications can be propagated to other objects.]]></description>
<description><![CDATA[For updates, the list of changes done during this operation]]></description> <description><![CDATA[For updates, the list of changes done during this operation]]></description>
<type>array</type> <type>array</type>
</event_datum> </event_datum>
<event_datum id="stimulus_applied">
<description>Life cycle stimulus applied (null if not within a transition)</description>
<type>string</type>
</event_datum>
<event_datum id="debug_info"> <event_datum id="debug_info">
<description>Debug string</description> <description>Debug string</description>
<type>string</type> <type>string</type>
@@ -432,14 +420,6 @@ The only action allowed is to deny transitions with $this->DenyTransition($sTran
<description>The object inserted</description> <description>The object inserted</description>
<type>DBObject</type> <type>DBObject</type>
</event_datum> </event_datum>
<event_datum id="is_new">
<description>Creation flag</description>
<type>boolean</type>
</event_datum>
<event_datum id="stimulus_applied">
<description>Life cycle stimulus applied (null if not within a transition)</description>
<type>string</type>
</event_datum>
<event_datum id="debug_info"> <event_datum id="debug_info">
<description>Debug string</description> <description>Debug string</description>
<type>string</type> <type>string</type>

View File

@@ -80,31 +80,42 @@ class DataTable
// Identified tables can have their own specific settings // Identified tables can have their own specific settings
$oCustomSettings = DataTableSettings::GetTableSettings($this->aClassAliases, $this->sTableId); $oCustomSettings = DataTableSettings::GetTableSettings($this->aClassAliases, $this->sTableId);
if ($oCustomSettings != null) { if ($oCustomSettings != null)
{
// Custom settings overload the default ones // Custom settings overload the default ones
$this->bUseCustomSettings = true; $this->bUseCustomSettings = true;
if ($this->oDefaultSettings->iDefaultPageSize == 0) { if ($this->oDefaultSettings->iDefaultPageSize == 0)
{
$oCustomSettings->iDefaultPageSize = 0; $oCustomSettings->iDefaultPageSize = 0;
} }
} else { }
else
{
$oCustomSettings = $oSettings; $oCustomSettings = $oSettings;
} }
if ($oCustomSettings->iDefaultPageSize > 0) { if ($oCustomSettings->iDefaultPageSize > 0)
{
$this->oSet->SetLimit($oCustomSettings->iDefaultPageSize); $this->oSet->SetLimit($oCustomSettings->iDefaultPageSize);
} }
$this->oSet->SetOrderBy($oCustomSettings->GetSortOrder()); $this->oSet->SetOrderBy($oCustomSettings->GetSortOrder());
// Load only the requested columns // Load only the requested columns
$aColumnsToLoad = []; $aColumnsToLoad = array();
foreach ($oCustomSettings->aColumns as $sAlias => $aColumnsInfo) { foreach($oCustomSettings->aColumns as $sAlias => $aColumnsInfo)
foreach ($aColumnsInfo as $sAttCode => $aData) { {
if ($sAttCode != '_key_') { foreach($aColumnsInfo as $sAttCode => $aData)
if ($aData['checked']) { {
if ($sAttCode != '_key_')
{
if ($aData['checked'])
{
$aColumnsToLoad[$sAlias][] = $sAttCode; $aColumnsToLoad[$sAlias][] = $sAttCode;
} else { }
// See if this column is a must to load else
{
// See if this column is a must to load
$sClass = $this->aClassAliases[$sAlias]; $sClass = $this->aClassAliases[$sAlias];
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode); $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
if ($oAttDef->AlwaysLoadInTables()) { if ($oAttDef->AlwaysLoadInTables()) {
@@ -116,15 +127,18 @@ class DataTable
} }
$this->oSet->OptimizeColumnLoad($aColumnsToLoad); $this->oSet->OptimizeColumnLoad($aColumnsToLoad);
$bToolkitMenu = true; $bToolkitMenu = true;
if (isset($aExtraParams['toolkit_menu'])) { if (isset($aExtraParams['toolkit_menu']))
{
$bToolkitMenu = (bool) $aExtraParams['toolkit_menu']; $bToolkitMenu = (bool) $aExtraParams['toolkit_menu'];
} }
if (UserRights::IsPortalUser()) { if (UserRights::IsPortalUser())
{
// Portal users have a limited access to data, for now they can only see what's configured for them // Portal users have a limited access to data, for now they can only see what's configured for them
$bToolkitMenu = false; $bToolkitMenu = false;
} }
return $this->GetAsHTML($oPage, $oCustomSettings->iDefaultPageSize, $oCustomSettings->iDefaultPageSize, 0, $oCustomSettings->aColumns, $bActionsMenu, $bToolkitMenu, $sSelectMode, $bViewLink, $aExtraParams); return $this->GetAsHTML($oPage, $oCustomSettings->iDefaultPageSize, $oCustomSettings->iDefaultPageSize, 0, $oCustomSettings->aColumns, $bActionsMenu, $bToolkitMenu, $sSelectMode, $bViewLink, $aExtraParams);
} }
@@ -153,10 +167,10 @@ class DataTable
if ($bActionsMenu) { if ($bActionsMenu) {
$sActionsMenu = $this->GetActionsMenu($oPage, $aExtraParams); $sActionsMenu = $this->GetActionsMenu($oPage, $aExtraParams);
} }
// if ($bToolkitMenu) // if ($bToolkitMenu)
// { // {
// $sToolkitMenu = $this->GetToolkitMenu($oPage, $aExtraParams); // $sToolkitMenu = $this->GetToolkitMenu($oPage, $aExtraParams);
// } // }
$sDataTable = $this->GetHTMLTable($oPage, $aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams); $sDataTable = $this->GetHTMLTable($oPage, $aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams);
$sConfigDlg = $this->GetTableConfigDlg($oPage, $aColumns, $bViewLink, $iDefaultPageSize); $sConfigDlg = $this->GetTableConfigDlg($oPage, $aColumns, $bViewLink, $iDefaultPageSize);
@@ -174,7 +188,7 @@ class DataTable
$aExtraParams['show_obsolete_data'] = $this->bShowObsoleteData; $aExtraParams['show_obsolete_data'] = $this->bShowObsoleteData;
$aOptions = [ $aOptions = array(
'sPersistentId' => '', 'sPersistentId' => '',
'sFilter' => $this->oSet->GetFilter()->serialize(), 'sFilter' => $this->oSet->GetFilter()->serialize(),
'oColumns' => $aColumns, 'oColumns' => $aColumns,
@@ -188,11 +202,12 @@ class DataTable
'sTableId' => $this->sTableId, 'sTableId' => $this->sTableId,
'oExtraParams' => $aExtraParams, 'oExtraParams' => $aExtraParams,
'sRenderUrl' => utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php', 'sRenderUrl' => utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php',
'oRenderParameters' => ['str' => ''], // Forces JSON to encode this as a object... 'oRenderParameters' => array('str' => ''), // Forces JSON to encode this as a object...
'oDefaultSettings' => ['str' => ''], // Forces JSON to encode this as a object... 'oDefaultSettings' => array('str' => ''), // Forces JSON to encode this as a object...
'oLabels' => ['moveup' => Dict::S('UI:Button:MoveUp'), 'movedown' => Dict::S('UI:Button:MoveDown')], 'oLabels' => array('moveup' => Dict::S('UI:Button:MoveUp'), 'movedown' => Dict::S('UI:Button:MoveDown')),
]; );
if ($this->oDefaultSettings != null) { if($this->oDefaultSettings != null)
{
$aOptions['oDefaultSettings'] = $this->GetAsHash($this->oDefaultSettings); $aOptions['oDefaultSettings'] = $this->GetAsHash($this->oDefaultSettings);
} }
$sJSOptions = json_encode($aOptions); $sJSOptions = json_encode($aOptions);
@@ -207,14 +222,16 @@ class DataTable
*/ */
public function GetAsHTMLTableRows(WebPage $oPage, $iPageSize, $aColumns, $sSelectMode, $bViewLink, $aExtraParams) public function GetAsHTMLTableRows(WebPage $oPage, $iPageSize, $aColumns, $sSelectMode, $bViewLink, $aExtraParams)
{ {
if ($iPageSize < 1) { if ($iPageSize < 1)
{
$iPageSize = -1; // convention: no pagination $iPageSize = -1; // convention: no pagination
} }
$aAttribs = $this->GetHTMLTableConfig($aColumns, $sSelectMode, $bViewLink); $aAttribs = $this->GetHTMLTableConfig($aColumns, $sSelectMode, $bViewLink);
$aValues = $this->GetHTMLTableValues($aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams); $aValues = $this->GetHTMLTableValues($aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams);
$sHtml = ''; $sHtml = '';
foreach ($aValues as $aRow) { foreach($aValues as $aRow)
{
$sHtml .= $oPage->GetTableRow($aRow, $aAttribs); $sHtml .= $oPage->GetTableRow($aRow, $aAttribs);
} }
return $sHtml; return $sHtml;
@@ -228,12 +245,15 @@ class DataTable
*/ */
protected function GetObjectCount(WebPage $oPage, $sSelectMode) protected function GetObjectCount(WebPage $oPage, $sSelectMode)
{ {
if (($sSelectMode == 'single') || ($sSelectMode == 'multiple')) { if (($sSelectMode == 'single') || ($sSelectMode == 'multiple'))
{
$sHtml = '<div class="pagination_objcount">'.Dict::Format('UI:Pagination:HeaderSelection', '<span id="total">'.$this->iNbObjects.'</span>', '<span class="selectedCount">0</span>').'</div>'; $sHtml = '<div class="pagination_objcount">'.Dict::Format('UI:Pagination:HeaderSelection', '<span id="total">'.$this->iNbObjects.'</span>', '<span class="selectedCount">0</span>').'</div>';
} else { }
else
{
$sHtml = '<div class="pagination_objcount">'.Dict::Format('UI:Pagination:HeaderNoSelection', '<span id="total">'.$this->iNbObjects.'</span>').'</div>'; $sHtml = '<div class="pagination_objcount">'.Dict::Format('UI:Pagination:HeaderNoSelection', '<span id="total">'.$this->iNbObjects.'</span>').'</div>';
} }
return $sHtml; return $sHtml;
} }
/** /**
@@ -247,19 +267,26 @@ class DataTable
protected function GetPager(WebPage $oPage, $iPageSize, $iDefaultPageSize, $iPageIndex) protected function GetPager(WebPage $oPage, $iPageSize, $iDefaultPageSize, $iPageIndex)
{ {
$sHtml = ''; $sHtml = '';
if ($iPageSize < 1) { // Display all if ($iPageSize < 1) // Display all
{
$sPagerStyle = 'style="display:none"'; // no limit: display the full table, so hide the "pager" UI $sPagerStyle = 'style="display:none"'; // no limit: display the full table, so hide the "pager" UI
// WARNING: mPDF does not take the "display" style into account // WARNING: mPDF does not take the "display" style into account
// when applied to a <td> or a <table> tag, so make sure you apply this to a div // when applied to a <td> or a <table> tag, so make sure you apply this to a div
} else { }
else
{
$sPagerStyle = ''; $sPagerStyle = '';
} }
$sCombo = '<select class="pagesize">'; $sCombo = '<select class="pagesize">';
if ($iPageSize < 1) { if($iPageSize < 1)
{
$sCombo .= "<option selected=\"selected\" value=\"-1\">".Dict::S('UI:Pagination:All')."</option>"; $sCombo .= "<option selected=\"selected\" value=\"-1\">".Dict::S('UI:Pagination:All')."</option>";
} else { }
for ($iPage = 1; $iPage < 5; $iPage++) { else
{
for($iPage = 1; $iPage < 5; $iPage++)
{
$iNbItems = $iPage * $iDefaultPageSize; $iNbItems = $iPage * $iDefaultPageSize;
$sSelected = ($iNbItems == $iPageSize) ? 'selected="selected"' : ''; $sSelected = ($iNbItems == $iPageSize) ? 'selected="selected"' : '';
$sCombo .= "<option $sSelected value=\"$iNbItems\">$iNbItems</option>"; $sCombo .= "<option $sSelected value=\"$iNbItems\">$iNbItems</option>";
@@ -268,25 +295,31 @@ class DataTable
} }
$sCombo .= '</select>'; $sCombo .= '</select>';
$sPages = Dict::S('UI:Pagination:PagesLabel'); $sPages = Dict::S('UI:Pagination:PagesLabel');
$sPageSizeCombo = Dict::Format('UI:Pagination:PageSize', $sCombo); $sPageSizeCombo = Dict::Format('UI:Pagination:PageSize', $sCombo);
$iNbPages = ($iPageSize < 1) ? 1 : ceil($this->iNbObjects / $iPageSize); $iNbPages = ($iPageSize < 1) ? 1 : ceil($this->iNbObjects / $iPageSize);
if ($iNbPages == 1) { if ($iNbPages == 1)
{
// No need to display the pager // No need to display the pager
$sPagerStyle = 'style="display:none"'; $sPagerStyle = 'style="display:none"';
} }
$aPagesToDisplay = []; $aPagesToDisplay = array();
for ($idx = 0; $idx <= min(4, $iNbPages - 1); $idx++) { for($idx = 0; $idx <= min(4, $iNbPages-1); $idx++)
if ($idx == 0) { {
if ($idx == 0)
{
$aPagesToDisplay[$idx] = '<span page="0" class="curr_page">1</span>'; $aPagesToDisplay[$idx] = '<span page="0" class="curr_page">1</span>';
} else { }
$aPagesToDisplay[$idx] = "<span id=\"gotopage_$idx\" class=\"gotopage\" page=\"$idx\">".(1 + $idx)."</span>"; else
{
$aPagesToDisplay[$idx] = "<span id=\"gotopage_$idx\" class=\"gotopage\" page=\"$idx\">".(1+$idx)."</span>";
} }
} }
$iLastPageIdx = $iNbPages - 1; $iLastPageIdx = $iNbPages - 1;
if (!isset($aPagesToDisplay[$iLastPageIdx])) { if (!isset($aPagesToDisplay[$iLastPageIdx]))
{
unset($aPagesToDisplay[$idx - 1]); // remove the last page added to make room for the very last page unset($aPagesToDisplay[$idx - 1]); // remove the last page added to make room for the very last page
$aPagesToDisplay[$iLastPageIdx] = "<span id=\"gotopage_$iLastPageIdx\" class=\"gotopage\" page=\"$iLastPageIdx\">... $iNbPages</span>"; $aPagesToDisplay[$iLastPageIdx] = "<span id=\"gotopage_$iLastPageIdx\" class=\"gotopage\" page=\"$iLastPageIdx\">... $iNbPages</span>";
} }
@@ -353,19 +386,22 @@ EOF;
*/ */
protected function GetToolkitMenu(WebPage $oPage, $aExtraParams) protected function GetToolkitMenu(WebPage $oPage, $aExtraParams)
{ {
if (!$oPage->IsPrintableVersion()) { if (!$oPage->IsPrintableVersion())
{
$sMenuTitle = Dict::S('UI:ConfigureThisList'); $sMenuTitle = Dict::S('UI:ConfigureThisList');
$sHtml = '<div class="itop_popup toolkit_menu" id="tk_'.$this->iListId.'"><ul><li aria-label="'.Dict::S('UI:Menu:Toolkit').'"><i class="fas fa-tools"></i><i class="fas fa-caret-down"></i><ul>'; $sHtml = '<div class="itop_popup toolkit_menu" id="tk_'.$this->iListId.'"><ul><li aria-label="'.Dict::S('UI:Menu:Toolkit').'"><i class="fas fa-tools"></i><i class="fas fa-caret-down"></i><ul>';
$oMenuItem1 = new JSPopupMenuItem('iTop::ConfigureList', $sMenuTitle, "$('#datatable_dlg_".$this->iListId."').dialog('open');"); $oMenuItem1 = new JSPopupMenuItem('iTop::ConfigureList', $sMenuTitle, "$('#datatable_dlg_".$this->iListId."').dialog('open');");
$aActions = [ $aActions = array(
$oMenuItem1->GetUID() => $oMenuItem1->GetMenuItem(), $oMenuItem1->GetUID() => $oMenuItem1->GetMenuItem(),
]; );
$this->oSet->Rewind(); $this->oSet->Rewind();
utils::GetPopupMenuItems($oPage, iPopupMenuExtension::MENU_OBJLIST_TOOLKIT, $this->oSet, $aActions, $this->sTableId, $this->iListId); utils::GetPopupMenuItems($oPage, iPopupMenuExtension::MENU_OBJLIST_TOOLKIT, $this->oSet, $aActions, $this->sTableId, $this->iListId);
$this->oSet->Rewind(); $this->oSet->Rewind();
$sHtml .= $oPage->RenderPopupMenuItems($aActions); $sHtml .= $oPage->RenderPopupMenuItems($aActions);
} else { }
else
{
$sHtml = ''; $sHtml = '';
} }
return $sHtml; return $sHtml;
@@ -386,10 +422,10 @@ EOF;
$sChecked = ($this->bUseCustomSettings) ? '' : 'checked'; $sChecked = ($this->bUseCustomSettings) ? '' : 'checked';
$sHtml .= "<p><input id=\"dtbl_dlg_settings_{$this->iListId}\" type=\"radio\" name=\"settings\" $sChecked value=\"defaults\"><label for=\"dtbl_dlg_settings_{$this->iListId}\">&nbsp;".Dict::S('UI:UseDefaultSettings').'</label></p>'; $sHtml .= "<p><input id=\"dtbl_dlg_settings_{$this->iListId}\" type=\"radio\" name=\"settings\" $sChecked value=\"defaults\"><label for=\"dtbl_dlg_settings_{$this->iListId}\">&nbsp;".Dict::S('UI:UseDefaultSettings').'</label></p>';
$sHtml .= "<fieldset>"; $sHtml .= "<fieldset>";
$sChecked = ($this->bUseCustomSettings) ? 'checked' : ''; $sChecked = ($this->bUseCustomSettings) ? 'checked': '';
$sHtml .= "<legend class=\"transparent\"><input id=\"dtbl_dlg_specific_{$this->iListId}\" type=\"radio\" class=\"specific_settings\" name=\"settings\" $sChecked value=\"specific\"><label for=\"dtbl_dlg_specific_{$this->iListId}\">&nbsp;".Dict::S('UI:UseSpecificSettings')."</label></legend>"; $sHtml .= "<legend class=\"transparent\"><input id=\"dtbl_dlg_specific_{$this->iListId}\" type=\"radio\" class=\"specific_settings\" name=\"settings\" $sChecked value=\"specific\"><label for=\"dtbl_dlg_specific_{$this->iListId}\">&nbsp;".Dict::S('UI:UseSpecificSettings')."</label></legend>";
$sHtml .= Dict::S('UI:ColumnsAndSortOrder').'<br/><ul class="sortable_field_list" id="sfl_'.$this->iListId.'"></ul>'; $sHtml .= Dict::S('UI:ColumnsAndSortOrder').'<br/><ul class="sortable_field_list" id="sfl_'.$this->iListId.'"></ul>';
$sHtml .= '<p>'.Dict::Format('UI:Display_X_ItemsPerPage', '<input type="text" size="4" name="page_size" value="'.$iDefaultPageSize.'">').'</p>'; $sHtml .= '<p>'.Dict::Format('UI:Display_X_ItemsPerPage', '<input type="text" size="4" name="page_size" value="'.$iDefaultPageSize.'">').'</p>';
$sHtml .= "</fieldset>"; $sHtml .= "</fieldset>";
$sHtml .= "<fieldset>"; $sHtml .= "<fieldset>";
@@ -408,7 +444,7 @@ EOF;
$sHtml .= '</td></tr></table>'; $sHtml .= '</td></tr></table>';
$sHtml .= "</form>"; $sHtml .= "</form>";
$sHtml .= "</div>"; $sHtml .= "</div>";
$sDlgTitle = addslashes(Dict::S('UI:ListConfigurationTitle')); $sDlgTitle = addslashes(Dict::S('UI:ListConfigurationTitle'));
$oPage->add_ready_script("$('#datatable_dlg_{$this->iListId}').dialog({autoOpen: false, title: '$sDlgTitle', width: 500, close: function() { $('#{$this->sDatatableContainerId}').datatable('onDlgCancel'); } });"); $oPage->add_ready_script("$('#datatable_dlg_{$this->iListId}').dialog({autoOpen: false, title: '$sDlgTitle', width: 500, close: function() { $('#{$this->sDatatableContainerId}').datatable('onDlgCancel'); } });");
@@ -422,7 +458,7 @@ EOF;
*/ */
public function GetAsHash($oSetting) public function GetAsHash($oSetting)
{ {
$aSettings = ['iDefaultPageSize' => $oSetting->iDefaultPageSize, 'oColumns' => $oSetting->aColumns]; $aSettings = array('iDefaultPageSize' => $oSetting->iDefaultPageSize, 'oColumns' => $oSetting->aColumns);
return $aSettings; return $aSettings;
} }
@@ -438,46 +474,55 @@ EOF;
*/ */
protected function GetHTMLTableConfig($aColumns, $sSelectMode, $bViewLink) protected function GetHTMLTableConfig($aColumns, $sSelectMode, $bViewLink)
{ {
$aAttribs = []; $aAttribs = array();
if ($sSelectMode == 'multiple') { if ($sSelectMode == 'multiple')
$aAttribs['form::select'] = [ {
$aAttribs['form::select'] = array(
'label' => "<input type=\"checkbox\" onClick=\"CheckAll('.selectList{$this->iListId}:not(:disabled)', this.checked);\" class=\"checkAll\"></input>", 'label' => "<input type=\"checkbox\" onClick=\"CheckAll('.selectList{$this->iListId}:not(:disabled)', this.checked);\" class=\"checkAll\"></input>",
'description' => Dict::S('UI:SelectAllToggle+'), 'description' => Dict::S('UI:SelectAllToggle+'),
'metadata' => [], 'metadata' => array(),
]; );
} elseif ($sSelectMode == 'single') { }
$aAttribs['form::select'] = ['label' => '', 'description' => '', 'metadata' => []]; else if ($sSelectMode == 'single')
{
$aAttribs['form::select'] = array('label' => '', 'description' => '', 'metadata' => array());
} }
foreach ($this->aClassAliases as $sAlias => $sClassName) { foreach($this->aClassAliases as $sAlias => $sClassName)
foreach ($aColumns[$sAlias] as $sAttCode => $aData) { {
if ($aData['checked']) { foreach($aColumns[$sAlias] as $sAttCode => $aData)
if ($sAttCode == '_key_') { {
if ($aData['checked'])
{
if ($sAttCode == '_key_')
{
$sAttLabel = MetaModel::GetName($sClassName); $sAttLabel = MetaModel::GetName($sClassName);
$aAttribs['key_'.$sAlias] = [ $aAttribs['key_'.$sAlias] = array(
'label' => $sAttLabel, 'label' => $sAttLabel,
'description' => '', 'description' => '',
'metadata' => [ 'metadata' => array(
'object_class' => $sClassName, 'object_class' => $sClassName,
'attribute_label' => $sAttLabel, 'attribute_label' => $sAttLabel,
], ),
]; );
} else { }
else
{
$oAttDef = MetaModel::GetAttributeDef($sClassName, $sAttCode); $oAttDef = MetaModel::GetAttributeDef($sClassName, $sAttCode);
$sAttDefClass = get_class($oAttDef); $sAttDefClass = get_class($oAttDef);
$sAttLabel = MetaModel::GetLabel($sClassName, $sAttCode); $sAttLabel = MetaModel::GetLabel($sClassName, $sAttCode);
$aAttribs[$sAttCode.'_'.$sAlias] = [ $aAttribs[$sAttCode.'_'.$sAlias] = array(
'label' => $sAttLabel, 'label' => $sAttLabel,
'description' => $oAttDef->GetOrderByHint(), 'description' => $oAttDef->GetOrderByHint(),
'metadata' => [ 'metadata' => array(
'object_class' => $sClassName, 'object_class' => $sClassName,
'attribute_code' => $sAttCode, 'attribute_code' => $sAttCode,
'attribute_type' => $sAttDefClass, 'attribute_type' => $sAttDefClass,
'attribute_label' => $sAttLabel, 'attribute_label' => $sAttLabel,
], ),
]; );
} }
} }
} }
@@ -485,6 +530,7 @@ EOF;
return $aAttribs; return $aAttribs;
} }
/** /**
* @param $aColumns * @param $aColumns
* @param $sSelectMode * @param $sSelectMode
@@ -503,74 +549,104 @@ EOF;
protected function GetHTMLTableValues($aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams) protected function GetHTMLTableValues($aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams)
{ {
$bLocalize = true; $bLocalize = true;
if (isset($aExtraParams['localize_values'])) { if (isset($aExtraParams['localize_values']))
{
$bLocalize = (bool) $aExtraParams['localize_values']; $bLocalize = (bool) $aExtraParams['localize_values'];
} }
$aValues = []; $aValues = array();
$aAttDefsCache = []; $aAttDefsCache = array();
$this->oSet->Seek(0); $this->oSet->Seek(0);
$iMaxObjects = $iPageSize; $iMaxObjects = $iPageSize;
while (($aObjects = $this->oSet->FetchAssoc()) && ($iMaxObjects != 0)) { while (($aObjects = $this->oSet->FetchAssoc()) && ($iMaxObjects != 0))
{
$bFirstObject = true; $bFirstObject = true;
$aRow = []; $aRow = array();
foreach ($this->aClassAliases as $sAlias => $sClassName) { foreach($this->aClassAliases as $sAlias => $sClassName)
if (is_object($aObjects[$sAlias])) { {
if (is_object($aObjects[$sAlias]))
{
$sHilightClass = MetaModel::GetHilightClass($sClassName, $aObjects[$sAlias]); $sHilightClass = MetaModel::GetHilightClass($sClassName, $aObjects[$sAlias]);
if ($sHilightClass != '') { if ($sHilightClass != '')
$aRow['@class'] = $sHilightClass; {
$aRow['@class'] = $sHilightClass;
} }
if ((($sSelectMode == 'single') || ($sSelectMode == 'multiple')) && $bFirstObject) { if ((($sSelectMode == 'single') || ($sSelectMode == 'multiple')) && $bFirstObject)
if (array_key_exists('selection_enabled', $aExtraParams) && isset($aExtraParams['selection_enabled'][$aObjects[$sAlias]->GetKey()])) { {
if (array_key_exists('selection_enabled', $aExtraParams) && isset($aExtraParams['selection_enabled'][$aObjects[$sAlias]->GetKey()]))
{
$sDisabled = ($aExtraParams['selection_enabled'][$aObjects[$sAlias]->GetKey()]) ? '' : ' disabled="disabled"'; $sDisabled = ($aExtraParams['selection_enabled'][$aObjects[$sAlias]->GetKey()]) ? '' : ' disabled="disabled"';
} else { }
else
{
$sDisabled = ''; $sDisabled = '';
} }
if ($sSelectMode == 'single') { if ($sSelectMode == 'single')
{
$aRow['form::select'] = "<input type=\"radio\" $sDisabled class=\"selectList{$this->iListId}\" name=\"selectObject\" value=\"".$aObjects[$sAlias]->GetKey()."\"></input>"; $aRow['form::select'] = "<input type=\"radio\" $sDisabled class=\"selectList{$this->iListId}\" name=\"selectObject\" value=\"".$aObjects[$sAlias]->GetKey()."\"></input>";
} else { }
else
{
$aRow['form::select'] = "<input type=\"checkbox\" $sDisabled class=\"selectList{$this->iListId}\" name=\"selectObject[]\" value=\"".$aObjects[$sAlias]->GetKey()."\"></input>"; $aRow['form::select'] = "<input type=\"checkbox\" $sDisabled class=\"selectList{$this->iListId}\" name=\"selectObject[]\" value=\"".$aObjects[$sAlias]->GetKey()."\"></input>";
} }
} }
foreach ($aColumns[$sAlias] as $sAttCode => $aData) { foreach($aColumns[$sAlias] as $sAttCode => $aData)
if ($aData['checked']) { {
if ($sAttCode == '_key_') { if ($aData['checked'])
$aRow['key_'.$sAlias] = [ {
if ($sAttCode == '_key_')
{
$aRow['key_'.$sAlias] = array(
'value_raw' => $aObjects[$sAlias]->GetKey(), 'value_raw' => $aObjects[$sAlias]->GetKey(),
'value_html' => $aObjects[$sAlias]->GetHyperLink(), 'value_html' => $aObjects[$sAlias]->GetHyperLink(),
]; );
} else { }
else
{
// Prepare att. def. classes cache to avoid retrieving AttDef for each row // Prepare att. def. classes cache to avoid retrieving AttDef for each row
if (!isset($aAttDefsCache[$sClassName][$sAttCode])) { if(!isset($aAttDefsCache[$sClassName][$sAttCode]))
{
$aAttDefClassesCache[$sClassName][$sAttCode] = get_class(MetaModel::GetAttributeDef($sClassName, $sAttCode)); $aAttDefClassesCache[$sClassName][$sAttCode] = get_class(MetaModel::GetAttributeDef($sClassName, $sAttCode));
} }
// Only retrieve raw (stored) value for simple fields // Only retrieve raw (stored) value for simple fields
$bExcludeRawValue = false; $bExcludeRawValue = false;
foreach (cmdbAbstractObject::GetAttDefClassesToExcludeFromMarkupMetadataRawValue() as $sAttDefClassToExclude) { foreach (cmdbAbstractObject::GetAttDefClassesToExcludeFromMarkupMetadataRawValue() as $sAttDefClassToExclude)
if (is_a($aAttDefClassesCache[$sClassName][$sAttCode], $sAttDefClassToExclude, true)) { {
if (is_a($aAttDefClassesCache[$sClassName][$sAttCode], $sAttDefClassToExclude, true))
{
$bExcludeRawValue = true; $bExcludeRawValue = true;
break; break;
} }
} }
if ($bExcludeRawValue) { if($bExcludeRawValue)
{
$aRow[$sAttCode.'_'.$sAlias] = $aObjects[$sAlias]->GetAsHTML($sAttCode, $bLocalize); $aRow[$sAttCode.'_'.$sAlias] = $aObjects[$sAlias]->GetAsHTML($sAttCode, $bLocalize);
} else { }
$aRow[$sAttCode.'_'.$sAlias] = [ else
{
$aRow[$sAttCode.'_'.$sAlias] = array(
'value_raw' => $aObjects[$sAlias]->Get($sAttCode), 'value_raw' => $aObjects[$sAlias]->Get($sAttCode),
'value_html' => $aObjects[$sAlias]->GetAsHTML($sAttCode, $bLocalize), 'value_html' => $aObjects[$sAlias]->GetAsHTML($sAttCode, $bLocalize),
]; );
} }
} }
} }
} }
} else { }
foreach ($aColumns[$sAlias] as $sAttCode => $aData) { else
if ($aData['checked']) { {
if ($sAttCode == '_key_') { foreach($aColumns[$sAlias] as $sAttCode => $aData)
{
if ($aData['checked'])
{
if ($sAttCode == '_key_')
{
$aRow['key_'.$sAlias] = ''; $aRow['key_'.$sAlias] = '';
} else { }
else
{
$aRow[$sAttCode.'_'.$sAlias] = ''; $aRow[$sAttCode.'_'.$sAlias] = '';
} }
} }
@@ -605,7 +681,8 @@ EOF;
public function GetHTMLTable(WebPage $oPage, $aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams) public function GetHTMLTable(WebPage $oPage, $aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams)
{ {
$iNbPages = ($iPageSize < 1) ? 1 : ceil($this->iNbObjects / $iPageSize); $iNbPages = ($iPageSize < 1) ? 1 : ceil($this->iNbObjects / $iPageSize);
if ($iPageSize < 1) { if ($iPageSize < 1)
{
$iPageSize = -1; // convention: no pagination $iPageSize = -1; // convention: no pagination
} }
$aAttribs = $this->GetHTMLTableConfig($aColumns, $sSelectMode, $bViewLink); $aAttribs = $this->GetHTMLTableConfig($aColumns, $sSelectMode, $bViewLink);
@@ -614,7 +691,8 @@ EOF;
$sHtml = '<table class="listContainer object-list">'; $sHtml = '<table class="listContainer object-list">';
foreach ($this->oSet->GetFilter()->GetInternalParams() as $sName => $sValue) { foreach($this->oSet->GetFilter()->GetInternalParams() as $sName => $sValue)
{
$aExtraParams['query_params'][$sName] = $sValue; $aExtraParams['query_params'][$sName] = $sValue;
} }
$aExtraParams['show_obsolete_data'] = $this->bShowObsoleteData; $aExtraParams['show_obsolete_data'] = $this->bShowObsoleteData;
@@ -629,16 +707,20 @@ EOF;
$sExtraParams = addslashes(str_replace('"', "'", json_encode(array_merge($aExtraParams, $aArgs)))); // JSON encode, change the style of the quotes and escape them $sExtraParams = addslashes(str_replace('"', "'", json_encode(array_merge($aExtraParams, $aArgs)))); // JSON encode, change the style of the quotes and escape them
$sSelectModeJS = ''; $sSelectModeJS = '';
$sHeaders = ''; $sHeaders = '';
if (($sSelectMode == 'single') || ($sSelectMode == 'multiple')) { if (($sSelectMode == 'single') || ($sSelectMode == 'multiple'))
{
$sSelectModeJS = $sSelectMode; $sSelectModeJS = $sSelectMode;
$sHeaders = 'headers: { 0: {sorter: false}},'; $sHeaders = 'headers: { 0: {sorter: false}},';
} }
$sDisplayKey = ($bViewLink) ? 'true' : 'false'; $sDisplayKey = ($bViewLink) ? 'true' : 'false';
// Protect against duplicate elements in the Zlist // Protect against duplicate elements in the Zlist
$aUniqueOrderedList = []; $aUniqueOrderedList = array();
foreach ($this->aClassAliases as $sAlias => $sClassName) { foreach($this->aClassAliases as $sAlias => $sClassName)
foreach ($aColumns[$sAlias] as $sAttCode => $aData) { {
if ($aData['checked']) { foreach($aColumns[$sAlias] as $sAttCode => $aData)
{
if ($aData['checked'])
{
$aUniqueOrderedList[$sAttCode] = true; $aUniqueOrderedList[$sAttCode] = true;
} }
} }
@@ -650,32 +732,41 @@ EOF;
$this->oSet->ApplyParameters(); $this->oSet->ApplyParameters();
// Display the actual sort order of the table // Display the actual sort order of the table
$aRealSortOrder = $this->oSet->GetRealSortOrder(); $aRealSortOrder = $this->oSet->GetRealSortOrder();
$aDefaultSort = []; $aDefaultSort = array();
$iColOffset = 0; $iColOffset = 0;
if (($sSelectMode == 'single') || ($sSelectMode == 'multiple')) { if (($sSelectMode == 'single') || ($sSelectMode == 'multiple'))
{
$iColOffset += 1; $iColOffset += 1;
} }
if ($bViewLink) { if ($bViewLink)
// $iColOffset += 1; {
// $iColOffset += 1;
} }
foreach ($aRealSortOrder as $sColCode => $bAscending) { foreach($aRealSortOrder as $sColCode => $bAscending)
{
$iPos = array_search($sColCode, $aUniqueOrderedList); $iPos = array_search($sColCode, $aUniqueOrderedList);
if ($iPos !== false) { if ($iPos !== false)
$aDefaultSort[] = "[".($iColOffset + $iPos).",".($bAscending ? '0' : '1')."]"; {
} elseif (($iPos = array_search(preg_replace('/_friendlyname$/', '', $sColCode), $aUniqueOrderedList)) !== false) { $aDefaultSort[] = "[".($iColOffset+$iPos).",".($bAscending ? '0' : '1')."]";
}
else if (($iPos = array_search(preg_replace('/_friendlyname$/', '', $sColCode), $aUniqueOrderedList)) !== false)
{
// if sorted on the friendly name of an external key, then consider it sorted on the column that shows the links // if sorted on the friendly name of an external key, then consider it sorted on the column that shows the links
$aDefaultSort[] = "[".($iColOffset + $iPos).",".($bAscending ? '0' : '1')."]"; $aDefaultSort[] = "[".($iColOffset+$iPos).",".($bAscending ? '0' : '1')."]";
} elseif ($sColCode == 'friendlyname' && $bViewLink) { }
else if($sColCode == 'friendlyname' && $bViewLink)
{
$aDefaultSort[] = "[".($iColOffset).",".($bAscending ? '0' : '1')."]"; $aDefaultSort[] = "[".($iColOffset).",".($bAscending ? '0' : '1')."]";
} }
} }
$sFakeSortList = ''; $sFakeSortList = '';
if (count($aDefaultSort) > 0) { if (count($aDefaultSort) > 0)
{
$sFakeSortList = '['.implode(',', $aDefaultSort).']'; $sFakeSortList = '['.implode(',', $aDefaultSort).']';
} }
$sOQL = addslashes($this->oSet->GetFilter()->serialize()); $sOQL = addslashes($this->oSet->GetFilter()->serialize());
$oPage->add_ready_script( $oPage->add_ready_script(
<<<JS <<<JS
var oTable = $('#{$this->sDatatableContainerId} table.listResults'); var oTable = $('#{$this->sDatatableContainerId} table.listResults');
oTable.tableHover(); oTable.tableHover();
oTable oTable
@@ -693,8 +784,9 @@ oTable
class_aliases: $sJSClassAliases $sCssCount class_aliases: $sJSClassAliases $sCssCount
}); });
JS JS
); );
if ($sFakeSortList != '') { if ($sFakeSortList != '')
{
$oPage->add_ready_script("oTable.trigger(\"fakesorton\", [$sFakeSortList]);"); $oPage->add_ready_script("oTable.trigger(\"fakesorton\", [$sFakeSortList]);");
} }
return $sHtml; return $sHtml;
@@ -711,9 +803,12 @@ JS
$iPageIndex = 0; $iPageIndex = 0;
$sHtml = $this->GetPager($oPage, $iPageSize, $iDefaultPageSize, $iPageIndex); $sHtml = $this->GetPager($oPage, $iPageSize, $iDefaultPageSize, $iPageIndex);
$oPage->add_ready_script("$('#pager{$this->iListId}').html('".json_encode($sHtml)."');"); $oPage->add_ready_script("$('#pager{$this->iListId}').html('".json_encode($sHtml)."');");
if ($iDefaultPageSize < 1) { if ($iDefaultPageSize < 1)
{
$oPage->add_ready_script("$('#pager{$this->iListId}').parent().hide()"); $oPage->add_ready_script("$('#pager{$this->iListId}').parent().hide()");
} else { }
else
{
$oPage->add_ready_script("$('#pager{$this->iListId}').parent().show()"); $oPage->add_ready_script("$('#pager{$this->iListId}').parent().show()");
} }
} }
@@ -770,15 +865,16 @@ class PrintableDataTable extends DataTable
public function GetHTMLTable(WebPage $oPage, $aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams) public function GetHTMLTable(WebPage $oPage, $aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams)
{ {
$iNbPages = ($iPageSize < 1) ? 1 : ceil($this->iNbObjects / $iPageSize); $iNbPages = ($iPageSize < 1) ? 1 : ceil($this->iNbObjects / $iPageSize);
if ($iPageSize < 1) { if ($iPageSize < 1)
{
$iPageSize = -1; // convention: no pagination $iPageSize = -1; // convention: no pagination
} }
$aAttribs = $this->GetHTMLTableConfig($aColumns, $sSelectMode, $bViewLink); $aAttribs = $this->GetHTMLTableConfig($aColumns, $sSelectMode, $bViewLink);
$aValues = $this->GetHTMLTableValues($aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams); $aValues = $this->GetHTMLTableValues($aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams);
$sHtml = $oPage->GetTable($aAttribs, $aValues); $sHtml = $oPage->GetTable($aAttribs, $aValues);
return $sHtml; return $sHtml;
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -1,9 +1,8 @@
<?php <?php
/** /**
* @deprecated 3.0.0 will be removed in 3.1.0 - moved to sources/Application/WebPage/ErrorPage.php, now loadable using autoloader * @deprecated 3.0.0 will be removed in 3.1.0 - moved to sources/Application/WebPage/ErrorPage.php, now loadable using autoloader
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
*/ */
DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/Application/WebPage/ErrorPage.php, now loadable using autoloader'); DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/Application/WebPage/ErrorPage.php, now loadable using autoloader');

View File

@@ -19,67 +19,73 @@ class ExcelExporter
protected $iPosition; protected $iPosition;
protected $sOutputFilePath; protected $sOutputFilePath;
protected $bAdvancedMode; protected $bAdvancedMode;
public function __construct($sToken = null) public function __construct($sToken = null)
{ {
$this->aStatistics = [ $this->aStatistics = array(
'objects_count' => 0, 'objects_count' => 0,
'total_duration' => 0, 'total_duration' => 0,
'data_retrieval_duration' => 0, 'data_retrieval_duration' => 0,
'excel_build_duration' => 0, 'excel_build_duration' => 0,
'excel_write_duration' => 0, 'excel_write_duration' => 0,
'peak_memory_usage' => 0, 'peak_memory_usage' => 0,
]; );
$this->fStartTime = microtime(true); $this->fStartTime = microtime(true);
$this->oSearch = null; $this->oSearch = null;
$this->sState = 'new'; $this->sState = 'new';
$this->aObjectsIDs = []; $this->aObjectsIDs = array();
$this->iPosition = 0; $this->iPosition = 0;
$this->aAuthorizedClasses = null; $this->aAuthorizedClasses = null;
$this->aTableHeaders = null; $this->aTableHeaders = null;
$this->sOutputFilePath = null; $this->sOutputFilePath = null;
$this->bAdvancedMode = false; $this->bAdvancedMode = false;
$this->CheckDataDir(); $this->CheckDataDir();
if ($sToken == null) { if ($sToken == null)
{
$this->sToken = $this->GetNewToken(); $this->sToken = $this->GetNewToken();
} else { }
else
{
$this->sToken = $sToken; $this->sToken = $sToken;
$this->ReloadState(); $this->ReloadState();
} }
} }
public function __destruct() public function __destruct()
{ {
if (($this->sState != 'done') && ($this->sState != 'error') && ($this->sToken != null)) { if (($this->sState != 'done') && ($this->sState != 'error') && ($this->sToken != null))
{
// Operation in progress, save the state // Operation in progress, save the state
$this->SaveState(); $this->SaveState();
} else { }
else
{
// Operation completed, cleanup the temp files // Operation completed, cleanup the temp files
@unlink($this->GetStateFile()); @unlink($this->GetStateFile());
@unlink($this->GetDataFile()); @unlink($this->GetDataFile());
} }
self::CleanupOldFiles(); self::CleanupOldFiles();
} }
public function SetChunkSize($iChunkSize) public function SetChunkSize($iChunkSize)
{ {
$this->iChunkSize = $iChunkSize; $this->iChunkSize = $iChunkSize;
} }
public function SetOutputFilePath($sDestFilePath) public function SetOutputFilePath($sDestFilePath)
{ {
$this->sOutputFilePath = $sDestFilePath; $this->sOutputFilePath = $sDestFilePath;
} }
public function SetAdvancedMode($bAdvanced) public function SetAdvancedMode($bAdvanced)
{ {
$this->bAdvancedMode = $bAdvanced; $this->bAdvancedMode = $bAdvanced;
} }
public function SaveState() public function SaveState()
{ {
$aState = [ $aState = array(
'state' => $this->sState, 'state' => $this->sState,
'statistics' => $this->aStatistics, 'statistics' => $this->aStatistics,
'filter' => $this->oSearch->serialize(), 'filter' => $this->oSearch->serialize(),
@@ -88,28 +94,31 @@ class ExcelExporter
'object_ids' => $this->aObjectsIDs, 'object_ids' => $this->aObjectsIDs,
'output_file_path' => $this->sOutputFilePath, 'output_file_path' => $this->sOutputFilePath,
'advanced_mode' => $this->bAdvancedMode, 'advanced_mode' => $this->bAdvancedMode,
]; );
file_put_contents($this->GetStateFile(), json_encode($aState)); file_put_contents($this->GetStateFile(), json_encode($aState));
return $this->sToken; return $this->sToken;
} }
public function ReloadState() public function ReloadState()
{ {
if ($this->sToken == null) { if ($this->sToken == null)
{
throw new Exception('ExcelExporter not initialized with a token, cannot reload state'); throw new Exception('ExcelExporter not initialized with a token, cannot reload state');
} }
if (!file_exists($this->GetStateFile())) { if (!file_exists($this->GetStateFile()))
{
throw new Exception("ExcelExporter: missing status file '".$this->GetStateFile()."', cannot reload state."); throw new Exception("ExcelExporter: missing status file '".$this->GetStateFile()."', cannot reload state.");
} }
$sJson = file_get_contents($this->GetStateFile()); $sJson = file_get_contents($this->GetStateFile());
$aState = json_decode($sJson, true); $aState = json_decode($sJson, true);
if ($aState === null) { if ($aState === null)
{
throw new Exception("ExcelExporter:corrupted status file '".$this->GetStateFile()."', not a JSON, cannot reload state."); throw new Exception("ExcelExporter:corrupted status file '".$this->GetStateFile()."', not a JSON, cannot reload state.");
} }
$this->sState = $aState['state']; $this->sState = $aState['state'];
$this->aStatistics = $aState['statistics']; $this->aStatistics = $aState['statistics'];
$this->oSearch = DBObjectSearch::unserialize($aState['filter']); $this->oSearch = DBObjectSearch::unserialize($aState['filter']);
@@ -119,183 +128,206 @@ class ExcelExporter
$this->sOutputFilePath = $aState['output_file_path']; $this->sOutputFilePath = $aState['output_file_path'];
$this->bAdvancedMode = $aState['advanced_mode']; $this->bAdvancedMode = $aState['advanced_mode'];
} }
public function SetObjectList($oSearch) public function SetObjectList($oSearch)
{ {
$this->oSearch = $oSearch; $this->oSearch = $oSearch;
} }
public function Run() public function Run()
{ {
$sCode = 'error'; $sCode = 'error';
$iPercentage = 100; $iPercentage = 100;
$sMessage = Dict::Format('ExcelExporter:ErrorUnexpected_State', $this->sState); $sMessage = Dict::Format('ExcelExporter:ErrorUnexpected_State', $this->sState);
$fTime = microtime(true); $fTime = microtime(true);
try { try
switch ($this->sState) { {
switch($this->sState)
{
case 'new': case 'new':
$oIDSet = new DBObjectSet($this->oSearch); $oIDSet = new DBObjectSet($this->oSearch);
$oIDSet->OptimizeColumnLoad(['id']); $oIDSet->OptimizeColumnLoad(array('id'));
$this->aObjectsIDs = []; $this->aObjectsIDs = array();
while ($oObj = $oIDSet->Fetch()) { while($oObj = $oIDSet->Fetch())
$this->aObjectsIDs[] = $oObj->GetKey(); {
} $this->aObjectsIDs[] = $oObj->GetKey();
$sCode = 'retrieving-data'; }
$iPercentage = 5; $sCode = 'retrieving-data';
$sMessage = Dict::S('ExcelExporter:RetrievingData'); $iPercentage = 5;
$this->iPosition = 0; $sMessage = Dict::S('ExcelExporter:RetrievingData');
$this->aStatistics['objects_count'] = count($this->aObjectsIDs); $this->iPosition = 0;
$this->aStatistics['data_retrieval_duration'] += microtime(true) - $fTime; $this->aStatistics['objects_count'] = count($this->aObjectsIDs);
$this->aStatistics['data_retrieval_duration'] += microtime(true) - $fTime;
// The first line of the file is the "headers" specifying the label and the type of each column
$this->GetFieldsList($oIDSet, $this->bAdvancedMode); // The first line of the file is the "headers" specifying the label and the type of each column
$sRow = json_encode($this->aTableHeaders); $this->GetFieldsList($oIDSet, $this->bAdvancedMode);
$hFile = @fopen($this->GetDataFile(), 'ab'); $sRow = json_encode($this->aTableHeaders);
if ($hFile === false) { $hFile = @fopen($this->GetDataFile(), 'ab');
throw new Exception('ExcelExporter: Failed to open temporary data file: "'.$this->GetDataFile().'" for writing.'); if ($hFile === false)
} {
fwrite($hFile, $sRow."\n"); throw new Exception('ExcelExporter: Failed to open temporary data file: "'.$this->GetDataFile().'" for writing.');
fclose($hFile); }
fwrite($hFile, $sRow."\n");
// Next state fclose($hFile);
$this->sState = 'retrieving-data';
break; // Next state
$this->sState = 'retrieving-data';
break;
case 'retrieving-data': case 'retrieving-data':
$oCurrentSearch = clone $this->oSearch; $oCurrentSearch = clone $this->oSearch;
$aIDs = array_slice($this->aObjectsIDs, $this->iPosition, $this->iChunkSize); $aIDs = array_slice($this->aObjectsIDs, $this->iPosition, $this->iChunkSize);
$oCurrentSearch->AddCondition('id', $aIDs, 'IN'); $oCurrentSearch->AddCondition('id', $aIDs, 'IN');
$hFile = @fopen($this->GetDataFile(), 'ab'); $hFile = @fopen($this->GetDataFile(), 'ab');
if ($hFile === false) { if ($hFile === false)
throw new Exception('ExcelExporter: Failed to open temporary data file: "'.$this->GetDataFile().'" for writing.'); {
} throw new Exception('ExcelExporter: Failed to open temporary data file: "'.$this->GetDataFile().'" for writing.');
$oSet = new DBObjectSet($oCurrentSearch); }
$this->GetFieldsList($oSet, $this->bAdvancedMode); $oSet = new DBObjectSet($oCurrentSearch);
while ($aObjects = $oSet->FetchAssoc()) { $this->GetFieldsList($oSet, $this->bAdvancedMode);
$aRow = []; while($aObjects = $oSet->FetchAssoc())
foreach ($this->aAuthorizedClasses as $sAlias => $sClassName) { {
$oObj = $aObjects[$sAlias]; $aRow = array();
if ($this->bAdvancedMode) { foreach($this->aAuthorizedClasses as $sAlias => $sClassName)
$aRow[] = $oObj->GetKey(); {
} $oObj = $aObjects[$sAlias];
foreach ($this->aFieldsList[$sAlias] as $sAttCodeEx => $oAttDef) { if ($this->bAdvancedMode)
$value = $oObj->Get($sAttCodeEx); {
if ($value instanceof ormCaseLog) { $aRow[] = $oObj->GetKey();
// Extract the case log as text and remove the "===" which make Excel think that the cell contains a formula the next time you edit it! }
$sExcelVal = trim(preg_replace('/========== ([^=]+) ============/', '********** $1 ************', $value->GetText())); foreach($this->aFieldsList[$sAlias] as $sAttCodeEx => $oAttDef)
} else { {
$sExcelVal = $oAttDef->GetEditValue($value, $oObj); $value = $oObj->Get($sAttCodeEx);
} if ($value instanceOf ormCaseLog)
$aRow[] = $sExcelVal; {
} // Extract the case log as text and remove the "===" which make Excel think that the cell contains a formula the next time you edit it!
$sExcelVal = trim(preg_replace('/========== ([^=]+) ============/', '********** $1 ************', $value->GetText()));
}
else
{
$sExcelVal = $oAttDef->GetEditValue($value, $oObj);
}
$aRow[] = $sExcelVal;
} }
$sRow = json_encode($aRow);
fwrite($hFile, $sRow."\n");
} }
fclose($hFile); $sRow = json_encode($aRow);
fwrite($hFile, $sRow."\n");
if (($this->iPosition + $this->iChunkSize) > count($this->aObjectsIDs)) { }
// Next state fclose($hFile);
$this->sState = 'building-excel';
$sCode = 'building-excel'; if (($this->iPosition + $this->iChunkSize) > count($this->aObjectsIDs))
$iPercentage = 80; {
$sMessage = Dict::S('ExcelExporter:BuildingExcelFile');
} else {
$sCode = 'retrieving-data';
$this->iPosition += $this->iChunkSize;
$iPercentage = 5 + round(75 * ($this->iPosition / count($this->aObjectsIDs)));
$sMessage = Dict::S('ExcelExporter:RetrievingData');
}
break;
case 'building-excel':
$hFile = @fopen($this->GetDataFile(), 'rb');
if ($hFile === false) {
throw new Exception('ExcelExporter: Failed to open temporary data file: "'.$this->GetDataFile().'" for reading.');
}
$sHeaders = fgets($hFile);
$aHeaders = json_decode($sHeaders, true);
$aData = [];
while ($sLine = fgets($hFile)) {
$aRow = json_decode($sLine);
$aData[] = $aRow;
}
fclose($hFile);
@unlink($this->GetDataFile());
$fStartExcel = microtime(true);
$writer = new XLSXWriter();
$writer->setAuthor(UserRights::GetUserFriendlyName());
$writer->writeSheet($aData, 'Sheet1', $aHeaders);
$fExcelTime = microtime(true) - $fStartExcel;
$this->aStatistics['excel_build_duration'] = $fExcelTime;
$fTime = microtime(true);
$writer->writeToFile($this->GetExcelFilePath());
$fExcelSaveTime = microtime(true) - $fTime;
$this->aStatistics['excel_write_duration'] = $fExcelSaveTime;
// Next state // Next state
$this->sState = 'done'; $this->sState = 'building-excel';
$sCode = 'done'; $sCode = 'building-excel';
$iPercentage = 100; $iPercentage = 80;
$sMessage = Dict::S('ExcelExporter:Done'); $sMessage = Dict::S('ExcelExporter:BuildingExcelFile');
break; }
else
{
$sCode = 'retrieving-data';
$this->iPosition += $this->iChunkSize;
$iPercentage = 5 + round(75 * ($this->iPosition / count($this->aObjectsIDs)));
$sMessage = Dict::S('ExcelExporter:RetrievingData');
}
break;
case 'building-excel':
$hFile = @fopen($this->GetDataFile(), 'rb');
if ($hFile === false)
{
throw new Exception('ExcelExporter: Failed to open temporary data file: "'.$this->GetDataFile().'" for reading.');
}
$sHeaders = fgets($hFile);
$aHeaders = json_decode($sHeaders, true);
$aData = array();
while($sLine = fgets($hFile))
{
$aRow = json_decode($sLine);
$aData[] = $aRow;
}
fclose($hFile);
@unlink($this->GetDataFile());
$fStartExcel = microtime(true);
$writer = new XLSXWriter();
$writer->setAuthor(UserRights::GetUserFriendlyName());
$writer->writeSheet($aData,'Sheet1', $aHeaders);
$fExcelTime = microtime(true) - $fStartExcel;
$this->aStatistics['excel_build_duration'] = $fExcelTime;
$fTime = microtime(true);
$writer->writeToFile($this->GetExcelFilePath());
$fExcelSaveTime = microtime(true) - $fTime;
$this->aStatistics['excel_write_duration'] = $fExcelSaveTime;
// Next state
$this->sState = 'done';
$sCode = 'done';
$iPercentage = 100;
$sMessage = Dict::S('ExcelExporter:Done');
break;
case 'done': case 'done':
$this->sState = 'done'; $this->sState = 'done';
$sCode = 'done'; $sCode = 'done';
$iPercentage = 100; $iPercentage = 100;
$sMessage = Dict::S('ExcelExporter:Done'); $sMessage = Dict::S('ExcelExporter:Done');
break; break;
} }
} catch (Exception $e) { }
catch(Exception $e)
{
$sCode = 'error'; $sCode = 'error';
$sMessage = $e->getMessage(); $sMessage = $e->getMessage();
} }
$this->aStatistics['total_duration'] += microtime(true) - $fTime; $this->aStatistics['total_duration'] += microtime(true) - $fTime;
$peak_memory = memory_get_peak_usage(true); $peak_memory = memory_get_peak_usage(true);
if ($peak_memory > $this->aStatistics['peak_memory_usage']) { if ($peak_memory > $this->aStatistics['peak_memory_usage'])
{
$this->aStatistics['peak_memory_usage'] = $peak_memory; $this->aStatistics['peak_memory_usage'] = $peak_memory;
} }
return [ return array(
'code' => $sCode, 'code' => $sCode,
'message' => $sMessage, 'message' => $sMessage,
'percentage' => $iPercentage, 'percentage' => $iPercentage,
]; );
} }
public function GetExcelFilePath() public function GetExcelFilePath()
{ {
if ($this->sOutputFilePath == null) { if ($this->sOutputFilePath == null)
{
return APPROOT.'data/bulk_export/'.$this->sToken.'.xlsx'; return APPROOT.'data/bulk_export/'.$this->sToken.'.xlsx';
} else { }
else
{
return $this->sOutputFilePath; return $this->sOutputFilePath;
} }
} }
public static function GetExcelFileFromToken($sToken) public static function GetExcelFileFromToken($sToken)
{ {
return @file_get_contents(APPROOT.'data/bulk_export/'.$sToken.'.xlsx'); return @file_get_contents(APPROOT.'data/bulk_export/'.$sToken.'.xlsx');
} }
public static function CleanupFromToken($sToken) public static function CleanupFromToken($sToken)
{ {
@unlink(APPROOT.'data/bulk_export/'.$sToken.'.status'); @unlink(APPROOT.'data/bulk_export/'.$sToken.'.status');
@unlink(APPROOT.'data/bulk_export/'.$sToken.'.data'); @unlink(APPROOT.'data/bulk_export/'.$sToken.'.data');
@unlink(APPROOT.'data/bulk_export/'.$sToken.'.xlsx'); @unlink(APPROOT.'data/bulk_export/'.$sToken.'.xlsx');
} }
public function Cleanup() public function Cleanup()
{ {
self::CleanupFromToken($this->sToken); self::CleanupFromToken($this->sToken);
} }
/** /**
* Delete all files in the data/bulk_export directory which are older than 1 day * Delete all files in the data/bulk_export directory which are older than 1 day
* unless a different delay is configured. * unless a different delay is configured.
@@ -304,12 +336,15 @@ class ExcelExporter
{ {
$aFiles = glob(APPROOT.'data/bulk_export/*.*'); $aFiles = glob(APPROOT.'data/bulk_export/*.*');
$iDelay = MetaModel::GetConfig()->Get('xlsx_exporter_cleanup_old_files_delay'); $iDelay = MetaModel::GetConfig()->Get('xlsx_exporter_cleanup_old_files_delay');
if ($iDelay > 0) { if($iDelay > 0)
foreach ($aFiles as $sFile) { {
foreach($aFiles as $sFile)
{
$iModificationTime = filemtime($sFile); $iModificationTime = filemtime($sFile);
if ($iModificationTime < (time() - $iDelay)) { if($iModificationTime < (time() - $iDelay))
{
// Temporary files older than one day are deleted // Temporary files older than one day are deleted
//echo "Supposed to delete: '".$sFile." (Unix Modification Time: $iModificationTime)'\n"; //echo "Supposed to delete: '".$sFile." (Unix Modification Time: $iModificationTime)'\n";
@unlink($sFile); @unlink($sFile);
@@ -317,155 +352,189 @@ class ExcelExporter
} }
} }
} }
public function DisplayStatistics(Page $oPage) public function DisplayStatistics(Page $oPage)
{ {
$aStats = [ $aStats = array(
'Number of objects exported' => $this->aStatistics['objects_count'], 'Number of objects exported' => $this->aStatistics['objects_count'],
'Total export duration' => sprintf('%.3f s', $this->aStatistics['total_duration']), 'Total export duration' => sprintf('%.3f s', $this->aStatistics['total_duration']),
'Data retrieval duration' => sprintf('%.3f s', $this->aStatistics['data_retrieval_duration']), 'Data retrieval duration' => sprintf('%.3f s', $this->aStatistics['data_retrieval_duration']),
'Excel build duration' => sprintf('%.3f s', $this->aStatistics['excel_build_duration']), 'Excel build duration' => sprintf('%.3f s', $this->aStatistics['excel_build_duration']),
'Excel write duration' => sprintf('%.3f s', $this->aStatistics['excel_write_duration']), 'Excel write duration' => sprintf('%.3f s', $this->aStatistics['excel_write_duration']),
'Peak memory usage' => self::HumanDisplay($this->aStatistics['peak_memory_usage']), 'Peak memory usage' => self::HumanDisplay($this->aStatistics['peak_memory_usage']),
]; );
if ($oPage instanceof CLIPage) { if ($oPage instanceof CLIPage)
{
$oPage->add($this->GetStatistics('text')); $oPage->add($this->GetStatistics('text'));
} else { }
else
{
$oPage->add($this->GetStatistics('html')); $oPage->add($this->GetStatistics('html'));
} }
} }
public function GetStatistics($sFormat = 'html') public function GetStatistics($sFormat = 'html')
{ {
$sStats = ''; $sStats = '';
$aStats = [ $aStats = array(
'Number of objects exported' => $this->aStatistics['objects_count'], 'Number of objects exported' => $this->aStatistics['objects_count'],
'Total export duration' => sprintf('%.3f s', $this->aStatistics['total_duration']), 'Total export duration' => sprintf('%.3f s', $this->aStatistics['total_duration']),
'Data retrieval duration' => sprintf('%.3f s', $this->aStatistics['data_retrieval_duration']), 'Data retrieval duration' => sprintf('%.3f s', $this->aStatistics['data_retrieval_duration']),
'Excel build duration' => sprintf('%.3f s', $this->aStatistics['excel_build_duration']), 'Excel build duration' => sprintf('%.3f s', $this->aStatistics['excel_build_duration']),
'Excel write duration' => sprintf('%.3f s', $this->aStatistics['excel_write_duration']), 'Excel write duration' => sprintf('%.3f s', $this->aStatistics['excel_write_duration']),
'Peak memory usage' => self::HumanDisplay($this->aStatistics['peak_memory_usage']), 'Peak memory usage' => self::HumanDisplay($this->aStatistics['peak_memory_usage']),
]; );
if ($sFormat == 'text') { if ($sFormat == 'text')
foreach ($aStats as $sLabel => $sValue) { {
foreach($aStats as $sLabel => $sValue)
{
$sStats .= "+------------------------------+----------+\n"; $sStats .= "+------------------------------+----------+\n";
$sStats .= sprintf("|%-30s|%10s|\n", $sLabel, $sValue); $sStats .= sprintf("|%-30s|%10s|\n", $sLabel, $sValue);
} }
$sStats .= "+------------------------------+----------+"; $sStats .= "+------------------------------+----------+";
} else { }
else
{
$sStats .= '<table><tbody>'; $sStats .= '<table><tbody>';
foreach ($aStats as $sLabel => $sValue) { foreach($aStats as $sLabel => $sValue)
{
$sStats .= "<tr><td>$sLabel</td><td>$sValue</td></tr>"; $sStats .= "<tr><td>$sLabel</td><td>$sValue</td></tr>";
} }
$sStats .= '</tbody></table>'; $sStats .= '</tbody></table>';
} }
return $sStats; return $sStats;
} }
public static function HumanDisplay($iSize) public static function HumanDisplay($iSize)
{ {
$aUnits = ['B','KB','MB','GB','TB','PB']; $aUnits = array('B','KB','MB','GB','TB','PB');
return @round($iSize / pow(1024, ($i = floor(log($iSize, 1024)))), 2).' '.$aUnits[$i]; return @round($iSize/pow(1024,($i=floor(log($iSize,1024)))),2).' '.$aUnits[$i];
} }
protected function CheckDataDir() protected function CheckDataDir()
{ {
if (!is_dir(APPROOT."data/bulk_export")) { if(!is_dir(APPROOT."data/bulk_export"))
{
@mkdir(APPROOT."data/bulk_export", 0777, true /* recursive */); @mkdir(APPROOT."data/bulk_export", 0777, true /* recursive */);
clearstatcache(); clearstatcache();
} }
if (!is_writable(APPROOT."data/bulk_export")) { if (!is_writable(APPROOT."data/bulk_export"))
{
throw new Exception('Data directory "'.APPROOT.'data/bulk_export" could not be written.'); throw new Exception('Data directory "'.APPROOT.'data/bulk_export" could not be written.');
} }
} }
protected function GetStateFile($sToken = null) protected function GetStateFile($sToken = null)
{ {
if ($sToken == null) { if ($sToken == null)
{
$sToken = $this->sToken; $sToken = $this->sToken;
} }
return APPROOT."data/bulk_export/$sToken.status"; return APPROOT."data/bulk_export/$sToken.status";
} }
protected function GetDataFile() protected function GetDataFile()
{ {
return APPROOT.'data/bulk_export/'.$this->sToken.'.data'; return APPROOT.'data/bulk_export/'.$this->sToken.'.data';
} }
protected function GetNewToken() protected function GetNewToken()
{ {
$iNum = rand(); $iNum = rand();
do { do
{
$iNum++; $iNum++;
$sToken = sprintf("%08x", $iNum); $sToken = sprintf("%08x", $iNum);
$sFileName = $this->GetStateFile($sToken); $sFileName = $this->GetStateFile($sToken);
$hFile = @fopen($sFileName, 'x'); $hFile = @fopen($sFileName, 'x');
} while ($hFile === false); }
while($hFile === false);
fclose($hFile); fclose($hFile);
return $sToken; return $sToken;
} }
protected function GetFieldsList($oSet, $bFieldsAdvanced = false, $bLocalize = true, $aFields = null) protected function GetFieldsList($oSet, $bFieldsAdvanced = false, $bLocalize = true, $aFields = null)
{ {
$this->aFieldsList = []; $this->aFieldsList = array();
$oAppContext = new ApplicationContext(); $oAppContext = new ApplicationContext();
$aClasses = $oSet->GetFilter()->GetSelectedClasses(); $aClasses = $oSet->GetFilter()->GetSelectedClasses();
$this->aAuthorizedClasses = []; $this->aAuthorizedClasses = array();
foreach ($aClasses as $sAlias => $sClassName) { foreach($aClasses as $sAlias => $sClassName)
if (UserRights::IsActionAllowed($sClassName, UR_ACTION_READ, $oSet) != UR_ALLOWED_NO) { {
if (UserRights::IsActionAllowed($sClassName, UR_ACTION_READ, $oSet) != UR_ALLOWED_NO)
{
$this->aAuthorizedClasses[$sAlias] = $sClassName; $this->aAuthorizedClasses[$sAlias] = $sClassName;
} }
} }
$aAttribs = []; $aAttribs = array();
$this->aTableHeaders = []; $this->aTableHeaders = array();
foreach ($this->aAuthorizedClasses as $sAlias => $sClassName) { foreach($this->aAuthorizedClasses as $sAlias => $sClassName)
$aList[$sAlias] = []; {
$aList[$sAlias] = array();
foreach (MetaModel::ListAttributeDefs($sClassName) as $sAttCode => $oAttDef) {
if (is_null($aFields) || (count($aFields) == 0)) { foreach(MetaModel::ListAttributeDefs($sClassName) as $sAttCode => $oAttDef)
{
if (is_null($aFields) || (count($aFields) == 0))
{
// Standard list of attributes (no link sets) // Standard list of attributes (no link sets)
if ($oAttDef->IsScalar() && ($oAttDef->IsWritable() || $oAttDef->IsExternalField())) { if ($oAttDef->IsScalar() && ($oAttDef->IsWritable() || $oAttDef->IsExternalField()))
{
$sAttCodeEx = $oAttDef->IsExternalField() ? $oAttDef->GetKeyAttCode().'->'.$oAttDef->GetExtAttCode() : $sAttCode; $sAttCodeEx = $oAttDef->IsExternalField() ? $oAttDef->GetKeyAttCode().'->'.$oAttDef->GetExtAttCode() : $sAttCode;
if ($oAttDef->IsExternalKey(EXTKEY_ABSOLUTE)) { if ($oAttDef->IsExternalKey(EXTKEY_ABSOLUTE))
if ($bFieldsAdvanced) { {
if ($bFieldsAdvanced)
{
$aList[$sAlias][$sAttCodeEx] = $oAttDef; $aList[$sAlias][$sAttCodeEx] = $oAttDef;
if ($oAttDef->IsExternalKey(EXTKEY_RELATIVE)) { if ($oAttDef->IsExternalKey(EXTKEY_RELATIVE))
$sRemoteClass = $oAttDef->GetTargetClass(); {
foreach (MetaModel::GetReconcKeys($sRemoteClass) as $sRemoteAttCode) { $sRemoteClass = $oAttDef->GetTargetClass();
foreach(MetaModel::GetReconcKeys($sRemoteClass) as $sRemoteAttCode)
{
$this->aFieldsList[$sAlias][$sAttCode.'->'.$sRemoteAttCode] = MetaModel::GetAttributeDef($sRemoteClass, $sRemoteAttCode); $this->aFieldsList[$sAlias][$sAttCode.'->'.$sRemoteAttCode] = MetaModel::GetAttributeDef($sRemoteClass, $sRemoteAttCode);
} }
} }
} }
} else { }
else
{
// Any other attribute // Any other attribute
$this->aFieldsList[$sAlias][$sAttCodeEx] = $oAttDef; $this->aFieldsList[$sAlias][$sAttCodeEx] = $oAttDef;
} }
} }
} else { }
else
{
// User defined list of attributes // User defined list of attributes
if (in_array($sAttCode, $aFields) || in_array($sAlias.'.'.$sAttCode, $aFields)) { if (in_array($sAttCode, $aFields) || in_array($sAlias.'.'.$sAttCode, $aFields))
{
$this->aFieldsList[$sAlias][$sAttCode] = $oAttDef; $this->aFieldsList[$sAlias][$sAttCode] = $oAttDef;
} }
} }
} }
if ($bFieldsAdvanced) { if ($bFieldsAdvanced)
{
$this->aTableHeaders['id'] = '0'; $this->aTableHeaders['id'] = '0';
} }
foreach ($this->aFieldsList[$sAlias] as $sAttCodeEx => $oAttDef) { foreach($this->aFieldsList[$sAlias] as $sAttCodeEx => $oAttDef)
{
$sLabel = $bLocalize ? MetaModel::GetLabel($sClassName, $sAttCodeEx, isset($aParams['showMandatoryFields'])) : $sAttCodeEx; $sLabel = $bLocalize ? MetaModel::GetLabel($sClassName, $sAttCodeEx, isset($aParams['showMandatoryFields'])) : $sAttCodeEx;
if ($oAttDef instanceof AttributeDateTime) { if($oAttDef instanceof AttributeDateTime)
{
$this->aTableHeaders[$sLabel] = 'datetime'; $this->aTableHeaders[$sLabel] = 'datetime';
} else { }
else
{
$this->aTableHeaders[$sLabel] = 'string'; $this->aTableHeaders[$sLabel] = 'string';
} }
} }
} }
} }
} }

View File

@@ -1,5 +1,4 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0

View File

@@ -1,5 +1,4 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0

View File

@@ -1,5 +1,4 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -7,4 +6,4 @@
class BulkChangeException extends CoreException class BulkChangeException extends CoreException
{ {
} }

View File

@@ -1,5 +1,4 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -7,4 +6,4 @@
class CSVParserException extends CoreException class CSVParserException extends CoreException
{ {
} }

View File

@@ -1,5 +1,4 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -7,4 +6,4 @@
class ConfigException extends CoreException class ConfigException extends CoreException
{ {
} }

View File

@@ -1,5 +1,4 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -64,20 +63,21 @@ class CoreCannotSaveObjectException extends CoreException
public function getTextMessage() public function getTextMessage()
{ {
$sTitle = Dict::S('UI:Error:SaveFailed'); $sTitle = Dict::S('UI:Error:SaveFailed');
$sContent = $sTitle; $sContent = utils::HtmlEntities($sTitle);
if (count($this->aIssues) == 1) { if (count($this->aIssues) == 1) {
$sIssue = reset($this->aIssues); $sIssue = reset($this->aIssues);
$sContent .= $sIssue; $sContent .= utils::HtmlEntities($sIssue);
} else { } else {
foreach ($this->aIssues as $sError) { foreach ($this->aIssues as $sError) {
$sContent .= " ".$sError.", "; $sContent .= " ".utils::HtmlEntities($sError).", ";
} }
} }
return $sContent; return $sContent;
} }
public function getIssues() public function getIssues()
{ {
return $this->aIssues; return $this->aIssues;

View File

@@ -1,5 +1,4 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -36,10 +35,10 @@ class CoreException extends Exception
} }
if (count($this->m_aContextData) > 0) { if (count($this->m_aContextData) > 0) {
$sMessage .= ": "; $sMessage .= ": ";
$aContextItems = []; $aContextItems = array();
foreach ($this->m_aContextData as $sKey => $value) { foreach ($this->m_aContextData as $sKey => $value) {
if (is_array($value)) { if (is_array($value)) {
$aPairs = []; $aPairs = array();
foreach ($value as $key => $val) { foreach ($value as $key => $val) {
if (is_array($val)) { if (is_array($val)) {
$aPairs[] = $key.'=>('.implode(', ', $val).')'; $aPairs[] = $key.'=>('.implode(', ', $val).')';
@@ -68,7 +67,7 @@ class CoreException extends Exception
public function getHtmlDesc($sHighlightHtmlBegin = '<b>', $sHighlightHtmlEnd = '</b>') public function getHtmlDesc($sHighlightHtmlBegin = '<b>', $sHighlightHtmlEnd = '</b>')
{ {
return utils::EscapeHtml($this->getMessage()); return $this->getMessage();
} }
/** /**
@@ -110,4 +109,4 @@ class CoreException extends Exception
{ {
return $this->m_aContextData; return $this->m_aContextData;
} }
} }

View File

@@ -1,5 +1,4 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -10,4 +9,5 @@
*/ */
class CorePortalInvalidActionRuleException extends CoreException class CorePortalInvalidActionRuleException extends CoreException
{ {
} }

View File

@@ -1,5 +1,4 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -15,4 +14,4 @@ class CoreTemplateException extends CoreException
$sMessage = "Twig Exception when rendering '$sTemplatePath' : ".$oTwigException->getMessage(); $sMessage = "Twig Exception when rendering '$sTemplatePath' : ".$oTwigException->getMessage();
parent::__construct($sMessage, null, '', $oTwigException); parent::__construct($sMessage, null, '', $oTwigException);
} }
} }

View File

@@ -1,5 +1,4 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0

View File

@@ -1,5 +1,4 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0

View File

@@ -1,5 +1,4 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -7,4 +6,4 @@
class DeleteException extends CoreException class DeleteException extends CoreException
{ {
} }

View File

@@ -1,5 +1,4 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0

View File

@@ -12,13 +12,13 @@ class InvalidExternalKeyValueException extends CoreUnexpectedValue
public function __construct($oObject, $sAttCode, $aContextData = null, $oPrevious = null) public function __construct($oObject, $sAttCode, $aContextData = null, $oPrevious = null)
{ {
$aContextData[self::ENUM_PARAMS_OBJECT] = get_class($oObject).'::'.$oObject->GetKey(); $aContextData[self::ENUM_PARAMS_OBJECT] = get_class($oObject) . '::' . $oObject->GetKey();
$aContextData[self::ENUM_PARAMS_ATTCODE] = $sAttCode; $aContextData[self::ENUM_PARAMS_ATTCODE] = $sAttCode;
$aContextData[self::ENUM_PARAMS_ATTVALUE] = $oObject->Get($sAttCode); $aContextData[self::ENUM_PARAMS_ATTVALUE] = $oObject->Get($sAttCode);
$oCurrentUser = UserRights::GetUserObject(); $oCurrentUser = UserRights::GetUserObject();
if (false === is_null($oCurrentUser)) { if (false === is_null($oCurrentUser)) {
$aContextData[self::ENUM_PARAMS_USER] = get_class($oCurrentUser).'::'.$oCurrentUser->GetKey(); $aContextData[self::ENUM_PARAMS_USER] = get_class($oCurrentUser) . '::' . $oCurrentUser->GetKey();
} }
parent::__construct('Attribute pointing to an object that is either non existing or not readable by the current user', $aContextData, '', $oPrevious); parent::__construct('Attribute pointing to an object that is either non existing or not readable by the current user', $aContextData, '', $oPrevious);

View File

@@ -1,5 +1,4 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -12,4 +11,4 @@
*/ */
class InvalidPasswordAttributeOneWayPassword extends CoreException class InvalidPasswordAttributeOneWayPassword extends CoreException
{ {
} }

View File

@@ -1,5 +1,4 @@
<?php <?php
/** /**
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -11,4 +10,4 @@ use Exception;
class PageNotFoundException extends Exception class PageNotFoundException extends Exception
{ {
} }

View File

@@ -1,5 +1,4 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0

View File

@@ -1,5 +1,4 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -7,4 +6,4 @@
class SynchroExceptionNotStarted extends CoreException class SynchroExceptionNotStarted extends CoreException
{ {
} }

View File

@@ -1,5 +1,4 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -7,4 +6,4 @@
class UserRightException extends CoreException class UserRightException extends CoreException
{ {
} }

View File

@@ -1,5 +1,4 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -7,4 +6,4 @@
class DictException extends CoreException class DictException extends CoreException
{ {
} }

View File

@@ -1,5 +1,4 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -9,9 +8,9 @@ class DictExceptionMissingString extends DictException
{ {
public function __construct($sLanguageCode, $sStringCode) public function __construct($sLanguageCode, $sStringCode)
{ {
$aContext = []; $aContext = array();
$aContext['language_code'] = $sLanguageCode; $aContext['language_code'] = $sLanguageCode;
$aContext['string_code'] = $sStringCode; $aContext['string_code'] = $sStringCode;
parent::__construct('Missing localized string', $aContext); parent::__construct('Missing localized string', $aContext);
} }
} }

View File

@@ -1,5 +1,4 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -9,8 +8,8 @@ class DictExceptionUnknownLanguage extends DictException
{ {
public function __construct($sLanguageCode) public function __construct($sLanguageCode)
{ {
$aContext = []; $aContext = array();
$aContext['language_code'] = $sLanguageCode; $aContext['language_code'] = $sLanguageCode;
parent::__construct('Unknown localization language', $aContext); parent::__construct('Unknown localization language', $aContext);
} }
} }

View File

@@ -1,5 +1,4 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -7,4 +6,5 @@
class iTopXmlException extends CoreException class iTopXmlException extends CoreException
{ {
}
}

View File

@@ -1,5 +1,4 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -21,7 +20,7 @@ class MySQLException extends CoreException
$aContext['mysql_errno'] = $oException->getCode(); $aContext['mysql_errno'] = $oException->getCode();
$this->code = $oException->getCode(); $this->code = $oException->getCode();
$aContext['mysql_error'] = $oException->getMessage(); $aContext['mysql_error'] = $oException->getMessage();
} elseif ($oMysqli != null) { } else if ($oMysqli != null) {
$aContext['mysql_errno'] = $oMysqli->errno; $aContext['mysql_errno'] = $oMysqli->errno;
$this->code = $oMysqli->errno; $this->code = $oMysqli->errno;
$aContext['mysql_error'] = $oMysqli->error; $aContext['mysql_error'] = $oMysqli->error;
@@ -37,4 +36,4 @@ class MySQLException extends CoreException
error_reporting(0); error_reporting(0);
} }
} }
} }

View File

@@ -1,5 +1,4 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -20,14 +19,14 @@ class MySQLHasGoneAwayException extends MySQLException
*/ */
public static function getErrorCodes() public static function getErrorCodes()
{ {
return [ return array(
2006, 2006,
2013, 2013,
]; );
} }
public function __construct($sIssue, $aContext) public function __construct($sIssue, $aContext)
{ {
parent::__construct($sIssue, $aContext, null); parent::__construct($sIssue, $aContext, null);
} }
} }

View File

@@ -1,5 +1,4 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -10,4 +9,5 @@
*/ */
class MySQLNoTransactionException extends MySQLException class MySQLNoTransactionException extends MySQLException
{ {
}
}

View File

@@ -1,5 +1,4 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -12,4 +11,5 @@
*/ */
class MySQLQueryHasNoResultException extends MySQLException class MySQLQueryHasNoResultException extends MySQLException
{ {
}
}

View File

@@ -1,5 +1,4 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -10,4 +9,5 @@
*/ */
class MySQLTransactionNotClosedException extends MySQLException class MySQLTransactionNotClosedException extends MySQLException
{ {
}
}

View File

@@ -1,5 +1,4 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -13,4 +12,4 @@
*/ */
class ProcessException extends CoreException class ProcessException extends CoreException
{ {
} }

View File

@@ -1,5 +1,4 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -14,4 +13,4 @@
*/ */
class ProcessFatalException extends CoreException class ProcessFatalException extends CoreException
{ {
} }

View File

@@ -1,5 +1,4 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
@@ -10,4 +9,4 @@
*/ */
class ProcessInvalidConfigException extends ProcessException class ProcessInvalidConfigException extends ProcessException
{ {
} }

View File

@@ -1,5 +1,4 @@
<?php <?php
/** /**
* Copyright (C) 2013-2024 Combodo SAS * Copyright (C) 2013-2024 Combodo SAS
* *
@@ -23,8 +22,8 @@
* @author Olivier DAIN <olivier.dain@combodo.com> * @author Olivier DAIN <olivier.dain@combodo.com>
* @since 3.0.0 N°3588 * @since 3.0.0 N°3588
*/ */
class FindStylesheetObject class FindStylesheetObject{
{
//file URIs //file URIs
private $aStylesheetFileURIs; private $aStylesheetFileURIs;
@@ -65,7 +64,7 @@ class FindStylesheetObject
return $this->aStylesheetFileURIs; return $this->aStylesheetFileURIs;
} }
public function GetLastModified(): int public function GetLastModified() : int
{ {
return $this->iLastModified; return $this->iLastModified;
} }
@@ -93,8 +92,7 @@ class FindStylesheetObject
$this->sLastStyleSheetPath = $sStylesheetFilePath; $this->sLastStyleSheetPath = $sStylesheetFilePath;
} }
public function AlreadyFetched(string $sStylesheetFilePath): bool public function AlreadyFetched(string $sStylesheetFilePath) : bool {
{
return in_array($sStylesheetFilePath, $this->aAllStylesheetFilePaths); return in_array($sStylesheetFilePath, $this->aAllStylesheetFilePaths);
} }
@@ -113,4 +111,4 @@ class FindStylesheetObject
{ {
$this->sLastStyleSheetPath = ""; $this->sLastStyleSheetPath = "";
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -1,10 +1,9 @@
<?php <?php
// Copyright (C) 2010-2024 Combodo SAS // Copyright (C) 2010-2024 Combodo SAS
// //
// This file is part of iTop. // This file is part of iTop.
// //
// iTop is free software; you can redistribute it and/or modify // iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by // it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
@@ -17,6 +16,7 @@
// You should have received a copy of the GNU Affero General Public License // You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with iTop. If not, see <http://www.gnu.org/licenses/>
/** /**
* Persistent class InputOutputTask * Persistent class InputOutputTask
* *
@@ -28,40 +28,41 @@ require_once(APPROOT.'/application/cmdbabstract.class.inc.php');
/** /**
* This class manages the input/output tasks * This class manages the input/output tasks
* for synchronizing information with external data sources * for synchronizing information with external data sources
*/ */
class InputOutputTask extends cmdbAbstractObject class InputOutputTask extends cmdbAbstractObject
{ {
public static function Init() public static function Init()
{ {
$aParams = $aParams = array
[ (
"category" => "application", "category" => "application",
"key_type" => "autoincrement", "key_type" => "autoincrement",
"name_attcode" => "name", "name_attcode" => "name",
"state_attcode" => "", "state_attcode" => "",
"reconc_keys" => [], "reconc_keys" => array(),
"db_table" => "priv_iotask", "db_table" => "priv_iotask",
"db_key_field" => "id", "db_key_field" => "id",
"db_finalclass_field" => "", "db_finalclass_field" => "",
]; );
MetaModel::Init_Params($aParams); MetaModel::Init_Params($aParams);
MetaModel::Init_AddAttribute(new AttributeString("name", ["allowed_values" => null, "sql" => "name", "default_value" => "", "is_null_allowed" => false, "depends_on" => []])); MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values"=>null, "sql"=>"name", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("description", ["allowed_values" => null, "sql" => "description", "default_value" => "", "is_null_allowed" => true, "depends_on" => []])); MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values"=>null, "sql"=>"description", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeEnum("category", ["allowed_values" => new ValueSetEnum('Input, Ouput'), "sql" => "category", "default_value" => "Input", "is_null_allowed" => false, "depends_on" => []])); MetaModel::Init_AddAttribute(new AttributeEnum("category", array("allowed_values"=>new ValueSetEnum('Input, Ouput'), "sql"=>"category", "default_value"=>"Input", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeEnum("source_type", ["allowed_values" => new ValueSetEnum('File, Database, Web Service'), "sql" => "source_type", "default_value" => "File", "is_null_allowed" => false, "depends_on" => []])); MetaModel::Init_AddAttribute(new AttributeEnum("source_type", array("allowed_values"=>new ValueSetEnum('File, Database, Web Service'), "sql"=>"source_type", "default_value"=>"File", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeEnum("source_subtype", ["allowed_values" => new ValueSetEnum('Oracle, MySQL, Postgress, MSSQL, SOAP, HTTP-Get, HTTP-Post, XML/RPC, CSV, XML, Excel'), "sql" => "source_subtype", "default_value" => "CSV", "is_null_allowed" => false, "depends_on" => []])); MetaModel::Init_AddAttribute(new AttributeEnum("source_subtype", array("allowed_values"=>new ValueSetEnum('Oracle, MySQL, Postgress, MSSQL, SOAP, HTTP-Get, HTTP-Post, XML/RPC, CSV, XML, Excel'), "sql"=>"source_subtype", "default_value"=>"CSV", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("source_path", ["allowed_values" => null, "sql" => "source_path", "default_value" => "", "is_null_allowed" => false, "depends_on" => []])); MetaModel::Init_AddAttribute(new AttributeString("source_path", array("allowed_values"=>null, "sql"=>"source_path", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeClass("objects_class", ["class_category" => "", "more_values" => "", "sql" => "objects_class", "default_value" => null, "is_null_allowed" => true, "depends_on" => []])); MetaModel::Init_AddAttribute(new AttributeClass("objects_class", array("class_category"=>"", "more_values"=>"", "sql"=>"objects_class", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeEnum("test_mode", ["allowed_values" => new ValueSetEnum('Yes,No'), "sql" => "test_mode", "default_value" => 'No', "is_null_allowed" => false, "depends_on" => []])); MetaModel::Init_AddAttribute(new AttributeEnum("test_mode", array("allowed_values"=>new ValueSetEnum('Yes,No'), "sql"=>"test_mode", "default_value"=>'No', "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeEnum("verbose_mode", ["allowed_values" => new ValueSetEnum('Yes,No'), "sql" => "verbose_mode", "default_value" => 'No', "is_null_allowed" => false, "depends_on" => []])); MetaModel::Init_AddAttribute(new AttributeEnum("verbose_mode", array("allowed_values"=>new ValueSetEnum('Yes,No'), "sql"=>"verbose_mode", "default_value" => 'No', "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeEnum("options", ["allowed_values" => new ValueSetEnum('Full, Update Only, Creation Only'), "sql" => "options", "default_value" => 'Full', "is_null_allowed" => true, "depends_on" => []])); MetaModel::Init_AddAttribute(new AttributeEnum("options", array("allowed_values"=>new ValueSetEnum('Full, Update Only, Creation Only'), "sql"=>"options", "default_value"=> 'Full', "is_null_allowed"=>true, "depends_on"=>array())));
// Display lists // Display lists
MetaModel::Init_SetZListItems('details', ['name', 'description', 'category', 'objects_class', 'source_type', 'source_subtype', 'source_path' , 'options', 'test_mode', 'verbose_mode']); // Attributes to be displayed for the complete details MetaModel::Init_SetZListItems('details', array('name', 'description', 'category', 'objects_class', 'source_type', 'source_subtype', 'source_path' , 'options', 'test_mode', 'verbose_mode')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', ['description', 'category', 'objects_class', 'source_type', 'source_subtype', 'options']); // Attributes to be displayed for a list MetaModel::Init_SetZListItems('list', array('description', 'category', 'objects_class', 'source_type', 'source_subtype', 'options')); // Attributes to be displayed for a list
// Search criteria // Search criteria
MetaModel::Init_SetZListItems('standard_search', ['name', 'category', 'objects_class', 'source_type', 'source_subtype']); // Criteria of the std search form MetaModel::Init_SetZListItems('standard_search', array('name', 'category', 'objects_class', 'source_type', 'source_subtype')); // Criteria of the std search form
MetaModel::Init_SetZListItems('advanced_search', ['name', 'description', 'category', 'objects_class', 'source_type', 'source_subtype']); // Criteria of the advanced search form MetaModel::Init_SetZListItems('advanced_search', array('name', 'description', 'category', 'objects_class', 'source_type', 'source_subtype')); // Criteria of the advanced search form
} }
} }
?>

Some files were not shown because too many files have changed in this diff Show More