mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-14 16:04:10 +01:00
Compare commits
112 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bd9da07734 | ||
|
|
3dbbf296b8 | ||
|
|
50a8af4082 | ||
|
|
6a1125875b | ||
|
|
878c23892d | ||
|
|
248dab9289 | ||
|
|
4f0e3430c0 | ||
|
|
3347f400b8 | ||
|
|
6082308e20 | ||
|
|
5fce2a2c1c | ||
|
|
03b8ed5ce4 | ||
|
|
31a34c247c | ||
|
|
a625733885 | ||
|
|
d7fad4b646 | ||
|
|
f4d538ef6c | ||
|
|
aadb605dec | ||
|
|
f63f2bd445 | ||
|
|
fefd9aae95 | ||
|
|
878b87b68c | ||
|
|
14ae9f0809 | ||
|
|
b3369c8b0e | ||
|
|
33903f570b | ||
|
|
127809a836 | ||
|
|
6c948873ff | ||
|
|
a93be39aeb | ||
|
|
7c93d116ec | ||
|
|
f948d6e026 | ||
|
|
a222ead43c | ||
|
|
d6bfbbcd30 | ||
|
|
17df9d0f9d | ||
|
|
93099ea3c7 | ||
|
|
2f9e050e2b | ||
|
|
5c341138e1 | ||
|
|
56b9eb6cf3 | ||
|
|
db20244212 | ||
|
|
6f9f74e72f | ||
|
|
8070d5b9b7 | ||
|
|
6197ecbaf4 | ||
|
|
ca585d3f42 | ||
|
|
02c78d4044 | ||
|
|
9e5d668c02 | ||
|
|
051656f295 | ||
|
|
9a51a44549 | ||
|
|
5102b113ed | ||
|
|
f1e4d94499 | ||
|
|
d04102bab3 | ||
|
|
c723d19e01 | ||
|
|
dac77e0606 | ||
|
|
02b98543d9 | ||
|
|
519aaadd9a | ||
|
|
fe27fef530 | ||
|
|
72dbb6f937 | ||
|
|
ccb29d10ae | ||
|
|
e479775833 | ||
|
|
86a7192f5a | ||
|
|
4a1be13904 | ||
|
|
0f3347f64d | ||
|
|
6564d84a2f | ||
|
|
f4747c5cef | ||
|
|
1e92c2f28a | ||
|
|
e4b097b196 | ||
|
|
85653c9ffc | ||
|
|
da5d8b20fa | ||
|
|
9a5a5f858f | ||
|
|
a0cd281c42 | ||
|
|
6bb5606c00 | ||
|
|
a6ceb88fca | ||
|
|
7bb7a94fbc | ||
|
|
e4324cedb4 | ||
|
|
07781c7c9d | ||
|
|
ea58a807fc | ||
|
|
fb6806a1c1 | ||
|
|
166451c4e9 | ||
|
|
7c1290f684 | ||
|
|
179c774ba8 | ||
|
|
e886d80de6 | ||
|
|
3791b2dd24 | ||
|
|
12c916f4e5 | ||
|
|
ba7e00e130 | ||
|
|
bada955725 | ||
|
|
f9e18675f3 | ||
|
|
22416cc0be | ||
|
|
ec086ad94a | ||
|
|
17d4b570e8 | ||
|
|
2dfad12553 | ||
|
|
26dcaa0ded | ||
|
|
b5d3ddb7e3 | ||
|
|
8b178914b3 | ||
|
|
ce6fd4d775 | ||
|
|
9c75cb4537 | ||
|
|
633fa343a5 | ||
|
|
a1d01e252b | ||
|
|
b157fad0b6 | ||
|
|
70d2bb163c | ||
|
|
fae6c89e9a | ||
|
|
89d310258b | ||
|
|
a58529f46c | ||
|
|
12a2035791 | ||
|
|
b1ff7f0e9b | ||
|
|
23cf2b91f4 | ||
|
|
3c4fe338b6 | ||
|
|
6159ab33b7 | ||
|
|
77f757995e | ||
|
|
2858d13fd5 | ||
|
|
99f398a87e | ||
|
|
87ee731dbe | ||
|
|
f2380ae354 | ||
|
|
2d039af278 | ||
|
|
831879fe37 | ||
|
|
ea1dfd8933 | ||
|
|
24519c69a4 | ||
|
|
bc841dd239 |
103
.doc/README.md
Normal file
103
.doc/README.md
Normal file
@@ -0,0 +1,103 @@
|
||||
# Phpdoc dokuwiki template
|
||||
This directory contains a template rendering iTop phpdoc as wiki pages.
|
||||
|
||||
|
||||
conventional tag 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 tags where 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 with `ClassName::`
|
||||
* 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 ans 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 enclose 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
|
||||
```
|
||||
composer require phpdocumentor/phpdocumentor:~2 --dev
|
||||
```
|
||||
|
||||
## Generation
|
||||
`.doc/bin/build-doc-object-manipulation` and `.doc/bin/build-doc-extensions` contains examples of doc. generation, beware: they have to be called from iTop root directory:
|
||||
```shell
|
||||
cd /path/to/itop/
|
||||
./.doc/bin/build-doc-object-manipulation
|
||||
```
|
||||
|
||||
the resulting documentation is written into `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
|
||||
|
||||
7
.doc/bin/build-doc-extensions
Executable file
7
.doc/bin/build-doc-extensions
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/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 .doc/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
|
||||
8
.doc/bin/build-doc-object-manipulation
Executable file
8
.doc/bin/build-doc-object-manipulation
Executable file
@@ -0,0 +1,8 @@
|
||||
#!/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 .doc/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
|
||||
20
.doc/phpdoc-extensions.dist.xml
Executable file
20
.doc/phpdoc-extensions.dist.xml
Executable 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>
|
||||
58
.doc/phpdoc-objects-manipulation.dist.xml
Executable file
58
.doc/phpdoc-objects-manipulation.dist.xml
Executable 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>-->
|
||||
<!--<!–<default>data/phpdocumentor/log/objects-manipulation/{DATE}.log</default>–>-->
|
||||
<!--<!–<errors>data/phpdocumentor/log/objects-manipulation/{DATE}.errors.log</errors>–>-->
|
||||
|
||||
<!--<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>
|
||||
0
.doc/phpdoc-templates/.placeholder
Normal file
0
.doc/phpdoc-templates/.placeholder
Normal file
136
.doc/phpdoc-templates/combodo-wiki/class.txt.twig
Normal file
136
.doc/phpdoc-templates/combodo-wiki/class.txt.twig
Normal 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 %}
|
||||
@@ -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 %}
|
||||
95
.doc/phpdoc-templates/combodo-wiki/elements/method.txt.twig
Normal file
95
.doc/phpdoc-templates/combodo-wiki/elements/method.txt.twig
Normal 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 %}
|
||||
@@ -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 %}
|
||||
1
.doc/phpdoc-templates/combodo-wiki/file.source.txt.twig
Normal file
1
.doc/phpdoc-templates/combodo-wiki/file.source.txt.twig
Normal file
@@ -0,0 +1 @@
|
||||
{{ node.source|raw }}
|
||||
122
.doc/phpdoc-templates/combodo-wiki/file.txt.twig
Normal file
122
.doc/phpdoc-templates/combodo-wiki/file.txt.twig
Normal 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 %}
|
||||
42
.doc/phpdoc-templates/combodo-wiki/graphs/class.html.twig
Normal file
42
.doc/phpdoc-templates/combodo-wiki/graphs/class.html.twig
Normal 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 %}
|
||||
5
.doc/phpdoc-templates/combodo-wiki/htaccess.dist
Normal file
5
.doc/phpdoc-templates/combodo-wiki/htaccess.dist
Normal 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>
|
||||
@@ -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 %}
|
||||
@@ -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 %}
|
||||
@@ -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 informations]]
|
||||
|
||||
</WRAP>{# group #}
|
||||
|
||||
{% endfor %}
|
||||
|
||||
@@ -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 %}
|
||||
@@ -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 %}
|
||||
@@ -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 -%}
|
||||
|
||||
22
.doc/phpdoc-templates/combodo-wiki/includes/tags.txt.twig
Normal file
22
.doc/phpdoc-templates/combodo-wiki/includes/tags.txt.twig
Normal 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 %}
|
||||
24
.doc/phpdoc-templates/combodo-wiki/includes/used-by.txt.twig
Normal file
24
.doc/phpdoc-templates/combodo-wiki/includes/used-by.txt.twig
Normal 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 %}#}
|
||||
24
.doc/phpdoc-templates/combodo-wiki/includes/uses.txt.twig
Normal file
24
.doc/phpdoc-templates/combodo-wiki/includes/uses.txt.twig
Normal 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 %}#}
|
||||
@@ -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 %}
|
||||
121
.doc/phpdoc-templates/combodo-wiki/interface.txt.twig
Normal file
121
.doc/phpdoc-templates/combodo-wiki/interface.txt.twig
Normal 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 %}
|
||||
5
.doc/phpdoc-templates/combodo-wiki/layout.txt.twig
Normal file
5
.doc/phpdoc-templates/combodo-wiki/layout.txt.twig
Normal file
@@ -0,0 +1,5 @@
|
||||
{% use 'elements/constant.txt.twig' %}
|
||||
{% use 'elements/property.txt.twig' %}
|
||||
{% use 'elements/method.txt.twig' %}
|
||||
|
||||
{% block content %}{% endblock %}
|
||||
51
.doc/phpdoc-templates/combodo-wiki/namespace.txt.twig
Normal file
51
.doc/phpdoc-templates/combodo-wiki/namespace.txt.twig
Normal 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 %}
|
||||
@@ -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 %}
|
||||
|
||||
27
.doc/phpdoc-templates/combodo-wiki/template.xml
Normal file
27
.doc/phpdoc-templates/combodo-wiki/template.xml
Normal 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>
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -33,7 +33,8 @@ test/vendor/*
|
||||
!/.idea/inspectionProfiles
|
||||
!/.idea/inspectionProfiles/*
|
||||
|
||||
|
||||
#phpdocumentor temp file
|
||||
ast.dump
|
||||
|
||||
# CMake
|
||||
cmake-build-*/
|
||||
|
||||
1
.idea/inspectionProfiles/profiles_settings.xml
generated
1
.idea/inspectionProfiles/profiles_settings.xml
generated
@@ -1,6 +1,5 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<settings>
|
||||
<option name="projectProfile" value="Combodo" />
|
||||
<option name="PROJECT_PROFILE" value="Combodo" />
|
||||
<version value="1.0" />
|
||||
</settings>
|
||||
|
||||
@@ -35,7 +35,7 @@ iTop also offers mass import tools and web services to integrate with your IT
|
||||
- [Changes since the previous version][58]
|
||||
- [New features][59]
|
||||
- [Migration notes][60]
|
||||
- [Download iTop 2.6.0][61]
|
||||
- [Download iTop 2.6.1][61]
|
||||
|
||||
|
||||
### Version 2.5
|
||||
@@ -74,6 +74,7 @@ We would like to give a special thank you to the people from the community who c
|
||||
- Gumble, David
|
||||
- Hippler, Lars
|
||||
- Khamit, Shamil
|
||||
- Kincel, Martin
|
||||
- Konečný, Kamil
|
||||
- Kunin, Vladimir
|
||||
- Lassiter, Dennis
|
||||
@@ -137,4 +138,4 @@ We would like to give a special thank you to the people from the community who c
|
||||
[58]: https://www.itophub.io/wiki/page?id=2_6_0:release:change_log
|
||||
[59]: https://www.itophub.io/wiki/page?id=2_6_0:release:2_6_whats_new
|
||||
[60]: https://www.itophub.io/wiki/page?id=2_6_0:install:250_to_260_migration_notes
|
||||
[61]: https://sourceforge.net/projects/itop/files/itop/2.6.0
|
||||
[61]: https://sourceforge.net/projects/itop/files/itop/2.6.1
|
||||
|
||||
@@ -365,7 +365,7 @@ interface iPopupMenuExtension
|
||||
* Base class for the various types of custom menus
|
||||
*
|
||||
* @package Extensibility
|
||||
* @internal
|
||||
* @api
|
||||
* @since 2.0
|
||||
*/
|
||||
abstract class ApplicationPopupMenuItem
|
||||
@@ -378,8 +378,10 @@ abstract class ApplicationPopupMenuItem
|
||||
protected $aCssClasses;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* Constructor
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @param string $sUID The unique identifier of this menu in iTop... make sure you pass something unique enough
|
||||
* @param string $sLabel The display label of the menu (must be localized)
|
||||
* @param array $aCssClasses The CSS classes to add to the menu
|
||||
@@ -509,6 +511,9 @@ class JSPopupMenuItem extends ApplicationPopupMenuItem
|
||||
|
||||
/**
|
||||
* Class for adding an item that triggers some Javascript code
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @param string $sUID The unique identifier of this menu in iTop... make sure you pass something unique enough
|
||||
* @param string $sLabel The display label of the menu (must be localized)
|
||||
* @param string $sJSCode In case the menu consists in executing some havascript code inside the page, pass it here. If supplied $sURL ans $sTarget will be ignored
|
||||
|
||||
@@ -385,6 +385,7 @@ EOF
|
||||
|
||||
if (!isset($aExtraParams['disable_plugins']) || !$aExtraParams['disable_plugins'])
|
||||
{
|
||||
/** @var iApplicationUIExtension $oExtensionInstance */
|
||||
foreach(MetaModel::EnumPlugins('iApplicationUIExtension') as $oExtensionInstance)
|
||||
{
|
||||
$oExtensionInstance->OnDisplayProperties($this, $oPage, $bEditMode);
|
||||
@@ -648,6 +649,7 @@ EOF
|
||||
}
|
||||
$oPage->SetCurrentTab('');
|
||||
|
||||
/** @var \iApplicationUIExtension $oExtensionInstance */
|
||||
foreach(MetaModel::EnumPlugins('iApplicationUIExtension') as $oExtensionInstance)
|
||||
{
|
||||
$oExtensionInstance->OnDisplayRelations($this, $oPage, $bEditMode);
|
||||
@@ -908,7 +910,7 @@ EOF
|
||||
|
||||
|
||||
/**
|
||||
* @param \iTopWebPage $oPage
|
||||
* @param \WebPage $oPage
|
||||
* @param bool $bEditMode
|
||||
*
|
||||
* @throws \CoreException
|
||||
@@ -918,8 +920,9 @@ EOF
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
* @throws \OQLException
|
||||
* @throws \Exception
|
||||
*/
|
||||
function DisplayDetails(WebPage $oPage, $bEditMode = false)
|
||||
public function DisplayDetails(WebPage $oPage, $bEditMode = false)
|
||||
{
|
||||
$sTemplate = Utils::ReadFromFile(MetaModel::GetDisplayTemplate(get_class($this)));
|
||||
if (!empty($sTemplate))
|
||||
@@ -941,6 +944,7 @@ EOF
|
||||
// template not found display the object using the *old style*
|
||||
$oPage->add('<div id="search-widget-results-outer">');
|
||||
$this->DisplayBareHeader($oPage, $bEditMode);
|
||||
/** @var \iTopWebPage $oPage */
|
||||
$oPage->AddTabContainer(OBJECT_PROPERTIES_TAB);
|
||||
$oPage->SetCurrentTabContainer(OBJECT_PROPERTIES_TAB);
|
||||
$oPage->SetCurrentTab(Dict::S('UI:PropertiesTab'));
|
||||
@@ -2101,7 +2105,7 @@ EOF
|
||||
$('#{$iId}_console_form').console_form_handler('alignColumns');
|
||||
$('#{$iId}_console_form').console_form_handler('option', 'field_set', $('#{$iId}_field_set'));
|
||||
// field_change must be processed to refresh the hidden value at anytime
|
||||
$('#{$iId}_console_form').bind('value_change', function() { $('#{$iId}').val(JSON.stringify($('#{$iId}_field_set').triggerHandler('get_current_values'))); console.error($('#{$iId}').val()); });
|
||||
$('#{$iId}_console_form').bind('value_change', function() { $('#{$iId}').val(JSON.stringify($('#{$iId}_field_set').triggerHandler('get_current_values'))); });
|
||||
// Initialize the hidden value with current state
|
||||
// update_value is triggered when preparing the wizard helper object for ajax calls
|
||||
$('#{$iId}').bind('update_value', function() { $(this).val(JSON.stringify($('#{$iId}_field_set').triggerHandler('get_current_values'))); });
|
||||
@@ -2174,6 +2178,14 @@ EOF
|
||||
if ((count($aAllowedValues) == 1) && ($bMandatory == 'true'))
|
||||
{
|
||||
// When there is only once choice, select it by default
|
||||
if($value != $key)
|
||||
{
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
$('#$iId').attr('data-validate','dependencies');
|
||||
EOF
|
||||
);
|
||||
}
|
||||
$sSelected = ' selected';
|
||||
}
|
||||
else
|
||||
@@ -3032,6 +3044,7 @@ EOF
|
||||
$current = parent::GetHilightClass(); // Default computation
|
||||
|
||||
// Invoke extensions before the deletion (the deletion will do some cleanup and we might loose some information
|
||||
/** @var \iApplicationUIExtension $oExtensionInstance */
|
||||
foreach(MetaModel::EnumPlugins('iApplicationUIExtension') as $oExtensionInstance)
|
||||
{
|
||||
$new = $oExtensionInstance->GetHilightClass($this);
|
||||
@@ -3453,6 +3466,7 @@ EOF
|
||||
}
|
||||
|
||||
// Invoke extensions after the update of the object from the form
|
||||
/** @var \iApplicationUIExtension $oExtensionInstance */
|
||||
foreach(MetaModel::EnumPlugins('iApplicationUIExtension') as $oExtensionInstance)
|
||||
{
|
||||
$oExtensionInstance->OnFormSubmit($this, $sFormPrefix);
|
||||
|
||||
@@ -445,14 +445,16 @@ EOF
|
||||
foreach($this->oModelReflection->ListAttributes($sClass) as $sAttCode => $sAttType)
|
||||
{
|
||||
// For external fields, find the real type of the target
|
||||
$sExtFieldAttCode = $sAttCode;
|
||||
$sTargetClass = $sClass;
|
||||
while (is_a($sAttType, 'AttributeExternalField', true))
|
||||
{
|
||||
$sExtKeyAttCode = $this->oModelReflection->GetAttributeProperty($sTargetClass, $sAttCode, 'extkey_attcode');
|
||||
$sTargetAttCode = $this->oModelReflection->GetAttributeProperty($sTargetClass, $sAttCode, 'target_attcode');
|
||||
$sExtKeyAttCode = $this->oModelReflection->GetAttributeProperty($sTargetClass, $sExtFieldAttCode, 'extkey_attcode');
|
||||
$sTargetAttCode = $this->oModelReflection->GetAttributeProperty($sTargetClass, $sExtFieldAttCode, 'target_attcode');
|
||||
$sTargetClass = $this->oModelReflection->GetAttributeProperty($sTargetClass, $sExtKeyAttCode, 'targetclass');
|
||||
$aTargetAttCodes = $this->oModelReflection->ListAttributes($sTargetClass);
|
||||
$sAttType = $aTargetAttCodes[$sTargetAttCode];
|
||||
$sExtFieldAttCode = $sTargetAttCode;
|
||||
}
|
||||
if (is_a($sAttType, 'AttributeLinkedSet', true))
|
||||
{
|
||||
|
||||
@@ -184,6 +184,10 @@ class DataTable
|
||||
*/
|
||||
public function GetAsHTMLTableRows(WebPage $oPage, $iPageSize, $aColumns, $sSelectMode, $bViewLink, $aExtraParams)
|
||||
{
|
||||
if ($iPageSize < 1)
|
||||
{
|
||||
$iPageSize = -1; // convention: no pagination
|
||||
}
|
||||
$aAttribs = $this->GetHTMLTableConfig($aColumns, $sSelectMode, $bViewLink);
|
||||
$aValues = $this->GetHTMLTableValues($aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams);
|
||||
|
||||
@@ -222,14 +226,21 @@ class DataTable
|
||||
}
|
||||
|
||||
$sCombo = '<select class="pagesize">';
|
||||
for($iPage = 1; $iPage < 5; $iPage++)
|
||||
if($iPageSize < 1)
|
||||
{
|
||||
$iNbItems = $iPage * $iDefaultPageSize;
|
||||
$sSelected = ($iNbItems == $iPageSize) ? 'selected="selected"' : '';
|
||||
$sCombo .= "<option $sSelected value=\"$iNbItems\">$iNbItems</option>";
|
||||
$sCombo .= "<option selected=\"selected\" value=\"-1\">".Dict::S('UI:Pagination:All')."</option>";
|
||||
}
|
||||
$sSelected = ($iPageSize < 1) ? 'selected="selected"' : '';
|
||||
$sCombo .= "<option $sSelected value=\"-1\">".Dict::S('UI:Pagination:All')."</option>";
|
||||
else
|
||||
{
|
||||
for($iPage = 1; $iPage < 5; $iPage++)
|
||||
{
|
||||
$iNbItems = $iPage * $iDefaultPageSize;
|
||||
$sSelected = ($iNbItems == $iPageSize) ? 'selected="selected"' : '';
|
||||
$sCombo .= "<option $sSelected value=\"$iNbItems\">$iNbItems</option>";
|
||||
}
|
||||
$sCombo .= "<option value=\"-1\">".Dict::S('UI:Pagination:All')."</option>";
|
||||
}
|
||||
|
||||
$sCombo .= '</select>';
|
||||
|
||||
$sPages = Dict::S('UI:Pagination:PagesLabel');
|
||||
@@ -577,8 +588,8 @@ EOF
|
||||
|
||||
public function UpdatePager(WebPage $oPage, $iDefaultPageSize, $iStart)
|
||||
{
|
||||
$iPageSize = ($iDefaultPageSize < 1) ? 1 : $iDefaultPageSize;
|
||||
$iPageIndex = 1 + floor($iStart / $iPageSize);
|
||||
$iPageSize = $iDefaultPageSize;
|
||||
$iPageIndex = 0;
|
||||
$sHtml = $this->GetPager($oPage, $iPageSize, $iDefaultPageSize, $iPageIndex);
|
||||
$oPage->add_ready_script("$('#pager{$this->iListId}').html('".json_encode($sHtml)."');");
|
||||
if ($iDefaultPageSize < 1)
|
||||
@@ -936,4 +947,4 @@ class DataTableSettings implements Serializable
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -500,7 +500,10 @@ class DisplayBlock
|
||||
}
|
||||
$aAttribs =array(
|
||||
'group' => array('label' => $sGroupByLabel, 'description' => ''),
|
||||
'value' => array('label'=> Dict::S('UI:GroupBy:'.$sAggregationFunction), 'description' => Dict::Format('UI:GroupBy:'.$sAggregationFunction.'+', $sAggregationAttr))
|
||||
'value' => array(
|
||||
'label' => Dict::S('UI:GroupBy:'.$sAggregationFunction),
|
||||
'description' => Dict::Format('UI:GroupBy:'.$sAggregationFunction.'+', $sAggregationAttr),
|
||||
),
|
||||
);
|
||||
$sFormat = isset($aExtraParams['format']) ? $aExtraParams['format'] : 'UI:Pagination:HeaderNoSelection';
|
||||
$sHtml .= $oPage->GetP(Dict::Format($sFormat, $iTotalCount));
|
||||
@@ -699,7 +702,7 @@ class DisplayBlock
|
||||
'breadcrumb_label' => MetaModel::GetName($this->m_oSet->GetClass()),
|
||||
'breadcrumb_max_count' => utils::GetConfig()->Get('breadcrumb.max_count'),
|
||||
'breadcrumb_instance_id' => MetaModel::GetConfig()->GetItopInstanceid(),
|
||||
'breadcrumb_icon' => utils::GetAbsoluteUrlAppRoot().'images/breadcrumb-search.png'
|
||||
'breadcrumb_icon' => utils::GetAbsoluteUrlAppRoot().'images/breadcrumb-search.png',
|
||||
));
|
||||
|
||||
$oPage->add_ready_script("$('body').trigger('update_history.itop', [$seventAttachedData])");
|
||||
@@ -1172,16 +1175,26 @@ EOF
|
||||
}
|
||||
if (($bAutoReload) && ($this->m_sStyle != 'search')) // Search form do NOT auto-reload
|
||||
{
|
||||
$sFilter = addslashes(str_replace('"', "'", $this->m_oFilter->serialize())); // Used either for asynchronous or auto_reload
|
||||
$sExtraParams = addslashes(str_replace('"', "'", json_encode($aExtraParams))); // JSON encode, change the style of the quotes and escape them
|
||||
// Used either for asynchronous or auto_reload
|
||||
// does a json_encode twice to get a string usable as function parameter
|
||||
$sFilterBefore = $this->m_oFilter->serialize();
|
||||
$sFilter = json_encode($sFilterBefore);
|
||||
$sExtraParams = json_encode(json_encode($aExtraParams));
|
||||
|
||||
$oPage->add_script('if (typeof window.oAutoReloadBlock == "undefined") {
|
||||
window.oAutoReloadBlock = {};
|
||||
}
|
||||
if (typeof window.oAutoReloadBlock[\''.$sId.'\'] != "undefined") {
|
||||
clearInterval(window.oAutoReloadBlock[\''.$sId.'\']);
|
||||
}
|
||||
window.oAutoReloadBlock[\''.$sId.'\'] = setInterval("ReloadBlock(\''.$sId.'\', \''.$this->m_sStyle.'\', \"'.$sFilter.'\", \"'.$sExtraParams.'\")", '.$iReloadInterval.');');
|
||||
$oPage->add_script(
|
||||
<<<JS
|
||||
if (typeof window.oAutoReloadBlock == "undefined") {
|
||||
window.oAutoReloadBlock = {};
|
||||
}
|
||||
if (typeof window.oAutoReloadBlock['$sId'] != "undefined") {
|
||||
clearInterval(window.oAutoReloadBlock['$sId']);
|
||||
}
|
||||
|
||||
window.oAutoReloadBlock['$sId'] = setInterval(function() {
|
||||
ReloadBlock('$sId', '{$this->m_sStyle}', $sFilter, $sExtraParams);
|
||||
}, '$iReloadInterval');
|
||||
JS
|
||||
);
|
||||
}
|
||||
|
||||
return $sHtml;
|
||||
@@ -1719,6 +1732,7 @@ class MenuBlock extends DisplayBlock
|
||||
*/
|
||||
}
|
||||
$this->AddMenuSeparator($aActions);
|
||||
/** @var \iApplicationUIExtension $oExtensionInstance */
|
||||
foreach (MetaModel::EnumPlugins('iApplicationUIExtension') as $oExtensionInstance)
|
||||
{
|
||||
$oSet->Rewind();
|
||||
@@ -1814,6 +1828,7 @@ class MenuBlock extends DisplayBlock
|
||||
}
|
||||
|
||||
$this->AddMenuSeparator($aActions);
|
||||
/** @var \iApplicationUIExtension $oExtensionInstance */
|
||||
foreach (MetaModel::EnumPlugins('iApplicationUIExtension') as $oExtensionInstance)
|
||||
{
|
||||
$oSet->Rewind();
|
||||
|
||||
@@ -707,6 +707,7 @@ EOF
|
||||
{
|
||||
// No rights to be here, redirect to the portal
|
||||
header('Location: '.$ret);
|
||||
die();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -399,6 +399,7 @@ class ObjectDetailsTemplate extends DisplayTemplate
|
||||
$aPlugInProperties = $aMatches[1];
|
||||
foreach($aPlugInProperties as $sPlugInClass)
|
||||
{
|
||||
/** @var \iApplicationUIExtension $oInstance */
|
||||
$oInstance = MetaModel::GetPlugins('iApplicationUIExtension', $sPlugInClass);
|
||||
if ($oInstance != null) // Safety check...
|
||||
{
|
||||
|
||||
@@ -208,6 +208,14 @@ class UIExtKeyWidget
|
||||
{
|
||||
// When there is only once choice, select it by default
|
||||
$sSelected = 'selected';
|
||||
if($value != $key)
|
||||
{
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
$('#$this->iId').attr('data-validate','dependencies');
|
||||
EOF
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -286,11 +286,13 @@ class UILinksWidgetDirect
|
||||
* @param DBObject $oCurrentObj
|
||||
* @param $aAlreadyLinked
|
||||
*
|
||||
* @param array $aPrefillFormParam
|
||||
*
|
||||
* @throws \CoreException
|
||||
* @throws \Exception
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public function GetObjectsSelectionDlg($oPage, $oCurrentObj, $aAlreadyLinked)
|
||||
public function GetObjectsSelectionDlg($oPage, $oCurrentObj, $aAlreadyLinked, $aPrefillFormParam = array())
|
||||
{
|
||||
$sHtml = "<div class=\"wizContainer\" style=\"vertical-align:top;\">\n";
|
||||
|
||||
@@ -333,6 +335,8 @@ class UILinksWidgetDirect
|
||||
|
||||
$aArgs = array_merge($oCurrentObj->ToArgs('this'), $oFilter->GetInternalParams());
|
||||
$oFilter->SetInternalParams($aArgs);
|
||||
$aPrefillFormParam['filter'] = $oFilter;
|
||||
$oCurrentObj->PrefillForm('search', $aPrefillFormParam);
|
||||
}
|
||||
$oBlock = new DisplayBlock($oFilter, 'search', false);
|
||||
$sHtml .= $oBlock->GetDisplay($oPage, "SearchFormToAdd_{$this->sInputid}",
|
||||
@@ -359,13 +363,17 @@ class UILinksWidgetDirect
|
||||
|
||||
/**
|
||||
* Search for objects to be linked to the current object (i.e "remote" objects)
|
||||
*
|
||||
* @param WebPage $oP The page used for the output (usually an AjaxWebPage)
|
||||
* @param string $sRemoteClass Name of the "remote" class to perform the search on, must be a derived class of $this->sLinkedClass
|
||||
* @param array $aAlreadyLinked Array of indentifiers of objects which are already linke to the current object (or about to be linked)
|
||||
* @param DBObject $oCurrentObj The object currently being edited... if known...
|
||||
* @throws Exception
|
||||
* @param array $aPrefillFormParam
|
||||
*
|
||||
* @throws \CoreException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public function SearchObjectsToAdd(WebPage $oP, $sRemoteClass = '', $aAlreadyLinked = array(), $oCurrentObj = null)
|
||||
public function SearchObjectsToAdd(WebPage $oP, $sRemoteClass = '', $aAlreadyLinked = array(), $oCurrentObj = null, $aPrefillFormParam = array())
|
||||
{
|
||||
if ($sRemoteClass == '')
|
||||
{
|
||||
@@ -395,16 +403,19 @@ class UILinksWidgetDirect
|
||||
$oFilter->AddCondition('id', $oCurrentObj->GetKey(), '!=');
|
||||
}
|
||||
}
|
||||
if (count($aAlreadyLinked) > 0)
|
||||
{
|
||||
$oFilter->AddCondition('id', $aAlreadyLinked, 'NOTIN');
|
||||
}
|
||||
if ($oCurrentObj != null)
|
||||
{
|
||||
$this->SetSearchDefaultFromContext($oCurrentObj, $oFilter);
|
||||
|
||||
$aArgs = array_merge($oCurrentObj->ToArgs('this'), $oFilter->GetInternalParams());
|
||||
$oFilter->SetInternalParams($aArgs);
|
||||
|
||||
$aPrefillFormParam['filter'] = $oFilter;
|
||||
$oCurrentObj->PrefillForm('search', $aPrefillFormParam);
|
||||
}
|
||||
if (count($aAlreadyLinked) > 0)
|
||||
{
|
||||
$oFilter->AddCondition('id', $aAlreadyLinked, 'NOTIN');
|
||||
}
|
||||
$oBlock = new DisplayBlock($oFilter, 'list', false);
|
||||
$oBlock->Display($oP, "ResultsToAdd_{$this->sInputid}", array('menu' => false, 'cssCount'=> '#count_'.$this->sInputid , 'selection_mode' => true, 'table_id' => 'add_'.$this->sInputid)); // Don't display the 'Actions' menu on the results
|
||||
|
||||
@@ -133,14 +133,15 @@ class UILinksWidget
|
||||
$sPrefix = "$this->m_sAttCode{$this->m_sNameSuffix}";
|
||||
$aRow = array();
|
||||
$aFieldsMap = array();
|
||||
$iKey = 0;
|
||||
if(is_object($linkObjOrId) && (!$linkObjOrId->IsNew()))
|
||||
{
|
||||
$key = $linkObjOrId->GetKey();
|
||||
$iKey = $linkObjOrId->GetKey();
|
||||
$iRemoteObjKey = $linkObjOrId->Get($this->m_sExtKeyToRemote);
|
||||
$sPrefix .= "[$key][";
|
||||
$sPrefix .= "[$iKey][";
|
||||
$sNameSuffix = "]"; // To make a tabular form
|
||||
$aArgs['prefix'] = $sPrefix;
|
||||
$aArgs['wizHelper'] = "oWizardHelper{$this->m_iInputId}{$key}";
|
||||
$aArgs['wizHelper'] = "oWizardHelper{$this->m_iInputId}{$iKey}";
|
||||
$aArgs['this'] = $linkObjOrId;
|
||||
|
||||
if($bReadOnly)
|
||||
@@ -154,7 +155,7 @@ class UILinksWidget
|
||||
}
|
||||
else
|
||||
{
|
||||
$aRow['form::checkbox'] = "<input class=\"selection\" data-remote-id=\"$iRemoteObjKey\" data-link-id=\"$key\" data-unique-id=\"$iUniqueId\" type=\"checkbox\" onClick=\"oWidget".$this->m_iInputId.".OnSelectChange();\" value=\"$key\">";
|
||||
$aRow['form::checkbox'] = "<input class=\"selection\" data-remote-id=\"$iRemoteObjKey\" data-link-id=\"$iKey\" data-unique-id=\"$iUniqueId\" type=\"checkbox\" onClick=\"oWidget".$this->m_iInputId.".OnSelectChange();\" value=\"$iKey\">";
|
||||
foreach($this->m_aEditableFields as $sFieldCode)
|
||||
{
|
||||
$sFieldId = $this->m_iInputId.'_'.$sFieldCode.'['.$linkObjOrId->GetKey().']';
|
||||
@@ -195,7 +196,30 @@ class UILinksWidget
|
||||
$aArgs['wizHelper'] = "oWizardHelper{$this->m_iInputId}_".($iUniqueId < 0 ? -$iUniqueId : $iUniqueId);
|
||||
$aArgs['this'] = $oNewLinkObj;
|
||||
$sInputValue = $iUniqueId > 0 ? "-$iUniqueId" : "$iUniqueId";
|
||||
$aRow['form::checkbox'] = "<input class=\"selection\" data-remote-id=\"$iRemoteObjKey\" data-link-id=\"\" data-unique-id=\"$iUniqueId\" type=\"checkbox\" onClick=\"oWidget".$this->m_iInputId.".OnSelectChange();\" value=\"$sInputValue\">";
|
||||
$aRow['form::checkbox'] = "<input class=\"selection\" data-remote-id=\"$iRemoteObjKey\" data-link-id=\"0\" data-unique-id=\"$iUniqueId\" type=\"checkbox\" onClick=\"oWidget".$this->m_iInputId.".OnSelectChange();\" value=\"$sInputValue\">";
|
||||
|
||||
if ($iUniqueId > 0)
|
||||
{
|
||||
// Rows created with ajax call need OnLinkAdded call.
|
||||
//
|
||||
$oP->add_ready_script(
|
||||
<<<EOF
|
||||
PrepareWidgets();
|
||||
oWidget{$this->m_iInputId}.OnLinkAdded($iUniqueId, $iRemoteObjKey);
|
||||
EOF
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Rows added before loading the form don't have to call OnLinkAdded.
|
||||
// Listeners are already present and DOM is not recreated
|
||||
$iPositiveUniqueId = -$iUniqueId;
|
||||
$oP->add_ready_script(<<<EOF
|
||||
oWidget{$this->m_iInputId}.AddLink($iPositiveUniqueId, $iRemoteObjKey);
|
||||
EOF
|
||||
);
|
||||
}
|
||||
|
||||
foreach($this->m_aEditableFields as $sFieldCode)
|
||||
{
|
||||
$sFieldId = $this->m_iInputId.'_'.$sFieldCode.'['.-$iUniqueId.']';
|
||||
@@ -207,20 +231,12 @@ class UILinksWidget
|
||||
cmdbAbstractObject::GetFormElementForField($oP, $this->m_sLinkedClass, $sFieldCode, $oAttDef, $sValue, $sDisplayValue, $sSafeId /* id */, $sNameSuffix, 0, $aArgs).
|
||||
'</div></div></div>';
|
||||
$aFieldsMap[$sFieldCode] = $sSafeId;
|
||||
$oP->add_ready_script(<<<EOF
|
||||
oWidget{$this->m_iInputId}.OnValueChange($iKey, $iUniqueId, '$sFieldCode', '$sValue');
|
||||
EOF
|
||||
);
|
||||
}
|
||||
$sState = '';
|
||||
|
||||
// Rows created with ajax call need OnLinkAdded call.
|
||||
// Rows added before loading the form cannot call OnLinkAdded.
|
||||
if ($iUniqueId > 0)
|
||||
{
|
||||
$oP->add_ready_script(
|
||||
<<<EOF
|
||||
PrepareWidgets();
|
||||
oWidget{$this->m_iInputId}.OnLinkAdded($iUniqueId, $iRemoteObjKey);
|
||||
EOF
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if(!$bReadOnly)
|
||||
@@ -337,8 +353,19 @@ EOF
|
||||
$sHtmlValue .= "<input type=\"hidden\" id=\"{$sFormPrefix}{$this->m_iInputId}\">\n";
|
||||
$oValue->Rewind();
|
||||
$aForm = array();
|
||||
$iAddedId = 1; // Unique id for new links
|
||||
$aAddedLinks = array();
|
||||
$iAddedId = -1; // Unique id for new links
|
||||
|
||||
$sDuplicates = ($this->m_bDuplicatesAllowed) ? 'true' : 'false';
|
||||
// Don't automatically launch the search if the table is huge
|
||||
$bDoSearch = !utils::IsHighCardinality($this->m_sRemoteClass);
|
||||
$sJSDoSearch = $bDoSearch ? 'true' : 'false';
|
||||
$sWizHelper = 'oWizardHelper'.$sFormPrefix;
|
||||
$oPage->add_ready_script(<<<EOF
|
||||
oWidget{$this->m_iInputId} = new LinksWidget('{$this->m_sAttCode}{$this->m_sNameSuffix}', '{$this->m_sClass}', '{$this->m_sAttCode}', '{$this->m_iInputId}', '{$this->m_sNameSuffix}', $sDuplicates, $sWizHelper, '{$this->m_sExtKeyToRemote}', $sJSDoSearch);
|
||||
oWidget{$this->m_iInputId}.Init();
|
||||
EOF
|
||||
);
|
||||
|
||||
while($oCurrentLink = $oValue->Fetch())
|
||||
{
|
||||
// We try to retrieve the remote object as usual
|
||||
@@ -357,9 +384,7 @@ EOF
|
||||
|
||||
if ($oCurrentLink->IsNew())
|
||||
{
|
||||
$key = -($iAddedId++);
|
||||
$iUniqueId = -$key;
|
||||
$aAddedLinks[] = array('iAddedId' => $iUniqueId, 'iRemote' => $oCurrentLink->Get($this->m_sExtKeyToRemote));
|
||||
$key = $iAddedId--;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -368,24 +393,6 @@ EOF
|
||||
$aForm[$key] = $this->GetFormRow($oPage, $oLinkedObj, $oCurrentLink, $aArgs, $oCurrentObj, $key, $bReadOnly);
|
||||
}
|
||||
$sHtmlValue .= $this->DisplayFormTable($oPage, $this->m_aTableConfig, $aForm);
|
||||
$sDuplicates = ($this->m_bDuplicatesAllowed) ? 'true' : 'false';
|
||||
// Don't automatically launch the search if the table is huge
|
||||
$bDoSearch = !utils::IsHighCardinality($this->m_sRemoteClass);
|
||||
$sJSDoSearch = $bDoSearch ? 'true' : 'false';
|
||||
$sWizHelper = 'oWizardHelper'.$sFormPrefix;
|
||||
$oPage->add_ready_script(<<<EOF
|
||||
oWidget{$this->m_iInputId} = new LinksWidget('{$this->m_sAttCode}{$this->m_sNameSuffix}', '{$this->m_sClass}', '{$this->m_sAttCode}', '{$this->m_iInputId}', '{$this->m_sNameSuffix}', $sDuplicates, $sWizHelper, '{$this->m_sExtKeyToRemote}', $sJSDoSearch);
|
||||
oWidget{$this->m_iInputId}.Init();
|
||||
EOF
|
||||
);
|
||||
|
||||
foreach ($aAddedLinks as $aAddedLink)
|
||||
{
|
||||
$oPage->add_ready_script(<<<EOF
|
||||
oWidget{$this->m_iInputId}.AddLink({$aAddedLink['iAddedId']}, {$aAddedLink['iRemote']});
|
||||
EOF
|
||||
);
|
||||
}
|
||||
|
||||
$sHtmlValue .= "<span style=\"float:left;\"> <img src=\"../images/tv-item-last.gif\"> <input id=\"{$this->m_sAttCode}{$this->m_sNameSuffix}_btnRemove\" type=\"button\" value=\"".Dict::S('UI:RemoveLinkedObjectsOf_Class')."\" onClick=\"oWidget{$this->m_iInputId}.RemoveSelected();\" >";
|
||||
$sHtmlValue .= " <input id=\"{$this->m_sAttCode}{$this->m_sNameSuffix}_btnAdd\" type=\"button\" value=\"".Dict::Format('UI:AddLinkedObjectsOf_Class', MetaModel::GetName($this->m_sRemoteClass))."\" onClick=\"oWidget{$this->m_iInputId}.AddObjects();\"><span id=\"{$this->m_sAttCode}{$this->m_sNameSuffix}_indicatorAdd\"></span></span>\n";
|
||||
|
||||
3054
composer.lock
generated
Normal file
3054
composer.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -512,7 +512,7 @@ abstract class AttributeDefinition
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|null $sDefault
|
||||
* @param string|null $sDefault if null, will return the attribute code replacing "_" by " "
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
@@ -6525,26 +6525,60 @@ class AttributeExternalField extends AttributeDefinition
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sDefault
|
||||
*
|
||||
* @return string dict entry if defined, otherwise :
|
||||
* <ul>
|
||||
* <li>if field is a friendlyname then display the label of the ExternalKey
|
||||
* <li>the class hierarchy -> field name
|
||||
*
|
||||
* <p>For example, having this :
|
||||
*
|
||||
* <pre>
|
||||
* +---------------------+ +--------------------+ +--------------+
|
||||
* | Class A | | Class B | | Class C |
|
||||
* +---------------------+ +--------------------+ +--------------+
|
||||
* | foo <ExternalField>-------->c_id_friendly_name--------->friendlyname |
|
||||
* +---------------------+ +--------------------+ +--------------+
|
||||
* </pre>
|
||||
*
|
||||
* <p>The ExternalField foo points to a magical field that is brought by c_id ExternalKey in class B.
|
||||
*
|
||||
* <p>In the normal case the foo label would be : B -> C -> friendlyname<br>
|
||||
* But as foo is a friendlyname its label will be the same as the one on A.b_id field
|
||||
* This can be overrided with dict key Class:ClassA/Attribute:foo
|
||||
*
|
||||
* @throws \CoreException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function GetLabel($sDefault = null)
|
||||
{
|
||||
$sLabelDefaultValue = '';
|
||||
$sLabel = parent::GetLabel($sLabelDefaultValue);
|
||||
if ($sLabelDefaultValue !== $sLabel)
|
||||
{
|
||||
return $sLabel;
|
||||
}
|
||||
|
||||
if ($this->IsFriendlyName())
|
||||
{
|
||||
// This will be used even if we are pointing to a friendlyname in a distance > 1
|
||||
// For example we can link to a magic friendlyname (like org_id_friendlyname)
|
||||
// If a specific label is needed, use a Dict key !
|
||||
// See N°2174
|
||||
$sKeyAttCode = $this->Get("extkey_attcode");
|
||||
$oExtKeyAttDef = MetaModel::GetAttributeDef($this->GetHostClass(), $sKeyAttCode);
|
||||
$sLabel = $oExtKeyAttDef->GetLabel($this->m_sCode);
|
||||
|
||||
return $sLabel;
|
||||
}
|
||||
else
|
||||
{
|
||||
$sLabel = parent::GetLabel('');
|
||||
if (strlen($sLabel) == 0)
|
||||
{
|
||||
$oRemoteAtt = $this->GetExtAttDef();
|
||||
$sLabel = $oRemoteAtt->GetLabel($this->m_sCode);
|
||||
$oKeyAtt = $this->GetKeyAttDef();
|
||||
$sKeyLabel = $oKeyAtt->GetLabel($this->GetKeyAttCode());
|
||||
$sLabel = "{$sKeyLabel}->{$sLabel}";
|
||||
}
|
||||
}
|
||||
|
||||
$oRemoteAtt = $this->GetExtAttDef();
|
||||
$sLabel = $oRemoteAtt->GetLabel($this->m_sCode);
|
||||
$oKeyAtt = $this->GetKeyAttDef();
|
||||
$sKeyLabel = $oKeyAtt->GetLabel($this->GetKeyAttCode());
|
||||
$sLabel = "{$sKeyLabel}->{$sLabel}";
|
||||
|
||||
return $sLabel;
|
||||
}
|
||||
@@ -7836,6 +7870,87 @@ class AttributeStopWatch extends AttributeDefinition
|
||||
throw new CoreException("Unknown item code '$sItemCode' for attribute ".$this->GetHostClass().'::'.$this->GetCode());
|
||||
}
|
||||
|
||||
|
||||
public function GetSubItemSearchType($sItemCode)
|
||||
{
|
||||
switch ($sItemCode)
|
||||
{
|
||||
case 'timespent':
|
||||
return static::SEARCH_WIDGET_TYPE_NUMERIC; //seconds
|
||||
case 'started':
|
||||
case 'laststart':
|
||||
case 'stopped':
|
||||
return static::SEARCH_WIDGET_TYPE_DATE_TIME; //timestamp
|
||||
}
|
||||
|
||||
foreach($this->ListThresholds() as $iThreshold => $aFoo)
|
||||
{
|
||||
$sThPrefix = $iThreshold.'_';
|
||||
if (substr($sItemCode, 0, strlen($sThPrefix)) == $sThPrefix)
|
||||
{
|
||||
// The current threshold is concerned
|
||||
$sThresholdCode = substr($sItemCode, strlen($sThPrefix));
|
||||
switch ($sThresholdCode)
|
||||
{
|
||||
case 'deadline':
|
||||
return static::SEARCH_WIDGET_TYPE_DATE_TIME; //timestamp
|
||||
case 'passed':
|
||||
case 'triggered':
|
||||
return static::SEARCH_WIDGET_TYPE_ENUM; //booleans, used in conjuction with GetSubItemAllowedValues and IsSubItemNullAllowed
|
||||
case 'overrun':
|
||||
return static::SEARCH_WIDGET_TYPE_NUMERIC; //seconds
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return static::SEARCH_WIDGET_TYPE_RAW;
|
||||
}
|
||||
|
||||
public function GetSubItemAllowedValues($sItemCode, $aArgs = array(), $sContains = '')
|
||||
{
|
||||
foreach($this->ListThresholds() as $iThreshold => $aFoo)
|
||||
{
|
||||
$sThPrefix = $iThreshold.'_';
|
||||
if (substr($sItemCode, 0, strlen($sThPrefix)) == $sThPrefix)
|
||||
{
|
||||
// The current threshold is concerned
|
||||
$sThresholdCode = substr($sItemCode, strlen($sThPrefix));
|
||||
switch ($sThresholdCode)
|
||||
{
|
||||
case 'passed':
|
||||
case 'triggered':
|
||||
return array(
|
||||
0 => $this->GetBooleanLabel(0),
|
||||
1 => $this->GetBooleanLabel(1),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function IsSubItemNullAllowed($sItemCode, $bDefaultValue)
|
||||
{
|
||||
foreach($this->ListThresholds() as $iThreshold => $aFoo)
|
||||
{
|
||||
$sThPrefix = $iThreshold.'_';
|
||||
if (substr($sItemCode, 0, strlen($sThPrefix)) == $sThPrefix)
|
||||
{
|
||||
// The current threshold is concerned
|
||||
$sThresholdCode = substr($sItemCode, strlen($sThPrefix));
|
||||
switch ($sThresholdCode)
|
||||
{
|
||||
case 'passed':
|
||||
case 'triggered':
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $bDefaultValue;
|
||||
}
|
||||
|
||||
protected function GetBooleanLabel($bValue)
|
||||
{
|
||||
$sDictKey = $bValue ? 'yes' : 'no';
|
||||
@@ -8185,9 +8300,39 @@ class AttributeStopWatch extends AttributeDefinition
|
||||
*/
|
||||
class AttributeSubItem extends AttributeDefinition
|
||||
{
|
||||
const SEARCH_WIDGET_TYPE = self::SEARCH_WIDGET_TYPE_RAW;
|
||||
/**
|
||||
* Return the search widget type corresponding to this attribute
|
||||
* the computation is made by AttributeStopWatch::GetSubItemSearchType
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function GetSearchType()
|
||||
{
|
||||
/** @var AttributeStopWatch $oParent */
|
||||
$oParent = $this->GetTargetAttDef();
|
||||
|
||||
static public function ListExpectedParams()
|
||||
return $oParent->GetSubItemSearchType($this->Get('item_code'));
|
||||
}
|
||||
|
||||
public function GetAllowedValues($aArgs = array(), $sContains = '')
|
||||
{
|
||||
/** @var AttributeStopWatch $oParent */
|
||||
$oParent = $this->GetTargetAttDef();
|
||||
|
||||
return $oParent->GetSubItemAllowedValues($this->Get('item_code'), $aArgs, $sContains);
|
||||
}
|
||||
|
||||
public function IsNullAllowed()
|
||||
{
|
||||
/** @var AttributeStopWatch $oParent */
|
||||
$oParent = $this->GetTargetAttDef();
|
||||
|
||||
$bDefaultValue = parent::IsNullAllowed();
|
||||
|
||||
return $oParent->IsSubItemNullAllowed($this->Get('item_code'), $bDefaultValue);
|
||||
}
|
||||
|
||||
static public function ListExpectedParams()
|
||||
{
|
||||
return array_merge(parent::ListExpectedParams(), array('target_attcode', 'item_code'));
|
||||
}
|
||||
|
||||
@@ -696,6 +696,8 @@ abstract class CMDBObject extends DBObject
|
||||
* TODO: investigate how to get rid of this class that was made to workaround some language limitation... or a poor design!
|
||||
*
|
||||
* @package iTopORM
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class CMDBObjectSet extends DBObjectSet
|
||||
{
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
define('ITOP_APPLICATION', 'iTop');
|
||||
define('ITOP_APPLICATION_SHORT', 'iTop');
|
||||
define('ITOP_VERSION', '2.6.0');
|
||||
define('ITOP_VERSION', '2.6.2');
|
||||
define('ITOP_REVISION', 'svn');
|
||||
define('ITOP_BUILD_DATE', '$WCNOW$');
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -17,9 +17,22 @@
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
//
|
||||
|
||||
// Dev hack for disabling the some query build optimizations (Folding/Merging)
|
||||
/** @internal Dev hack for disabling some query build optimizations (Folding/Merging) */
|
||||
define('ENABLE_OPT', true);
|
||||
|
||||
/**
|
||||
* A search over a DBObject
|
||||
*
|
||||
* This is the most common search cases, the other class representing a search is DBUnionSearch.
|
||||
* For clarity purpose, since only the constructor vary between DBObjectSearch and DBUnionSearch, all the API is documented on the common ancestor: DBSearch
|
||||
* Please refer to DBSearch's documentation
|
||||
*
|
||||
* @package iTopORM
|
||||
* @phpdoc-tuning-exclude-inherited this tag prevent PHPdoc from displaying inherited methods. This is done in order to force the API doc. location into DBSearch only.
|
||||
* @api
|
||||
* @see DBSearch
|
||||
* @see DBUnionSearch
|
||||
*/
|
||||
class DBObjectSearch extends DBSearch
|
||||
{
|
||||
private $m_aClasses; // queried classes (alias => class name), the first item is the class corresponding to this filter (the rest is coming from subfilters)
|
||||
@@ -29,11 +42,23 @@ class DBObjectSearch extends DBSearch
|
||||
private $m_aPointingTo;
|
||||
private $m_aReferencedBy;
|
||||
|
||||
// By default, some information may be hidden to the current user
|
||||
// But it may happen that we need to disable that feature
|
||||
/**
|
||||
* @var bool whether or not some information should be hidden to the current user. Default to false == hide information.
|
||||
* @see AllowAllData()
|
||||
*/
|
||||
protected $m_bAllowAllData = false;
|
||||
protected $m_bDataFiltered = false;
|
||||
|
||||
/**
|
||||
* DBObjectSearch constructor.
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @param string $sClass
|
||||
* @param string|null $sClassAlias
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __construct($sClass, $sClassAlias = null)
|
||||
{
|
||||
parent::__construct();
|
||||
@@ -524,7 +549,7 @@ class DBObjectSearch extends DBSearch
|
||||
/**
|
||||
* Specify a condition on external keys or link sets
|
||||
* @param string $sAttSpec Can be either an attribute code or extkey->[sAttSpec] or linkset->[sAttSpec] and so on, recursively
|
||||
* Example: infra_list->ci_id->location_id->country
|
||||
* Example: infra_list->ci_id->location_id->country
|
||||
* @param $value
|
||||
* @return void
|
||||
* @throws \CoreException
|
||||
@@ -1642,7 +1667,7 @@ class DBObjectSearch extends DBSearch
|
||||
// Query caching
|
||||
//
|
||||
$sOqlAPCCacheId = null;
|
||||
if (self::$m_bQueryCacheEnabled)
|
||||
if (self::$m_bQueryCacheEnabled && $bCanCache)
|
||||
{
|
||||
// Warning: using directly the query string as the key to the hash array can FAIL if the string
|
||||
// is long and the differences are only near the end... so it's safer (but not bullet proof?)
|
||||
@@ -2344,8 +2369,8 @@ class DBObjectSearch extends DBSearch
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the expression for the class and its subclasses (if finalclass = 'subclass' ...)
|
||||
* Simplifies the final expression by grouping classes having the same expression
|
||||
* Get the expression for the class and its subclasses (if finalclass = 'subclass' ...)
|
||||
* Simplifies the final expression by grouping classes having the same expression
|
||||
* @param $sClass
|
||||
* @param $sAttCode
|
||||
* @return \FunctionExpression|mixed|null
|
||||
|
||||
@@ -27,9 +27,13 @@ require_once('dbobjectiterator.php');
|
||||
|
||||
|
||||
/**
|
||||
* A set of persistent objects, could be heterogeneous as long as the objects in the set have a common ancestor class
|
||||
* A set of persistent objects
|
||||
*
|
||||
* Created against a DBObjectSearch with additional information not relevant for the DBObjectSearch (ie: order, limit, ...)
|
||||
* This set could be heterogeneous as long as the objects in the set have a common ancestor class.
|
||||
*
|
||||
* @package iTopORM
|
||||
* @api
|
||||
*/
|
||||
class DBObjectSet implements iDBObjectSetIterator
|
||||
{
|
||||
@@ -81,6 +85,8 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
|
||||
/**
|
||||
* Create a new set based on a Search definition.
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @param DBSearch $oFilter The search filter defining the objects which are part of the set (multiple columns/objects per row are supported)
|
||||
* @param array $aOrderBy Array of '[<classalias>.]attcode' => bAscending
|
||||
@@ -110,6 +116,9 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
$this->m_oSQLResult = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
if (is_object($this->m_oSQLResult))
|
||||
@@ -119,6 +128,8 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @throws \Exception
|
||||
@@ -145,6 +156,9 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
return $sRet;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function __clone()
|
||||
{
|
||||
$this->m_oFilter = $this->m_oFilter->DeepClone();
|
||||
@@ -158,6 +172,7 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
|
||||
/**
|
||||
* Called when unserializing a DBObjectSet
|
||||
* @internal
|
||||
*/
|
||||
public function __wakeup()
|
||||
{
|
||||
@@ -168,18 +183,30 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
$this->m_oSQLResult = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @param $bShow
|
||||
*/
|
||||
public function SetShowObsoleteData($bShow)
|
||||
{
|
||||
$this->m_oFilter->SetShowObsoleteData($bShow);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @return bool
|
||||
*/
|
||||
public function GetShowObsoleteData()
|
||||
{
|
||||
return $this->m_oFilter->GetShowObsoleteData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the subset of attributes to load (for each class of objects) before performing the SQL query for retrieving the rows from the DB
|
||||
* Specify the subset of attributes to load
|
||||
* this subset is specified for each class of objects,
|
||||
* this has to be done before the actual fetch.
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @param array $aAttToLoad Format: alias => array of attribute_codes
|
||||
*
|
||||
@@ -262,6 +289,8 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
/**
|
||||
* Create a set (in-memory) containing just the given object
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @param \DBobject $oObject
|
||||
*
|
||||
* @return \DBObjectSet The singleton set
|
||||
@@ -278,6 +307,8 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
/**
|
||||
* Create an empty set (in-memory), for the given class (and its subclasses) of objects
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @param string $sClass The class (or an ancestor) for the objects to be added in this set
|
||||
*
|
||||
* @return \DBObjectSet The empty set
|
||||
@@ -297,6 +328,8 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
/**
|
||||
* Create a set (in-memory) with just one column (i.e. one object per row) and filled with the given array of objects
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @param string $sClass The class of the objects (must be a common ancestor to all objects in the set)
|
||||
* @param array $aObjects The list of objects to add into the set
|
||||
*
|
||||
@@ -314,9 +347,11 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
/**
|
||||
* Create a set in-memory with several classes of objects per row (with one alias per "column")
|
||||
*
|
||||
* Limitation:
|
||||
* **Limitation:**
|
||||
* The filter/OQL query representing such a set can not be rebuilt (only the first column will be taken into account)
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @param array $aClasses Format: array of (alias => class)
|
||||
* @param array $aObjects Format: array of (array of (classalias => object))
|
||||
*
|
||||
@@ -345,6 +380,9 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @param $oObject
|
||||
* @param string $sLinkSetAttCode
|
||||
* @param string $sExtKeyToRemote
|
||||
@@ -371,11 +409,15 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch all as array of DBObject
|
||||
*
|
||||
* Note: After calling this method, the set cursor will be at the end of the set. You might want to rewind it.
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @param bool $bWithId
|
||||
*
|
||||
* @return array
|
||||
* @return DBObject[]
|
||||
*
|
||||
* @throws \Exception
|
||||
* @throws \CoreException
|
||||
@@ -401,7 +443,14 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* Fetch all as a structured array
|
||||
*
|
||||
* Unlike ToArray, ToArrayOfValues return the objects as an array.
|
||||
* Only the scalar values will be presents (see AttributeDefinition::IsScalar())
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @return array[]
|
||||
*
|
||||
* @throws \Exception
|
||||
* @throws \CoreException
|
||||
@@ -773,6 +822,7 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
* May actually perform the SQL query SELECT COUNT... if the set was not previously loaded, or loaded with a
|
||||
* SetLimit
|
||||
*
|
||||
* @api
|
||||
* @return int The total number of rows for this set.
|
||||
*
|
||||
* @throws \CoreException
|
||||
@@ -796,11 +846,13 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
return $this->m_iNumTotalDBRows + count($this->m_aAddedObjects); // Does it fix Trac #887 ??
|
||||
}
|
||||
|
||||
/** Check if the count exceeds a given limit
|
||||
/**
|
||||
* Check if the count exceeds a given limit
|
||||
*
|
||||
* @param $iLimit
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
*
|
||||
* @throws \CoreException
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
@@ -831,11 +883,13 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
return ($iCount > $iLimit);
|
||||
}
|
||||
|
||||
/** Count only up to the given limit
|
||||
/**
|
||||
* Count only up to the given limit
|
||||
*
|
||||
* @param $iLimit
|
||||
*
|
||||
* @return int
|
||||
*
|
||||
*
|
||||
* @throws \CoreException
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
@@ -877,9 +931,11 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the object (with the given class alias) at the current position in the set and move the cursor to the next position.
|
||||
* Fetch an object (with the given class alias) at the current position in the set and move the cursor to the next position.
|
||||
*
|
||||
* @param string $sRequestedClassAlias The class alias to fetch (if there are several objects/classes per row)
|
||||
* @api
|
||||
*
|
||||
* @param string $sRequestedClassAlias The class alias to fetch (defaults to the first selected class)
|
||||
*
|
||||
* @return \DBObject The fetched object or null when at the end
|
||||
*
|
||||
@@ -933,6 +989,8 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
/**
|
||||
* Fetch the whole row of objects (if several classes have been specified in the query) and move the cursor to the next position
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @return array An associative with the format 'classAlias' => $oObj representing the current row of the set. Returns null when at the end.
|
||||
*
|
||||
* @throws \CoreException
|
||||
@@ -981,8 +1039,10 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
|
||||
/**
|
||||
* Position the cursor (for iterating in the set) to the first position (equivalent to Seek(0))
|
||||
*
|
||||
* @throws \Exception
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function Rewind()
|
||||
{
|
||||
@@ -1200,9 +1260,9 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
* @param \DBObjectSet $oObjectSet
|
||||
*
|
||||
* @return \DBObjectSet The "delta" set.
|
||||
*
|
||||
* @throws \Exception
|
||||
* @throws \CoreException
|
||||
*
|
||||
* @throws \Exception
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public function CreateDelta(DBObjectSet $oObjectSet)
|
||||
{
|
||||
@@ -1445,6 +1505,8 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
|
||||
/**
|
||||
* Helper function to perform a custom sort of a hash array
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
function HashCountComparison($a, $b) // Sort descending on 'count'
|
||||
{
|
||||
@@ -1464,6 +1526,11 @@ function HashCountComparison($a, $b) // Sort descending on 'count'
|
||||
* LIMITATIONS:
|
||||
* - only DBObjectSets with one column (i.e. one class of object selected) are supported
|
||||
* - the first set must be the one loaded from the database
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @package iTopORM
|
||||
*
|
||||
*/
|
||||
class DBObjectSetComparator
|
||||
{
|
||||
@@ -1508,6 +1575,8 @@ class DBObjectSetComparator
|
||||
/**
|
||||
* Builds the lists of fingerprints and initializes internal structures, if it was not already done
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @throws \CoreException
|
||||
*/
|
||||
protected function ComputeFingerprints()
|
||||
@@ -1557,6 +1626,9 @@ class DBObjectSetComparator
|
||||
|
||||
/**
|
||||
* Tells if the sets are equivalent or not. Returns as soon as the first difference is found.
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @return boolean true if the set have an equivalent content, false otherwise
|
||||
*
|
||||
* @throws \CoreException
|
||||
@@ -1603,8 +1675,10 @@ class DBObjectSetComparator
|
||||
/**
|
||||
* Get the list of differences between the two sets. In ordeer to write back into the database only the minimum changes
|
||||
* THE FIRST SET MUST BE THE ONE LOADED FROM THE DATABASE
|
||||
* Returns a hash: 'added' => DBObject(s), 'removed' => DBObject(s), 'modified' => DBObjects(s)
|
||||
* @return array
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @return array 'added' => DBObject(s), 'removed' => DBObject(s), 'modified' => DBObjects(s)
|
||||
*
|
||||
* @throws \Exception
|
||||
* @throws \CoreException
|
||||
@@ -1659,7 +1733,9 @@ class DBObjectSetComparator
|
||||
}
|
||||
|
||||
/**
|
||||
* Helpr to clone (in memory) an object and to apply to it the values taken from a second object
|
||||
* Helper to clone (in memory) an object and to apply to it the values taken from a second object
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @param \DBObject $oObjToClone
|
||||
* @param \DBObject $oObjWithValues
|
||||
@@ -1682,4 +1758,4 @@ class DBObjectSetComparator
|
||||
}
|
||||
return $oObj;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,24 +22,35 @@ require_once('dbunionsearch.class.php');
|
||||
|
||||
/**
|
||||
* An object search
|
||||
*
|
||||
*
|
||||
* DBSearch provides an API that leverage the possibility to construct a search against iTop's persisted objects.
|
||||
* In order to do so, it let you declare the classes you want to fetch, the conditions you want to apply, ...
|
||||
*
|
||||
* Note: in the ancient times of iTop, a search was named after DBObjectSearch.
|
||||
* When the UNION has been introduced, it has been decided to:
|
||||
* - declare a hierarchy of search classes, with two leafs :
|
||||
* - one class to cope with a single query (A JOIN B... WHERE...)
|
||||
* - and the other to cope with several queries (query1 UNION query2)
|
||||
* - in order to preserve forward/backward compatibility of the existing modules
|
||||
* - keep the name of DBObjectSearch even if it a little bit confusing
|
||||
* - do not provide a type-hint for function parameters defined in the modules
|
||||
* - leave the statements DBObjectSearch::FromOQL in the modules, though DBSearch is more relevant
|
||||
* When the UNION has been introduced, it has been decided to:
|
||||
* * declare a hierarchy of search classes : `DBObjectSearch` & `DBUnionSearch`
|
||||
* * DBObjectSearch cope with single query (A JOIN B... WHERE...)
|
||||
* * DBUnionSearch cope with several queries (query1 UNION query2)
|
||||
* * in order to preserve forward/backward compatibility of the existing modules
|
||||
* * keep the name of DBObjectSearch even if it a little bit confusing
|
||||
* * do not provide a type-hint for function parameters defined in the modules
|
||||
* * leave the statements DBObjectSearch::FromOQL in the modules, though DBSearch is more relevant
|
||||
*
|
||||
* @copyright Copyright (C) 2015-2017 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*
|
||||
*
|
||||
* @package iTopORM
|
||||
* @api
|
||||
* @see DBObjectSearch::__construct()
|
||||
* @see DBUnionSearch::__construct()
|
||||
*/
|
||||
|
||||
abstract class DBSearch
|
||||
{
|
||||
/** @internal */
|
||||
const JOIN_POINTING_TO = 0;
|
||||
/** @internal */
|
||||
const JOIN_REFERENCED_BY = 1;
|
||||
|
||||
protected $m_bNoContextParameters = false;
|
||||
@@ -47,14 +58,23 @@ abstract class DBSearch
|
||||
protected $m_bArchiveMode = false;
|
||||
protected $m_bShowObsoleteData = true;
|
||||
|
||||
/**
|
||||
* DBSearch constructor.
|
||||
*
|
||||
* @api
|
||||
* @see DBSearch::FromOQL()
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->Init();
|
||||
}
|
||||
|
||||
/**
|
||||
* called by the constructor
|
||||
* @internal Set the obsolete and archive modes to the default ones
|
||||
*/
|
||||
protected function Init()
|
||||
{
|
||||
// Set the obsolete and archive modes to the default ones
|
||||
$this->m_bArchiveMode = utils::IsArchiveMode();
|
||||
$this->m_bShowObsoleteData = true;
|
||||
}
|
||||
@@ -62,6 +82,8 @@ abstract class DBSearch
|
||||
/**
|
||||
* Perform a deep clone (as opposed to "clone" which does copy a reference to the underlying objects)
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @return \DBSearch
|
||||
**/
|
||||
public function DeepClone()
|
||||
@@ -69,22 +91,62 @@ abstract class DBSearch
|
||||
return unserialize(serialize($this)); // Beware this serializes/unserializes the search and its parameters as well
|
||||
}
|
||||
|
||||
/**
|
||||
* whether or not some information should be hidden to the current user.
|
||||
*
|
||||
* @api
|
||||
* @see IsAllDataAllowed()
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function AllowAllData();
|
||||
|
||||
/**
|
||||
* Current state of AllowAllData
|
||||
*
|
||||
* @internal
|
||||
* @see AllowAllData()
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function IsAllDataAllowed();
|
||||
|
||||
/**
|
||||
* Should the archives be fetched
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @param $bEnable
|
||||
*/
|
||||
public function SetArchiveMode($bEnable)
|
||||
{
|
||||
$this->m_bArchiveMode = $bEnable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @return bool
|
||||
*/
|
||||
public function GetArchiveMode()
|
||||
{
|
||||
return $this->m_bArchiveMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should the obsolete data be fetched
|
||||
*
|
||||
* @internal
|
||||
* @param $bShow
|
||||
*/
|
||||
public function SetShowObsoleteData($bShow)
|
||||
{
|
||||
$this->m_bShowObsoleteData = $bShow;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @return bool
|
||||
*/
|
||||
public function GetShowObsoleteData()
|
||||
{
|
||||
if ($this->m_bArchiveMode || $this->IsAllDataAllowed())
|
||||
@@ -99,14 +161,36 @@ abstract class DBSearch
|
||||
return $bRet;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function NoContextParameters() {$this->m_bNoContextParameters = true;}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @return bool
|
||||
*/
|
||||
public function HasContextParameters() {return $this->m_bNoContextParameters;}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @param $sPluginClass
|
||||
* @param $sProperty
|
||||
* @param $value
|
||||
*/
|
||||
public function SetModifierProperty($sPluginClass, $sProperty, $value)
|
||||
{
|
||||
$this->m_aModifierProperties[$sPluginClass][$sProperty] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @param $sPluginClass
|
||||
*
|
||||
* @return array|mixed
|
||||
*/
|
||||
public function GetModifierProperties($sPluginClass)
|
||||
{
|
||||
if (array_key_exists($sPluginClass, $this->m_aModifierProperties))
|
||||
@@ -119,18 +203,44 @@ abstract class DBSearch
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @param $sAlias
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function GetClassName($sAlias);
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function GetClass();
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function GetClassAlias();
|
||||
|
||||
/**
|
||||
* Change the class (only subclasses are supported as of now, because the conditions must fit the new class)
|
||||
* Defaults to the first selected class (most of the time it is also the first joined class
|
||||
*/
|
||||
* Change the class
|
||||
*
|
||||
* Defaults to the first selected class (most of the time it is also the first joined class
|
||||
* only subclasses are supported as of now, because the conditions must fit the new class
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
abstract public function ChangeClass($sNewClass, $sAlias = null);
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function GetSelectedClasses();
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @param array $aSelectedClasses array of aliases
|
||||
* @throws CoreException
|
||||
*/
|
||||
@@ -139,64 +249,207 @@ abstract class DBSearch
|
||||
/**
|
||||
* Change any alias of the query tree
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @param $sOldName
|
||||
* @param $sNewName
|
||||
* @return bool True if the alias has been found and changed
|
||||
*/
|
||||
abstract public function RenameAlias($sOldName, $sNewName);
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function IsAny();
|
||||
|
||||
/**
|
||||
* @deprecated use ToOQL() instead
|
||||
* @internal
|
||||
* @return string
|
||||
*/
|
||||
public function Describe(){return 'deprecated - use ToOQL() instead';}
|
||||
/**
|
||||
* @deprecated use ToOQL() instead
|
||||
* @internal
|
||||
* @return string
|
||||
*/
|
||||
public function DescribeConditionPointTo($sExtKeyAttCode, $aPointingTo){return 'deprecated - use ToOQL() instead';}
|
||||
/**
|
||||
* @deprecated use ToOQL() instead
|
||||
* @internal
|
||||
* @return string
|
||||
*/
|
||||
public function DescribeConditionRefBy($sForeignClass, $sForeignExtKeyAttCode){return 'deprecated - use ToOQL() instead';}
|
||||
/**
|
||||
* @deprecated use ToOQL() instead
|
||||
* @internal
|
||||
* @return string
|
||||
*/
|
||||
public function DescribeConditionRelTo($aRelInfo){return 'deprecated - use ToOQL() instead';}
|
||||
/**
|
||||
* @deprecated use ToOQL() instead
|
||||
* @internal
|
||||
* @return string
|
||||
*/
|
||||
public function DescribeConditions(){return 'deprecated - use ToOQL() instead';}
|
||||
/**
|
||||
* @deprecated use ToOQL() instead
|
||||
* @internal
|
||||
* @return string
|
||||
*/
|
||||
public function __DescribeHTML(){return 'deprecated - use ToOQL() instead';}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function ResetCondition();
|
||||
|
||||
/**
|
||||
* add $oExpression as a OR
|
||||
*
|
||||
* @api
|
||||
* @see DBSearch::AddConditionExpression()
|
||||
*
|
||||
* @param Expression $oExpression
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function MergeConditionExpression($oExpression);
|
||||
|
||||
/**
|
||||
* add $oExpression as a AND
|
||||
*
|
||||
* @api
|
||||
* @see DBSearch::MergeConditionExpression()
|
||||
*
|
||||
* @param Expression $oExpression
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function AddConditionExpression($oExpression);
|
||||
|
||||
/**
|
||||
* Condition on the friendlyname
|
||||
*
|
||||
* Restrict the query to only the corresponding selected class' friendlyname
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @param string $sName the desired friendlyname
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function AddNameCondition($sName);
|
||||
|
||||
/**
|
||||
* Add a condition
|
||||
*
|
||||
* This is the simplest way to express a AND condition. For complex use cases, use MergeConditionExpression or AddConditionExpression instead
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @param string $sFilterCode
|
||||
* @param mixed $value
|
||||
* @param string $sOpCode operator to use : '=' (default), '!=', 'IN', 'NOT IN'
|
||||
*
|
||||
* @throws \CoreException
|
||||
*
|
||||
*/
|
||||
abstract public function AddCondition($sFilterCode, $value, $sOpCode = null);
|
||||
/**
|
||||
* Specify a condition on external keys or link sets
|
||||
* @param sAttSpec Can be either an attribute code or extkey->[sAttSpec] or linkset->[sAttSpec] and so on, recursively
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @param string $sAttSpec Can be either an attribute code or extkey->[sAttSpec] or linkset->[sAttSpec] and so on, recursively
|
||||
* Example: infra_list->ci_id->location_id->country
|
||||
* @param value The value to match (can be an array => IN(val1, val2...)
|
||||
* @param mixed $value The value to match (can be an array => IN(val1, val2...)
|
||||
* @return void
|
||||
*/
|
||||
abstract public function AddConditionAdvanced($sAttSpec, $value);
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @param string $sFullText
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function AddCondition_FullText($sFullText);
|
||||
|
||||
/**
|
||||
* Perform a join, the remote class being matched by the mean of its primary key
|
||||
*
|
||||
* The join is performed
|
||||
* * from the searched class, based on the $sExtKeyAttCode attribute
|
||||
* * against the oFilter searched class, based on its primary key
|
||||
* Note : if several classes have already being joined (SELECT a join b ON...), the first joined class (a in the example) is considered as being the searched class.
|
||||
*
|
||||
* @api
|
||||
* @see AddCondition_ReferencedBy()
|
||||
*
|
||||
* @param DBObjectSearch $oFilter
|
||||
* @param $sExtKeyAttCode
|
||||
* @param int $iOperatorCode
|
||||
* @param null $aRealiasingMap array of <old-alias> => <new-alias>, for each alias that has changed
|
||||
* @param string $sExtKeyAttCode
|
||||
* @param int $iOperatorCode the comparison operator to use. For the list of all possible values, see the constant defined in core/oql/oqlquery.class.inc.php
|
||||
* @param array|null $aRealiasingMap array of <old-alias> => <new-alias>, for each alias that has changed in the newly attached oFilter (in case of collisions between the two filters)
|
||||
*
|
||||
* @throws CoreException
|
||||
* @throws CoreWarning
|
||||
*/
|
||||
abstract public function AddCondition_PointingTo(DBObjectSearch $oFilter, $sExtKeyAttCode, $iOperatorCode = TREE_OPERATOR_EQUALS, &$aRealiasingMap = null);
|
||||
|
||||
/**
|
||||
* Inverse operation of AddCondition_PointingTo
|
||||
*
|
||||
* The join is performed
|
||||
* * from the olFilter searched class, based on the $sExtKeyAttCode attribute
|
||||
* * against the searched class, based on its primary key
|
||||
* Note : if several classes have already being joined (SELECT a join b ON...), the first joined class (a in the example) is considered as being the searched class.
|
||||
*
|
||||
*
|
||||
* @api
|
||||
* @see AddCondition_PointingTo()
|
||||
*
|
||||
* @param DBObjectSearch $oFilter
|
||||
* @param $sForeignExtKeyAttCode
|
||||
* @param int $iOperatorCode
|
||||
* @param null $aRealiasingMap array of <old-alias> => <new-alias>, for each alias that has changed
|
||||
* @param array|null $aRealiasingMap array of <old-alias> => <new-alias>, for each alias that has changed in the newly attached oFilter (in case of collisions between the two filters)
|
||||
*/
|
||||
abstract public function AddCondition_ReferencedBy(DBObjectSearch $oFilter, $sForeignExtKeyAttCode, $iOperatorCode = TREE_OPERATOR_EQUALS, &$aRealiasingMap = null);
|
||||
|
||||
/**
|
||||
* Filter the result
|
||||
*
|
||||
* The filter is performed by returning only the values in common with the given $oFilter
|
||||
* The impact on the resulting query performance/viability can be significant.
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @param DBSearch $oFilter
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function Intersect(DBSearch $oFilter);
|
||||
|
||||
/**
|
||||
* @param DBSearch $oFilter
|
||||
* @param integer $iDirection
|
||||
* @param string $sExtKeyAttCode
|
||||
* @param integer $iOperatorCode
|
||||
* @param array &$RealisasingMap Map of aliases from the attached query, that could have been renamed by the optimization process
|
||||
* @return DBSearch
|
||||
*/
|
||||
/**
|
||||
* Perform a join
|
||||
*
|
||||
* The join is performed against $oFilter selected class using $sExtKeyAttCode of the current selected class
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @param DBSearch $oFilter The join is performed against $oFilter selected class
|
||||
* @param integer $iDirection can be either DBSearch::JOIN_POINTING_TO or DBSearch::JOIN_REFERENCED_BY
|
||||
* @param string $sExtKeyAttCode The join is performed against $sExtKeyAttCode wetheir it is compared aginst the current DBSearch or $oFilter depend of $iDirection
|
||||
* @param integer $iOperatorCode See DBSearch::AddCondition_PointingTo()
|
||||
* @param array|null $aRealiasingMap Map of aliases from the attached query, that could have been renamed by the optimization process
|
||||
*
|
||||
* @return DBSearch
|
||||
* @throws CoreException
|
||||
* @throws CoreWarning
|
||||
*/
|
||||
public function Join(DBSearch $oFilter, $iDirection, $sExtKeyAttCode, $iOperatorCode = TREE_OPERATOR_EQUALS, &$aRealiasingMap = null)
|
||||
{
|
||||
$oSourceFilter = $this->DeepClone();
|
||||
@@ -231,21 +484,68 @@ abstract class DBSearch
|
||||
return $oRet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the internal params.
|
||||
*
|
||||
* If any params pre-existed, they are lost.
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @param mixed[string] $aParams array of mixed params index by string name
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function SetInternalParams($aParams);
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function GetInternalParams();
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @param bool $bExcludeMagicParams
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function GetQueryParams($bExcludeMagicParams = true);
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function ListConstantFields();
|
||||
|
||||
/**
|
||||
* Turn the parameters (:xxx) into scalar values in order to easily
|
||||
* serialize a search
|
||||
* Turn the parameters (:xxx) into scalar values
|
||||
*
|
||||
* The goal is to easily serialize a search
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @param array $aArgs
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract public function ApplyParameters($aArgs);
|
||||
|
||||
/**
|
||||
* Convert a query to a string representation
|
||||
*
|
||||
* This operation can be revert back to a DBSearch using DBSearch::unserialize()
|
||||
*
|
||||
* @api
|
||||
* @see DBSearch::unserialize()
|
||||
*
|
||||
* @param bool $bDevelopParams
|
||||
* @param array $aContextParams
|
||||
*
|
||||
* @return false|string
|
||||
* @throws ArchivedObjectException
|
||||
* @throws CoreException
|
||||
*/
|
||||
public function serialize($bDevelopParams = false, $aContextParams = array())
|
||||
{
|
||||
$aQueryParams = $this->GetQueryParams();
|
||||
@@ -293,6 +593,10 @@ abstract class DBSearch
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a serialized query back to an instance of DBSearch
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @param string $sValue Serialized OQL query
|
||||
*
|
||||
* @return \DBSearch
|
||||
@@ -336,11 +640,13 @@ abstract class DBSearch
|
||||
/**
|
||||
* Create a new DBObjectSearch from $oSearch with a new alias $sAlias
|
||||
*
|
||||
* Note : This has not be tested with UNION queries.
|
||||
* @internal Note : This has not be tested with UNION queries.
|
||||
*
|
||||
* @param DBSearch $oSearch
|
||||
* @param string $sAlias
|
||||
* @param string $sAlias
|
||||
*
|
||||
* @return DBObjectSearch
|
||||
* @throws CoreException
|
||||
*/
|
||||
static public function CloneWithAlias(DBSearch $oSearch, $sAlias)
|
||||
{
|
||||
@@ -349,12 +655,37 @@ abstract class DBSearch
|
||||
return $oSearchWithAlias;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the DBSearch to an OQL representation
|
||||
*
|
||||
* @api
|
||||
* @see DBSearch::FromOQL()
|
||||
*
|
||||
* @param bool $bDevelopParams
|
||||
* @param null $aContextParams
|
||||
* @param bool $bWithAllowAllFlag
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function ToOQL($bDevelopParams = false, $aContextParams = null, $bWithAllowAllFlag = false);
|
||||
|
||||
static protected $m_aOQLQueries = array();
|
||||
|
||||
// Do not filter out depending on user rights
|
||||
// In particular when we are currently in the process of evaluating the user rights...
|
||||
/**
|
||||
* FromOQL with AllowAllData enabled
|
||||
*
|
||||
* The goal is to not filter out depending on user rights.
|
||||
* In particular when we are currently in the process of evaluating the user rights...
|
||||
*
|
||||
* @internal
|
||||
* @see DBSearch::FromOQL()
|
||||
*
|
||||
* @param string $sQuery
|
||||
* @param null $aParams
|
||||
*
|
||||
* @return DBSearch
|
||||
* @throws OQLException
|
||||
*/
|
||||
static public function FromOQL_AllData($sQuery, $aParams = null)
|
||||
{
|
||||
$oRes = self::FromOQL($sQuery, $aParams);
|
||||
@@ -363,9 +694,19 @@ abstract class DBSearch
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sQuery
|
||||
* @param array $aParams
|
||||
* @return self
|
||||
* Create a new DBSearch from the given OQL.
|
||||
*
|
||||
* This is the simplest way to create a DBSearch.
|
||||
* For almost every cases, this is the easiest way.
|
||||
*
|
||||
* @api
|
||||
* @see DBSearch::ToOQL()
|
||||
*
|
||||
* @param string $sQuery The OQL to convert to a DBSearch
|
||||
* @param mixed[string] $aParams array of <mixed> params index by <string> name
|
||||
*
|
||||
* @return DBObjectSearch|DBUnionSearch
|
||||
*
|
||||
* @throws OQLException
|
||||
*/
|
||||
static public function FromOQL($sQuery, $aParams = null)
|
||||
@@ -442,14 +783,20 @@ abstract class DBSearch
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the result has an array structure.
|
||||
*
|
||||
* Alternative to object mapping: the data are transfered directly into an array
|
||||
* This is 10 times faster than creating a set of objects, and makes sense when optimization is required
|
||||
* But this speed comes at the cost of not obtaining the easy to manipulates DBObject instances but simple array structure.
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @param array $aColumns
|
||||
* @param array $aColumns The columns you'd like to fetch.
|
||||
* @param array $aOrderBy Array of '[<classalias>.]attcode' => bAscending
|
||||
* @param array $aArgs
|
||||
*
|
||||
* @return array|void
|
||||
*
|
||||
* @throws \CoreException
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
@@ -506,7 +853,11 @@ abstract class DBSearch
|
||||
protected static $m_aQueryStructCache = array();
|
||||
|
||||
|
||||
/** Generate a Group By SQL request from a search
|
||||
/**
|
||||
* Generate a Group By SQL query from the current search
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @param array $aArgs
|
||||
* @param array $aGroupByExpr array('alias' => Expression)
|
||||
* @param bool $bExcludeNullValues
|
||||
@@ -514,7 +865,9 @@ abstract class DBSearch
|
||||
* @param array $aOrderBy array('alias' => bool) true = ASC false = DESC
|
||||
* @param int $iLimitCount
|
||||
* @param int $iLimitStart
|
||||
*
|
||||
* @return string SQL query generated
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function MakeGroupByQuery($aArgs, $aGroupByExpr, $bExcludeNullValues = false, $aSelectExpr = array(), $aOrderBy = array(), $iLimitCount = 0, $iLimitStart = 0)
|
||||
@@ -590,6 +943,10 @@ abstract class DBSearch
|
||||
|
||||
|
||||
/**
|
||||
* Generate a SQL query from the current search
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @param array|hash $aOrderBy Array of '[<classalias>.]attcode' => bAscending
|
||||
* @param array $aArgs
|
||||
* @param null $aAttToLoad
|
||||
@@ -684,9 +1041,33 @@ abstract class DBSearch
|
||||
return $sRes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @return mixed
|
||||
*/
|
||||
protected abstract function IsDataFiltered();
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @return mixed
|
||||
*/
|
||||
protected abstract function SetDataFiltered();
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @param $aOrderBy
|
||||
* @param $aArgs
|
||||
* @param $aAttToLoad
|
||||
* @param $aExtendedDataSpec
|
||||
* @param $iLimitCount
|
||||
* @param $iLimitStart
|
||||
* @param $bGetCount
|
||||
* @param null $aGroupByExpr
|
||||
* @param null $aSelectExpr
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function GetSQLQuery($aOrderBy, $aArgs, $aAttToLoad, $aExtendedDataSpec, $iLimitCount, $iLimitStart, $bGetCount, $aGroupByExpr = null, $aSelectExpr = null)
|
||||
{
|
||||
$oSearch = $this;
|
||||
@@ -727,18 +1108,46 @@ abstract class DBSearch
|
||||
return $oSQLQuery;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @param $aAttToLoad
|
||||
* @param $bGetCount
|
||||
* @param null $aGroupByExpr
|
||||
* @param null $aSelectedClasses
|
||||
* @param null $aSelectExpr
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public abstract function GetSQLQueryStructure(
|
||||
$aAttToLoad, $bGetCount, $aGroupByExpr = null, $aSelectedClasses = null, $aSelectExpr = null
|
||||
);
|
||||
|
||||
/**
|
||||
* Get the current search conditions
|
||||
*
|
||||
* @internal
|
||||
* @see DBSearch $m_oSearchCondition
|
||||
*
|
||||
* @return \Expression
|
||||
*/
|
||||
public abstract function GetCriteria();
|
||||
|
||||
/**
|
||||
* Shortcut to add efficient IN condition
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @param $sFilterCode
|
||||
* @param $aValues
|
||||
* @param bool $bPositiveMatch if true a `IN` is performed, if false, a `NOT IN` is performed
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public abstract function AddConditionForInOperatorUsingParam($sFilterCode, $aValues, $bPositiveMatch = true);
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @return string a unique param name
|
||||
*/
|
||||
protected function GenerateUniqueParamName() {
|
||||
@@ -759,36 +1168,78 @@ abstract class DBSearch
|
||||
protected static $m_bIndentQueries = false;
|
||||
protected static $m_bOptimizeQueries = false;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public static function StartDebugQuery()
|
||||
{
|
||||
$aBacktrace = debug_backtrace();
|
||||
self::$m_bDebugQuery = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public static function StopDebugQuery()
|
||||
{
|
||||
self::$m_bDebugQuery = false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @param bool $bEnabled
|
||||
* @param bool $bUseAPC
|
||||
* @param int $iTimeToLive
|
||||
*/
|
||||
public static function EnableQueryCache($bEnabled, $bUseAPC, $iTimeToLive = 3600)
|
||||
{
|
||||
self::$m_bQueryCacheEnabled = $bEnabled;
|
||||
self::$m_bUseAPCCache = $bUseAPC;
|
||||
self::$m_iQueryCacheTTL = $iTimeToLive;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @param $bEnabled
|
||||
*/
|
||||
public static function EnableQueryTrace($bEnabled)
|
||||
{
|
||||
self::$m_bTraceQueries = $bEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @param $bEnabled
|
||||
*/
|
||||
public static function EnableQueryIndentation($bEnabled)
|
||||
{
|
||||
self::$m_bIndentQueries = $bEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @param $bEnabled
|
||||
*/
|
||||
public static function EnableOptimizeQuery($bEnabled)
|
||||
{
|
||||
self::$m_bOptimizeQueries = $bEnabled;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @param $aOrderBy
|
||||
* @param $aArgs
|
||||
* @param $aAttToLoad
|
||||
* @param $aExtendedDataSpec
|
||||
* @param $iLimitCount
|
||||
* @param $iLimitStart
|
||||
* @param $bGetCount
|
||||
* @param $sSql
|
||||
*
|
||||
* @throws MySQLException
|
||||
*/
|
||||
protected function AddQueryTraceSelect($aOrderBy, $aArgs, $aAttToLoad, $aExtendedDataSpec, $iLimitCount, $iLimitStart, $bGetCount, $sSql)
|
||||
{
|
||||
if (self::$m_bTraceQueries)
|
||||
@@ -808,7 +1259,16 @@ abstract class DBSearch
|
||||
self::AddQueryTrace($aQueryData, $sOql, $sSql);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @param $aArgs
|
||||
* @param $aGroupByExpr
|
||||
* @param $sSql
|
||||
*
|
||||
* @throws MySQLException
|
||||
*/
|
||||
protected function AddQueryTraceGroupBy($aArgs, $aGroupByExpr, $sSql)
|
||||
{
|
||||
if (self::$m_bTraceQueries)
|
||||
@@ -824,6 +1284,15 @@ abstract class DBSearch
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @param $aQueryData
|
||||
* @param $sOql
|
||||
* @param $sSql
|
||||
*
|
||||
* @throws MySQLException
|
||||
*/
|
||||
protected static function AddQueryTrace($aQueryData, $sOql, $sSql)
|
||||
{
|
||||
if (self::$m_bTraceQueries)
|
||||
@@ -854,6 +1323,9 @@ abstract class DBSearch
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public static function RecordQueryTrace()
|
||||
{
|
||||
if (!self::$m_bTraceQueries)
|
||||
@@ -914,6 +1386,10 @@ abstract class DBSearch
|
||||
file_put_contents($sAllQueries, $sLog);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @param $value
|
||||
*/
|
||||
protected static function DbgTrace($value)
|
||||
{
|
||||
if (!self::$m_bDebugQuery)
|
||||
@@ -949,7 +1425,9 @@ abstract class DBSearch
|
||||
|
||||
/**
|
||||
* Experimental!
|
||||
* todo: implement the change tracking
|
||||
* @todo implement the change tracking
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @param $bArchive
|
||||
* @throws Exception
|
||||
@@ -1025,6 +1503,9 @@ abstract class DBSearch
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function UpdateContextFromUser()
|
||||
{
|
||||
$this->SetShowObsoleteData(utils::ShowObsoleteData());
|
||||
|
||||
@@ -18,10 +18,21 @@
|
||||
|
||||
|
||||
/**
|
||||
* A union of DBObjectSearches
|
||||
* A union of DBObjectSearches
|
||||
*
|
||||
* This search class represent an union over a collection of DBObjectSearch.
|
||||
* For clarity purpose, since only the constructor vary between DBObjectSearch and DBUnionSearch, all the API is documented on the common ancestor: DBSearch
|
||||
* Please refer to DBSearch's documentation
|
||||
*
|
||||
* @copyright Copyright (C) 2015-2017 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*
|
||||
*
|
||||
* @package iTopORM
|
||||
* @phpdoc-tuning-exclude-inherited this tag prevent PHPdoc from displaying inherited methods. This is done in order to force the API doc. location into DBSearch only.
|
||||
* @api
|
||||
* @see DBSearch
|
||||
* @see DBObjectSearch
|
||||
*/
|
||||
|
||||
class DBUnionSearch extends DBSearch
|
||||
@@ -29,6 +40,15 @@ class DBUnionSearch extends DBSearch
|
||||
protected $aSearches; // source queries
|
||||
protected $aSelectedClasses; // alias => classes (lowest common ancestors) computed at construction
|
||||
|
||||
/**
|
||||
* DBUnionSearch constructor.
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @param $aSearches
|
||||
*
|
||||
* @throws CoreException
|
||||
*/
|
||||
public function __construct($aSearches)
|
||||
{
|
||||
if (count ($aSearches) == 0)
|
||||
|
||||
@@ -243,10 +243,16 @@ class HTMLDOMSanitizer extends HTMLSanitizer
|
||||
{
|
||||
// Regular urls
|
||||
$sUrlPattern = utils::GetConfig()->Get('url_validation_pattern');
|
||||
|
||||
// Mailto urls
|
||||
$sMailtoPattern = '(mailto:(' . utils::GetConfig()->Get('email_validation_pattern') . ')(?:\?(?:subject|body)=([a-zA-Z0-9+\$_.-]*)(?:&(?:subject|body)=([a-zA-Z0-9+\$_.-]*))?)?)';
|
||||
|
||||
$sPattern = $sUrlPattern . '|' . $sMailtoPattern;
|
||||
// Notification placeholders
|
||||
// eg. $this->caller_id$, $this->hyperlink()$, $this->hyperlink(portal)$, $APP_URL$, $MODULES_URL$, ...
|
||||
// Note: Authorize both $xxx$ and %24xxx%24 as the latter one is encoded when used in HTML attributes (eg. a[href])
|
||||
$sPlaceholderPattern = '(\$|%24)[\w-]*(->[\w]*(\([\w-]*?\))?)?(\$|%24)';
|
||||
|
||||
$sPattern = $sUrlPattern . '|' . $sMailtoPattern . '|' . $sPlaceholderPattern;
|
||||
$sPattern = '/'.str_replace('/', '\/', $sPattern).'/i';
|
||||
self::$aAttrsWhiteList['href'] = $sPattern;
|
||||
}
|
||||
@@ -261,7 +267,7 @@ class HTMLDOMSanitizer extends HTMLSanitizer
|
||||
// We have to transform that into <p><br></p> (which is how Thunderbird implements empty lines)
|
||||
// Unfortunately, DOMDocument::loadHTML does not take the tag namespaces into account (once loaded there is no way to know if the tag did have a namespace)
|
||||
// therefore we have to do the transformation upfront
|
||||
$sHTML = preg_replace('@<o:p>\s*</o:p>@', '<br>', $sHTML);
|
||||
$sHTML = preg_replace('@<o:p>(\s| )*</o:p>@', '<br>', $sHTML);
|
||||
|
||||
@$this->oDoc->loadHTML('<?xml encoding="UTF-8"?>'.$sHTML); // For loading HTML chunks where the character set is not specified
|
||||
|
||||
|
||||
@@ -97,8 +97,9 @@ define('MYSQL_ENGINE', 'innodb');
|
||||
|
||||
|
||||
/**
|
||||
* (API) The objects definitions as well as their mapping to the database
|
||||
* The objects definitions as well as their mapping to the database
|
||||
*
|
||||
* @api
|
||||
* @package iTopORM
|
||||
*/
|
||||
abstract class MetaModel
|
||||
@@ -1233,6 +1234,7 @@ abstract class MetaModel
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @param string $sClass
|
||||
*
|
||||
* @return array
|
||||
@@ -1285,9 +1287,12 @@ abstract class MetaModel
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sClass
|
||||
* @param string $sAttCode
|
||||
* @param bool $bExtended
|
||||
* Check it the given attribute exists in the specified class
|
||||
*
|
||||
* @api
|
||||
* @param string $sClass Class name
|
||||
* @param string $sAttCode Attribute code
|
||||
* @param bool $bExtended Allow the extended syntax: extkey_id->remote_attcode
|
||||
*
|
||||
* @return bool
|
||||
* @throws \Exception
|
||||
@@ -1341,6 +1346,7 @@ abstract class MetaModel
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @param string $sClass
|
||||
* @param string $sFilterCode
|
||||
*
|
||||
@@ -1356,6 +1362,9 @@ abstract class MetaModel
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given class name is actually a persistent class
|
||||
*
|
||||
* @api
|
||||
* @param string $sClass
|
||||
*
|
||||
* @return bool
|
||||
@@ -1630,17 +1639,20 @@ abstract class MetaModel
|
||||
/**
|
||||
* array of ("classname" => array filterdef)
|
||||
*
|
||||
* @deprecated
|
||||
* @var array
|
||||
*/
|
||||
private static $m_aFilterDefs = array();
|
||||
/**
|
||||
* array of ("classname" => array of ("attcode"=>"sourceclass"))
|
||||
*
|
||||
* @deprecated
|
||||
* @var array
|
||||
*/
|
||||
private static $m_aFilterOrigins = array();
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @param string $sClass
|
||||
*
|
||||
* @return mixed
|
||||
@@ -1653,6 +1665,7 @@ abstract class MetaModel
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @param string $sClass
|
||||
* @param string $sFilterCode
|
||||
*
|
||||
@@ -1670,6 +1683,7 @@ abstract class MetaModel
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @param string $sClass
|
||||
* @param string $sFilterCode
|
||||
*
|
||||
@@ -1688,6 +1702,7 @@ abstract class MetaModel
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @param string $sClass
|
||||
* @param string $sFilterCode
|
||||
*
|
||||
@@ -1705,6 +1720,7 @@ abstract class MetaModel
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @param string $sClass
|
||||
* @param string $sFilterCode
|
||||
*
|
||||
@@ -1722,6 +1738,7 @@ abstract class MetaModel
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @param string $sClass
|
||||
* @param string $sFilterCode
|
||||
*
|
||||
@@ -1740,6 +1757,7 @@ abstract class MetaModel
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @param string $sClass
|
||||
* @param string $sFilterCode
|
||||
* @param string $sOpCode
|
||||
@@ -1759,6 +1777,7 @@ abstract class MetaModel
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @param string $sFilterCode
|
||||
*
|
||||
* @return string
|
||||
@@ -1856,7 +1875,7 @@ abstract class MetaModel
|
||||
private static $m_aRelationInfos = array();
|
||||
|
||||
/**
|
||||
* TO BE DEPRECATED: use EnumRelationsEx instead
|
||||
* @deprecated Use EnumRelationsEx instead
|
||||
*
|
||||
* @param string $sClass
|
||||
*
|
||||
@@ -6643,22 +6662,24 @@ abstract class MetaModel
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for the specified class and id.
|
||||
* Instantiate an object already persisted to the Database.
|
||||
*
|
||||
* @api
|
||||
* @see MetaModel::GetObjectWithArchive to get object even if it's archived
|
||||
* @see utils::PushArchiveMode() to enable search on archived objects
|
||||
*
|
||||
* @param string $sClass
|
||||
* @param int $iKey id value of the object to retrieve
|
||||
* @param bool $bMustBeFound see throws ArchivedObjectException
|
||||
* @param bool $bAllowAllData if true then no rights filtering
|
||||
* @param bool $bAllowAllData if true then user rights will be bypassed - use with care!
|
||||
* @param null $aModifierProperties
|
||||
*
|
||||
* @return DBObject|null null if : (the object is not found) or (archive mode disabled and object is archived and
|
||||
* @return \cmdbAbstractObject null if : (the object is not found) or (archive mode disabled and object is archived and
|
||||
* $bMustBeFound=false)
|
||||
* @throws CoreException if no result found and $bMustBeFound=true
|
||||
* @throws ArchivedObjectException if archive mode disabled and result is archived and $bMustBeFound=true
|
||||
* @throws \Exception
|
||||
*
|
||||
* @see MetaModel::GetObjectWithArchive to get object even if it's archived
|
||||
* @see utils::PushArchiveMode() to enable search on archived objects
|
||||
*/
|
||||
public static function GetObject($sClass, $iKey, $bMustBeFound = true, $bAllowAllData = false, $aModifierProperties = null)
|
||||
{
|
||||
@@ -6859,8 +6880,11 @@ abstract class MetaModel
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sClass
|
||||
* @param array|null $aValues array of attcode => value
|
||||
* Instantiate a persistable object (not yet persisted)
|
||||
*
|
||||
* @api
|
||||
* @param string $sClass A persistable class
|
||||
* @param array|null $aValues array of attcode => attribute value to preset
|
||||
*
|
||||
* @return DBObject
|
||||
* @throws \CoreException
|
||||
@@ -6905,6 +6929,8 @@ abstract class MetaModel
|
||||
* @todo: protect it against forbidden usages (in such a case, delete objects one by one)
|
||||
*
|
||||
* @param \DBObjectSearch $oFilter
|
||||
* @deprecated
|
||||
* @experimental
|
||||
*
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
@@ -6922,6 +6948,8 @@ abstract class MetaModel
|
||||
* @param DBObjectSearch $oFilter
|
||||
* @param array $aValues array of attcode => value
|
||||
*
|
||||
* @deprecated
|
||||
* @experimental
|
||||
* @return int Modified objects
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
@@ -7216,6 +7244,10 @@ abstract class MetaModel
|
||||
{
|
||||
// Expand the parameters for the object
|
||||
$sName = substr($sSearch, 0, $iPos);
|
||||
// Note: Capturing
|
||||
// 1 - The delimiter
|
||||
// 2 - The arrow
|
||||
// 3 - The attribute code
|
||||
$aRegExps = array(
|
||||
'/(\\$)'.$sName.'-(>|>)([^\\$]+)\\$/', // Support both syntaxes: $this->xxx$ or $this->xxx$ for HTML compatibility
|
||||
'/(%24)'.$sName.'-(>|>)([^%24]+)%24/', // Support for urlencoded in HTML attributes (%20this->xxx%20)
|
||||
@@ -7250,8 +7282,28 @@ abstract class MetaModel
|
||||
}
|
||||
else
|
||||
{
|
||||
$aSearches[] = '$'.$sSearch.'$';
|
||||
$aReplacements[] = (string)$replace;
|
||||
$aRegExps = array(
|
||||
'/(\$)'.$sSearch.'\$/', // Support for regular placeholders (eg. $APP_URL$)
|
||||
'/(%24)'.$sSearch.'%24/', // Support for urlencoded in HTML attributes (eg. %24APP_URL%24)
|
||||
);
|
||||
foreach($aRegExps as $sRegExp)
|
||||
{
|
||||
if(preg_match_all($sRegExp, $sInput, $aMatches))
|
||||
{
|
||||
foreach($aMatches[1] as $idx => $sDelimiter)
|
||||
{
|
||||
try
|
||||
{
|
||||
$aReplacements[] = (string) $replace;
|
||||
$aSearches[] = $aMatches[1][$idx] . $sSearch . $aMatches[1][$idx];
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
// No replacement will occur
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return str_replace($aSearches, $aReplacements, $sInput);
|
||||
|
||||
@@ -45,7 +45,7 @@ class iTopMutex
|
||||
static protected $aAcquiredLocks = array(); // Number of instances of the Mutex, having the lock, in this page
|
||||
|
||||
public function __construct(
|
||||
$sName, $sDBHost = null, $sDBUser = null, $sDBPwd = null, $bDBTlsEnabled = false, $sDBTlsCA = null
|
||||
$sName, $sDBHost = null, $sDBUser = null, $sDBPwd = null, $bDBTlsEnabled = null, $sDBTlsCA = null
|
||||
)
|
||||
{
|
||||
// Compute the name of a lock for mysql
|
||||
|
||||
@@ -126,6 +126,7 @@ class ormDocument
|
||||
*/
|
||||
public function GetDisplayURL($sClass, $Id, $sAttCode)
|
||||
{
|
||||
// TODO: When refactoring this with the URLMaker system, mind to also change calls in the portal (look for the "p_object_document_display" route)
|
||||
return utils::GetAbsoluteUrlAppRoot() . "pages/ajax.render.php?operation=display_document&class=$sClass&id=$Id&field=$sAttCode";
|
||||
}
|
||||
|
||||
@@ -137,6 +138,7 @@ class ormDocument
|
||||
{
|
||||
// Compute a signature to reset the cache anytime the data changes (this is acceptable if used only with icon files)
|
||||
$sSignature = md5($this->GetData());
|
||||
// TODO: When refactoring this with the URLMaker system, mind to also change calls in the portal (look for the "p_object_document_display" route)
|
||||
return utils::GetAbsoluteUrlAppRoot() . "pages/ajax.document.php?operation=download_document&class=$sClass&id=$Id&field=$sAttCode&s=$sSignature&cache=86400";
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
//
|
||||
// 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
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
@@ -66,7 +66,7 @@ class SimpleCrypt
|
||||
* Constructor
|
||||
* @param string $sEngineName Engine for encryption. Values: Simple, Mcrypt, Sodium or OpenSSL
|
||||
* @throws Exception This library is unkown
|
||||
*/
|
||||
*/
|
||||
function __construct($sEngineName = 'Mcrypt')
|
||||
{
|
||||
switch($sEngineName){
|
||||
@@ -88,7 +88,8 @@ class SimpleCrypt
|
||||
}
|
||||
break;
|
||||
case 'OpenSSL':
|
||||
if(!function_exists('openssl_decrypt')){
|
||||
case 'OpenSSLMcryptCompatibility':
|
||||
if(!function_exists('openssl_decrypt')){
|
||||
$sEngineName = 'Simple';
|
||||
}
|
||||
break;
|
||||
@@ -101,30 +102,30 @@ class SimpleCrypt
|
||||
$sEngineName = 'SimpleCrypt' . $sEngineName . 'Engine';
|
||||
$this->oEngine = new $sEngineName;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Encrypts the string with the given key
|
||||
* @param string $key
|
||||
* @param string $sString Plaintext string
|
||||
* @return string Ciphered string
|
||||
*/
|
||||
*/
|
||||
function Encrypt($key, $sString)
|
||||
{
|
||||
return $this->oEngine->Encrypt($key,$sString);
|
||||
return $this->oEngine->Encrypt($key,$sString);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Decrypts the string by the given key
|
||||
* @param string $key
|
||||
* @param string $string Ciphered string
|
||||
* @return string Plaintext string
|
||||
* @return string Plaintext string
|
||||
*/
|
||||
function Decrypt($key, $string)
|
||||
{
|
||||
return $this->oEngine->Decrypt($key,$string);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a random "salt" value, to be used when "hashing" a password
|
||||
* using a one-way encryption algorithm, to prevent an attack using a "rainbow table"
|
||||
@@ -135,9 +136,9 @@ class SimpleCrypt
|
||||
{
|
||||
// Copied from http://www.php.net/manual/en/function.mt-rand.php#83655
|
||||
// get 128 pseudorandom bits in a string of 16 bytes
|
||||
|
||||
|
||||
$sRandomBits = null;
|
||||
|
||||
|
||||
// Unix/Linux platform?
|
||||
$fp = @fopen('/dev/urandom','rb');
|
||||
if ($fp !== FALSE)
|
||||
@@ -156,14 +157,14 @@ class SimpleCrypt
|
||||
{
|
||||
$CAPI_Util = new COM('CAPICOM.Utilities.1');
|
||||
$sBase64RandomBits = ''.$CAPI_Util->GetRandom(16,0);
|
||||
|
||||
|
||||
// if we ask for binary data PHP munges it, so we
|
||||
// request base64 return value. We squeeze out the
|
||||
// redundancy and useless ==CRLF by hashing...
|
||||
if ($sBase64RandomBits)
|
||||
{
|
||||
//echo "Random bits got from CAPICOM.Utilities.1<br/>\n";
|
||||
$sRandomBits = md5($sBase64RandomBits, TRUE);
|
||||
$sRandomBits = md5($sBase64RandomBits, TRUE);
|
||||
}
|
||||
}
|
||||
catch (Exception $ex)
|
||||
@@ -182,10 +183,10 @@ class SimpleCrypt
|
||||
{
|
||||
$sRandomBits .= sprintf('%04x', mt_rand(0, 65535));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
return $sRandomBits;
|
||||
return $sRandomBits;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,7 +222,7 @@ class SimpleCryptSimpleEngine implements CryptEngine
|
||||
$char = chr(ord($char)+ord($keychar));
|
||||
$result.=$char;
|
||||
}
|
||||
return $result;
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function Decrypt($key, $encrypted_data)
|
||||
@@ -235,7 +236,7 @@ class SimpleCryptSimpleEngine implements CryptEngine
|
||||
$result.=$char;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -258,10 +259,13 @@ class SimpleCryptMcryptEngine implements CryptEngine
|
||||
{
|
||||
$this->td = mcrypt_module_open($this->alg,'','cbc','');
|
||||
}
|
||||
|
||||
|
||||
public function Encrypt($key, $sString)
|
||||
{
|
||||
$iv = mcrypt_create_iv (mcrypt_enc_get_iv_size($this->td), MCRYPT_RAND_URANDOM); // MCRYPT_RAND_URANDOM is now useable since itop requires php >= 5.6
|
||||
$iv = mcrypt_create_iv (mcrypt_enc_get_iv_size($this->td), MCRYPT_DEV_URANDOM); // MCRYPT_DEV_URANDOM is now useable since itop requires php >= 5.6
|
||||
if (false === $iv) {
|
||||
throw new Exception('IV generation failed');
|
||||
}
|
||||
mcrypt_generic_init($this->td, $key, $iv);
|
||||
if (empty($sString))
|
||||
{
|
||||
@@ -275,7 +279,7 @@ class SimpleCryptMcryptEngine implements CryptEngine
|
||||
public function Decrypt($key, $encrypted_data)
|
||||
{
|
||||
$iv = substr($encrypted_data, 0, mcrypt_enc_get_iv_size($this->td));
|
||||
$string = substr($encrypted_data, mcrypt_enc_get_iv_size($this->td));
|
||||
$string = substr($encrypted_data, mcrypt_enc_get_iv_size($this->td));
|
||||
$r = mcrypt_generic_init($this->td, $key, $iv);
|
||||
if (($r < 0) || ($r === false))
|
||||
{
|
||||
@@ -288,7 +292,7 @@ class SimpleCryptMcryptEngine implements CryptEngine
|
||||
}
|
||||
return $decrypted_data;
|
||||
}
|
||||
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
mcrypt_module_close($this->td);
|
||||
|
||||
@@ -57,7 +57,7 @@ abstract class TagSetFieldData extends cmdbAbstractObject
|
||||
"default_value" => '',
|
||||
"is_null_allowed" => false,
|
||||
"depends_on" => array(),
|
||||
"validation_pattern" => '^[a-zA-Z][a-zA-Z0-9]{3,}$',
|
||||
"validation_pattern" => '^[a-zA-Z][a-zA-Z0-9]{2,}$',
|
||||
)));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("label", array(
|
||||
"allowed_values" => null,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Beware the version number MUST be enclosed with quotes otherwise v2.3.0 becomes v2 0.3 .0
|
||||
$version: "v2.6.1";
|
||||
$version: "v2.6.3";
|
||||
|
||||
// Base colors
|
||||
$gray-base: #000 !default;
|
||||
|
||||
@@ -343,10 +343,10 @@ a.small_action {
|
||||
padding-left: 5px;
|
||||
padding-top: 2px;
|
||||
padding-bottom: 2px;
|
||||
background: #ea7d1e url(../images/actions_left.png?v=v2.6.1) no-repeat left;
|
||||
background: #ea7d1e url(../images/actions_left.png?v=v2.6.3) no-repeat left;
|
||||
}
|
||||
.actions_details span {
|
||||
background: url(../images/actions_right.png?v=v2.6.1) no-repeat right;
|
||||
background: url(../images/actions_right.png?v=v2.6.3) no-repeat right;
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
padding-top: 2px;
|
||||
@@ -520,7 +520,7 @@ div.actions_menu > ul {
|
||||
nowidth: 70px;
|
||||
padding-left: 5px;
|
||||
/* Nasty work-around for IE... en attendant mieux */
|
||||
background: #ea7d1e url(../images/actions_left.png?v=v2.6.1) no-repeat top left;
|
||||
background: #ea7d1e url(../images/actions_left.png?v=v2.6.3) no-repeat top left;
|
||||
cursor: pointer;
|
||||
margin: 0;
|
||||
}
|
||||
@@ -532,7 +532,7 @@ div.actions_menu > ul > li {
|
||||
height: 17px;
|
||||
padding-right: 16px;
|
||||
padding-left: 4px;
|
||||
background: url(../images/actions_right.png?v=v2.6.1) no-repeat top right transparent;
|
||||
background: url(../images/actions_right.png?v=v2.6.3) no-repeat top right transparent;
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
vertical-align: middle;
|
||||
@@ -678,7 +678,7 @@ td a.dp-choose-date, a.dp-choose-date, td a.dp-choose-date:hover, a.dp-choose-da
|
||||
display: block;
|
||||
text-indent: -2000px;
|
||||
overflow: hidden;
|
||||
background: url(../images/calendar.png?v=v2.6.1) no-repeat;
|
||||
background: url(../images/calendar.png?v=v2.6.3) no-repeat;
|
||||
}
|
||||
td a.dp-choose-date.dp-disabled, a.dp-choose-date.dp-disabled {
|
||||
background-position: 0 -20px;
|
||||
@@ -1332,19 +1332,19 @@ input.dp-applied {
|
||||
}
|
||||
/* Beware: IE6 does not support multiple selector with multiple classes, only the last class is used */
|
||||
table.listResults tr.odd td.truncated, table.listResults tr td.truncated, .wizContainer table.listResults tr.odd td.truncated, .wizContainer table.listResults tr td.truncated {
|
||||
background: url(../images/truncated.png?v=v2.6.1) bottom repeat-x;
|
||||
background: url(../images/truncated.png?v=v2.6.3) bottom repeat-x;
|
||||
}
|
||||
/* Beware: IE6 does not support multiple selector with multiple classes, only the last class is used */
|
||||
table.listResults tr.even td.truncated, .wizContainer table.listResults tr.even td.truncated {
|
||||
background: #f9f9f1 url(../images/truncated.png?v=v2.6.1) bottom repeat-x;
|
||||
background: #f9f9f1 url(../images/truncated.png?v=v2.6.3) bottom repeat-x;
|
||||
}
|
||||
/* Beware: IE6 does not support multiple selector with multiple classes, only the last class is used */
|
||||
table.listResults tr.even td.hover.truncated, .wizContainer table.listResults tr.even td.hover.truncated {
|
||||
background: #fdf5d0 url(../images/truncated.png?v=v2.6.1) bottom repeat-x;
|
||||
background: #fdf5d0 url(../images/truncated.png?v=v2.6.3) bottom repeat-x;
|
||||
}
|
||||
/* Beware: IE6 does not support multiple selector with multiple classes, only the last class is used */
|
||||
table.listResults tr.odd td.hover.truncated, table.listResults tr td.hover.truncated, .wizContainer table.listResults tr.odd td.hover.truncated, .wizContainer table.listResults tr td.hover.truncated {
|
||||
background: #fdf5d0 url(../images/truncated.png?v=v2.6.1) bottom repeat-x;
|
||||
background: #fdf5d0 url(../images/truncated.png?v=v2.6.3) bottom repeat-x;
|
||||
}
|
||||
table.listResults.truncated {
|
||||
border-bottom: 0;
|
||||
@@ -1452,7 +1452,7 @@ div#logo {
|
||||
div#logo div {
|
||||
height: 88px;
|
||||
width: 244px;
|
||||
background: url(../images/itop-logo-2.png?v=v2.6.1) left no-repeat;
|
||||
background: url(../images/itop-logo-2.png?v=v2.6.3) left no-repeat;
|
||||
}
|
||||
#left-pane .ui-layout-north {
|
||||
overflow: hidden;
|
||||
@@ -1544,7 +1544,7 @@ div#logo div {
|
||||
}
|
||||
#global-search-image {
|
||||
vertical-align: middle;
|
||||
background: url(../images/search.png?v=v2.6.1) center center no-repeat;
|
||||
background: url(../images/search.png?v=v2.6.3) center center no-repeat;
|
||||
display: inline-block;
|
||||
width: 28px;
|
||||
height: 30px;
|
||||
@@ -1573,7 +1573,7 @@ span.ui-icon {
|
||||
margin: 0 2px;
|
||||
}
|
||||
.ui-layout-button-pin-down {
|
||||
background: url(../images/splitter-bkg.png?v=v2.6.1) transparent;
|
||||
background: url(../images/splitter-bkg.png?v=v2.6.3) transparent;
|
||||
width: 16px;
|
||||
background-position: -144px -144px;
|
||||
}
|
||||
@@ -1830,6 +1830,9 @@ fieldset .details > .field_container {
|
||||
padding-left: 0.4em;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.field_container > div > div.field_value .attribute-edit .form-field-container .form-field-content > .form_validation, .field_container > div > div.field_value .attribute-edit .form-field-container .form-field-content > .field_status {
|
||||
display: inline;
|
||||
}
|
||||
.field_container > div > div.field_value .attribute-edit .field_input_zone {
|
||||
width: 100%;
|
||||
/* auto; */
|
||||
@@ -2089,7 +2092,7 @@ img.prev, img.first, img.next, img.last {
|
||||
}
|
||||
div.actions_button {
|
||||
float: right;
|
||||
background: #ea7d1e url("../images/actions_left.png?v=v2.6.1") no-repeat scroll left top;
|
||||
background: #ea7d1e url("../images/actions_left.png?v=v2.6.3") no-repeat scroll left top;
|
||||
padding-left: 5px;
|
||||
margin-top: 0;
|
||||
margin-right: 10px;
|
||||
@@ -2097,7 +2100,7 @@ div.actions_button {
|
||||
vertical-align: middle;
|
||||
}
|
||||
div.actions_button a, .actions_button a:hover, .actions_button a:visited {
|
||||
background: #ea7d1e url(../images/actions_bkg.png?v=v2.6.1) no-repeat scroll right top;
|
||||
background: #ea7d1e url(../images/actions_bkg.png?v=v2.6.3) no-repeat scroll right top;
|
||||
color: #fff;
|
||||
padding-right: 8px;
|
||||
cursor: pointer;
|
||||
@@ -2121,10 +2124,10 @@ select#org_id {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
.dragHover {
|
||||
background: url(./ui-lightness/images/ui-bg_diagonals-thick_20_666666_40x40.png?v=v2.6.1);
|
||||
background: url(./ui-lightness/images/ui-bg_diagonals-thick_20_666666_40x40.png?v=v2.6.3);
|
||||
}
|
||||
.edit_mode .dashlet {
|
||||
background: url(./ui-lightness/images/ui-bg_diagonals-thick_20_666666_40x40.png?v=v2.6.1);
|
||||
background: url(./ui-lightness/images/ui-bg_diagonals-thick_20_666666_40x40.png?v=v2.6.3);
|
||||
padding: 5px;
|
||||
margin: 0;
|
||||
position: relative;
|
||||
@@ -2169,7 +2172,7 @@ table.prop_table {
|
||||
top: 0;
|
||||
right: 0;
|
||||
z-index: 10;
|
||||
background: transparent url(../images/delete.png?v=v2.6.1) no-repeat center;
|
||||
background: transparent url(../images/delete.png?v=v2.6.3) no-repeat center;
|
||||
}
|
||||
td.prop_value {
|
||||
text-align: left;
|
||||
@@ -2390,17 +2393,17 @@ a.summary, a.summary:hover {
|
||||
}
|
||||
.message_info {
|
||||
border: 1px solid #993;
|
||||
background: url(../images/info-mini.png?v=v2.6.1) 1em 1em no-repeat #ffc;
|
||||
background: url(../images/info-mini.png?v=v2.6.3) 1em 1em no-repeat #ffc;
|
||||
padding-left: 3em;
|
||||
}
|
||||
.message_ok {
|
||||
border: 1px solid #393;
|
||||
background: url(../images/ok.png?v=v2.6.1) 1em 1em no-repeat #cfc;
|
||||
background: url(../images/ok.png?v=v2.6.3) 1em 1em no-repeat #cfc;
|
||||
padding-left: 3em;
|
||||
}
|
||||
.message_error {
|
||||
border: 1px solid #933;
|
||||
background: url(../images/error.png?v=v2.6.1) 1em 1em no-repeat #fcc;
|
||||
background: url(../images/error.png?v=v2.6.3) 1em 1em no-repeat #fcc;
|
||||
padding-left: 3em;
|
||||
}
|
||||
.fg-menu a img {
|
||||
@@ -2531,18 +2534,18 @@ div.explain-printable {
|
||||
}
|
||||
#hiddeable_chapters .ui-tabs .ui-tabs-nav li.hideable-chapter span {
|
||||
padding-left: 20px;
|
||||
background: url(../images/eye-open-555.png?v=v2.6.1) 2px center no-repeat;
|
||||
background: url(../images/eye-open-555.png?v=v2.6.3) 2px center no-repeat;
|
||||
}
|
||||
#hiddeable_chapters .ui-tabs .ui-tabs-nav li.hideable-chapter.strikethrough span {
|
||||
text-decoration: line-through;
|
||||
background: url(../images/eye-closed-555.png?v=v2.6.1) 2px center no-repeat;
|
||||
background: url(../images/eye-closed-555.png?v=v2.6.3) 2px center no-repeat;
|
||||
}
|
||||
.printable-version legend {
|
||||
padding-left: 26px;
|
||||
background: #1c94c4 url(../images/eye-open-fff.png?v=v2.6.1) 8px center no-repeat;
|
||||
background: #1c94c4 url(../images/eye-open-fff.png?v=v2.6.3) 8px center no-repeat;
|
||||
}
|
||||
.printable-version .strikethrough legend {
|
||||
background: #1c94c4 url(../images/eye-closed-fff.png?v=v2.6.1) 8px center no-repeat;
|
||||
background: #1c94c4 url(../images/eye-closed-fff.png?v=v2.6.3) 8px center no-repeat;
|
||||
}
|
||||
.printable-version fieldset.strikethrough span {
|
||||
display: none;
|
||||
@@ -2693,7 +2696,7 @@ span.search-button, span.refresh-button {
|
||||
#itop-breadcrumb .breadcrumb-item a::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
background-image: url(../images/breadcrumb-separator.png?v=v2.6.1);
|
||||
background-image: url(../images/breadcrumb-separator.png?v=v2.6.3);
|
||||
background-repeat: no-repeat;
|
||||
width: 8px;
|
||||
height: 16px;
|
||||
|
||||
@@ -2115,6 +2115,11 @@ fieldset .details>.field_container {
|
||||
padding-left: 0.4em;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.form-field-container .form-field-content{
|
||||
> .form_validation, > .field_status {
|
||||
display: inline;
|
||||
}
|
||||
}
|
||||
|
||||
.field_input_zone{
|
||||
width: 100%; /* auto; */
|
||||
|
||||
@@ -1,2 +1,20 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2013-2020 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
* 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
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* iTop is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
*/
|
||||
|
||||
echo 'Access denied';
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Localized data
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2018 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'authent-external/2.6.1',
|
||||
'authent-external/2.6.3',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
|
||||
38
datamodels/2.x/authent-external/sk.dict.authent-external.php
Normal file
38
datamodels/2.x/authent-external/sk.dict.authent-external.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
/**
|
||||
* Localized data
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2018 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
* 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
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* iTop is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
// Dictionnay conventions
|
||||
// Class:<class_name>
|
||||
// Class:<class_name>+
|
||||
// Class:<class_name>/Attribute:<attribute_code>
|
||||
// Class:<class_name>/Attribute:<attribute_code>+
|
||||
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>
|
||||
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>+
|
||||
// Class:<class_name>/Stimulus:<stimulus_code>
|
||||
// Class:<class_name>/Stimulus:<stimulus_code>+
|
||||
//
|
||||
// Class: UserExternal
|
||||
//
|
||||
Dict::Add('SK SK', 'Slovak', 'Slovenčina', array(
|
||||
'Class:UserExternal' => 'Externý užívateľ',
|
||||
'Class:UserExternal+' => '',
|
||||
));
|
||||
@@ -2,6 +2,7 @@
|
||||
/**
|
||||
* Localized data
|
||||
*
|
||||
* @author Robert Deng <denglx@gmail.com>
|
||||
* @copyright Copyright (C) 2010-2018 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*
|
||||
|
||||
@@ -38,4 +38,6 @@
|
||||
Dict::Add('CS CZ', 'Czech', 'Čeština', array(
|
||||
'Class:UserLDAP' => 'LDAP uživatel',
|
||||
'Class:UserLDAP+' => 'Uživatel ověřen přes LDAP',
|
||||
'Class:UserLDAP/Attribute:password' => 'Heslo',
|
||||
'Class:UserLDAP/Attribute:password+' => '',
|
||||
));
|
||||
|
||||
@@ -16,11 +16,13 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
/**
|
||||
* @author Erik Bøg <erik@boegmoeller.dk>
|
||||
* @author Erik Bøg <erik@boegmoeller.dk>
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @licence http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
Dict::Add('DA DA', 'Danish', 'Dansk', array(
|
||||
'Class:UserLDAP' => 'LDAP-Bruger',
|
||||
'Class:UserLDAP+' => 'Bruger der godkendes via LDAP',
|
||||
'Class:UserLDAP/Attribute:password' => 'Password',
|
||||
'Class:UserLDAP/Attribute:password+' => 'Brugerens password',
|
||||
));
|
||||
|
||||
@@ -25,4 +25,6 @@
|
||||
Dict::Add('DE DE', 'German', 'Deutsch', array(
|
||||
'Class:UserLDAP' => 'LDAP-Benutzer',
|
||||
'Class:UserLDAP+' => 'Benutzer, der über LDAP authentifiziert wird',
|
||||
'Class:UserLDAP/Attribute:password' => 'Passwort',
|
||||
'Class:UserLDAP/Attribute:password+' => 'Benutzerpasswort',
|
||||
));
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Localized data
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2018 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
@@ -38,4 +38,6 @@
|
||||
Dict::Add('EN US', 'English', 'English', array(
|
||||
'Class:UserLDAP' => 'LDAP user',
|
||||
'Class:UserLDAP+' => 'User authentified by LDAP',
|
||||
'Class:UserLDAP/Attribute:password' => 'Password',
|
||||
'Class:UserLDAP/Attribute:password+' => 'user authentication string',
|
||||
));
|
||||
|
||||
@@ -37,4 +37,6 @@
|
||||
Dict::Add('ES CR', 'Spanish', 'Español, Castellaño', array(
|
||||
'Class:UserLDAP' => 'Usuario LDAP',
|
||||
'Class:UserLDAP+' => 'Usuario Autenticado vía LDAP',
|
||||
'Class:UserLDAP/Attribute:password' => 'Contraseña',
|
||||
'Class:UserLDAP/Attribute:password+' => 'Contraseña',
|
||||
));
|
||||
|
||||
@@ -22,4 +22,6 @@
|
||||
Dict::Add('FR FR', 'French', 'Français', array(
|
||||
'Class:UserLDAP' => 'Utilisateur LDAP',
|
||||
'Class:UserLDAP+' => 'Utilisateur authentifié par un serveur LDAP',
|
||||
'Class:UserLDAP/Attribute:password' => 'Mot de passe LDAP',
|
||||
'Class:UserLDAP/Attribute:password+' => '',
|
||||
));
|
||||
|
||||
@@ -22,4 +22,6 @@
|
||||
Dict::Add('HU HU', 'Hungarian', 'Magyar', array(
|
||||
'Class:UserLDAP' => 'LDAP felhasználó',
|
||||
'Class:UserLDAP+' => '',
|
||||
'Class:UserLDAP/Attribute:password' => 'Jelszó',
|
||||
'Class:UserLDAP/Attribute:password+' => '',
|
||||
));
|
||||
|
||||
@@ -36,4 +36,6 @@
|
||||
Dict::Add('IT IT', 'Italian', 'Italiano', array(
|
||||
'Class:UserLDAP' => 'Utente LDAP',
|
||||
'Class:UserLDAP+' => 'Utente autenticato da LDAP',
|
||||
'Class:UserLDAP/Attribute:password' => 'Password',
|
||||
'Class:UserLDAP/Attribute:password+' => 'user authentication string',
|
||||
));
|
||||
|
||||
@@ -16,11 +16,13 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
/**
|
||||
* @author Hirofumi Kosaka <kosaka@rworks.jp>
|
||||
* @author Hirofumi Kosaka <kosaka@rworks.jp>
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @licence http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:UserLDAP' => 'LDAP ユーザー',
|
||||
'Class:UserLDAP+' => 'LDAP認証ユーザー',
|
||||
'Class:UserLDAP/Attribute:password' => 'パスワード',
|
||||
'Class:UserLDAP/Attribute:password+' => '認証文字列',
|
||||
));
|
||||
|
||||
@@ -9,7 +9,7 @@ if (function_exists('ldap_connect'))
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'authent-ldap/2.6.1',
|
||||
'authent-ldap/2.6.3',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
|
||||
@@ -36,4 +36,6 @@
|
||||
Dict::Add('NL NL', 'Dutch', 'Nederlands', array(
|
||||
'Class:UserLDAP' => 'LDAP-gebruiker',
|
||||
'Class:UserLDAP+' => 'Gebruiker aangemeld via LDAP',
|
||||
'Class:UserLDAP/Attribute:password' => 'Password~~',
|
||||
'Class:UserLDAP/Attribute:password+' => 'user authentication string~~',
|
||||
));
|
||||
|
||||
@@ -22,4 +22,6 @@
|
||||
Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
|
||||
'Class:UserLDAP' => 'Usuário externo via LDAP',
|
||||
'Class:UserLDAP+' => '',
|
||||
'Class:UserLDAP/Attribute:password' => 'Senha',
|
||||
'Class:UserLDAP/Attribute:password+' => '',
|
||||
));
|
||||
|
||||
@@ -14,4 +14,6 @@
|
||||
Dict::Add('RU RU', 'Russian', 'Русский', array(
|
||||
'Class:UserLDAP' => 'Пользователь LDAP',
|
||||
'Class:UserLDAP+' => 'Пользователь, аутентифицируемый через LDAP',
|
||||
'Class:UserLDAP/Attribute:password' => 'Пароль',
|
||||
'Class:UserLDAP/Attribute:password+' => 'Строка аутентификации пользователя',
|
||||
));
|
||||
|
||||
40
datamodels/2.x/authent-ldap/sk.dict.authent-ldap.php
Normal file
40
datamodels/2.x/authent-ldap/sk.dict.authent-ldap.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
/**
|
||||
* Localized data
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2018 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
* 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
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* iTop is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
// Dictionnay conventions
|
||||
// Class:<class_name>
|
||||
// Class:<class_name>+
|
||||
// Class:<class_name>/Attribute:<attribute_code>
|
||||
// Class:<class_name>/Attribute:<attribute_code>+
|
||||
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>
|
||||
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>+
|
||||
// Class:<class_name>/Stimulus:<stimulus_code>
|
||||
// Class:<class_name>/Stimulus:<stimulus_code>+
|
||||
//
|
||||
// Class: UserLDAP
|
||||
//
|
||||
Dict::Add('SK SK', 'Slovak', 'Slovenčina', array(
|
||||
'Class:UserLDAP' => 'LDAP užívateľ',
|
||||
'Class:UserLDAP+' => '',
|
||||
'Class:UserLDAP/Attribute:password' => 'Heslo',
|
||||
'Class:UserLDAP/Attribute:password+' => '',
|
||||
));
|
||||
@@ -37,4 +37,6 @@
|
||||
Dict::Add('TR TR', 'Turkish', 'Türkçe', array(
|
||||
'Class:UserLDAP' => 'LDAP kullanıcısı',
|
||||
'Class:UserLDAP+' => 'Yetki kontrolü LDAP tarafından yapılan',
|
||||
'Class:UserLDAP/Attribute:password' => 'Şifre',
|
||||
'Class:UserLDAP/Attribute:password+' => 'şifre',
|
||||
));
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
/**
|
||||
* Localized data
|
||||
*
|
||||
* @author Robert Deng <denglx@gmail.com>
|
||||
* @copyright Copyright (C) 2010-2018 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*
|
||||
@@ -35,4 +36,6 @@
|
||||
Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
'Class:UserLDAP' => 'LDAP 用户',
|
||||
'Class:UserLDAP+' => '用户身份由LDAP 认证',
|
||||
'Class:UserLDAP/Attribute:password' => '密码',
|
||||
'Class:UserLDAP/Attribute:password+' => '用于验证用户身份的字符串',
|
||||
));
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Localized data
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2018 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'authent-local/2.6.1',
|
||||
'authent-local/2.6.3',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
|
||||
40
datamodels/2.x/authent-local/sk.dict.authent-local.php
Normal file
40
datamodels/2.x/authent-local/sk.dict.authent-local.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
/**
|
||||
* Localized data
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2018 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
* 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
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* iTop is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
// Dictionnay conventions
|
||||
// Class:<class_name>
|
||||
// Class:<class_name>+
|
||||
// Class:<class_name>/Attribute:<attribute_code>
|
||||
// Class:<class_name>/Attribute:<attribute_code>+
|
||||
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>
|
||||
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>+
|
||||
// Class:<class_name>/Stimulus:<stimulus_code>
|
||||
// Class:<class_name>/Stimulus:<stimulus_code>+
|
||||
//
|
||||
// Class: UserLocal
|
||||
//
|
||||
Dict::Add('SK SK', 'Slovak', 'Slovenčina', array(
|
||||
'Class:UserLocal' => 'iTop užívateľ',
|
||||
'Class:UserLocal+' => '',
|
||||
'Class:UserLocal/Attribute:password' => 'Heslo',
|
||||
'Class:UserLocal/Attribute:password+' => '',
|
||||
));
|
||||
@@ -2,6 +2,7 @@
|
||||
/**
|
||||
* Localized data
|
||||
*
|
||||
* @author Robert Deng <denglx@gmail.com>
|
||||
* @copyright Copyright (C) 2010-2018 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*
|
||||
|
||||
83
datamodels/2.x/combodo-db-tools/cs.dict.combodo-db-tools.php
Normal file
83
datamodels/2.x/combodo-db-tools/cs.dict.combodo-db-tools.php
Normal file
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2013-2020 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
* 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
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* iTop is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
*/
|
||||
// Database inconsistencies
|
||||
Dict::Add('CS CZ', 'Czech', 'Čeština', array(
|
||||
// Dictionary entries go here
|
||||
'Menu:DBToolsMenu' => 'DB Tools~~',
|
||||
'DBTools:Class' => 'Class~~',
|
||||
'DBTools:Title' => 'Database Maintenance Tools~~',
|
||||
'DBTools:ErrorsFound' => 'Errors Found~~',
|
||||
'DBTools:Error' => 'Error~~',
|
||||
'DBTools:Count' => 'Count~~',
|
||||
'DBTools:SQLquery' => 'SQL query~~',
|
||||
'DBTools:FixitSQLquery' => 'SQL query To Fix it (indication)~~',
|
||||
'DBTools:SQLresult' => 'SQL result~~',
|
||||
'DBTools:NoError' => 'The database is OK~~',
|
||||
'DBTools:HideIds' => 'Error List~~',
|
||||
'DBTools:ShowIds' => 'Detailed view~~',
|
||||
'DBTools:ShowReport' => 'Report~~',
|
||||
'DBTools:IntegrityCheck' => 'Integrity check~~',
|
||||
'DBTools:FetchCheck' => 'Fetch Check (long)~~',
|
||||
|
||||
'DBTools:Analyze' => 'Analyze~~',
|
||||
'DBTools:Details' => 'Show Details~~',
|
||||
'DBTools:ShowAll' => 'Show All Errors~~',
|
||||
|
||||
'DBTools:Inconsistencies' => 'Database inconsistencies~~',
|
||||
|
||||
'DBAnalyzer-Integrity-OrphanRecord' => 'Orphan record in `%1$s`, it should have its counterpart in table `%2$s`~~',
|
||||
'DBAnalyzer-Integrity-InvalidExtKey' => 'Invalid external key %1$s (column: `%2$s.%3$s`)~~',
|
||||
'DBAnalyzer-Integrity-MissingExtKey' => 'Missing external key %1$s (column: `%2$s.%3$s`)~~',
|
||||
'DBAnalyzer-Integrity-InvalidValue' => 'Invalid value for %1$s (column: `%2$s.%3$s`)~~',
|
||||
'DBAnalyzer-Integrity-UsersWithoutProfile' => 'Some user accounts have no profile at all~~',
|
||||
'DBAnalyzer-Fetch-Count-Error' => 'Fetch count error in `%1$s`, %2$d entries fetched / %3$d counted~~',
|
||||
));
|
||||
|
||||
// Database Info
|
||||
Dict::Add('CS CZ', 'Czech', 'Čeština', array(
|
||||
'DBTools:DatabaseInfo' => 'Database Information~~',
|
||||
'DBTools:Base' => 'Base~~',
|
||||
'DBTools:Size' => 'Size~~',
|
||||
));
|
||||
|
||||
// Lost attachments
|
||||
Dict::Add('CS CZ', 'Czech', 'Čeština', array(
|
||||
'DBTools:LostAttachments' => 'Lost attachments~~',
|
||||
'DBTools:LostAttachments:Disclaimer' => 'Here you can search your database for lost or misplaced attachments. This is NOT a data recovery tool, is does not retrieve deleted data.~~',
|
||||
|
||||
'DBTools:LostAttachments:Button:Analyze' => 'Analyze~~',
|
||||
'DBTools:LostAttachments:Button:Restore' => 'Restore~~',
|
||||
'DBTools:LostAttachments:Button:Restore:Confirm' => 'This action cannot be undone, please confirm that you want to restore the selected files.~~',
|
||||
'DBTools:LostAttachments:Button:Busy' => 'Please wait...~~',
|
||||
|
||||
'DBTools:LostAttachments:Step:Analyze' => 'First, search for lost/misplaced attachments by analyzing the database.~~',
|
||||
|
||||
'DBTools:LostAttachments:Step:AnalyzeResults' => 'Analyze results:~~',
|
||||
'DBTools:LostAttachments:Step:AnalyzeResults:None' => 'Great! Every thing seems to be at the right place.~~',
|
||||
'DBTools:LostAttachments:Step:AnalyzeResults:Some' => 'Some attachments (%1$d) seem to be misplaced. Take a look at the following list and check the ones you would like to move.~~',
|
||||
'DBTools:LostAttachments:Step:AnalyzeResults:Item:Filename' => 'Filename~~',
|
||||
'DBTools:LostAttachments:Step:AnalyzeResults:Item:CurrentLocation' => 'Current location~~',
|
||||
'DBTools:LostAttachments:Step:AnalyzeResults:Item:TargetLocation' => 'Move to...~~',
|
||||
|
||||
'DBTools:LostAttachments:Step:RestoreResults' => 'Restore results:~~',
|
||||
'DBTools:LostAttachments:Step:RestoreResults:Results' => '%1$d/%2$d attachments were restored.~~',
|
||||
|
||||
'DBTools:LostAttachments:StoredAsInlineImage' => 'Stored as inline image~~',
|
||||
'DBTools:LostAttachments:History' => 'Attachment "%1$s" restored with DB tools~~'
|
||||
));
|
||||
83
datamodels/2.x/combodo-db-tools/da.dict.combodo-db-tools.php
Normal file
83
datamodels/2.x/combodo-db-tools/da.dict.combodo-db-tools.php
Normal file
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2013-2020 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
* 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
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* iTop is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
*/
|
||||
// Database inconsistencies
|
||||
Dict::Add('DA DA', 'Danish', 'Dansk', array(
|
||||
// Dictionary entries go here
|
||||
'Menu:DBToolsMenu' => 'DB Tools~~',
|
||||
'DBTools:Class' => 'Class~~',
|
||||
'DBTools:Title' => 'Database Maintenance Tools~~',
|
||||
'DBTools:ErrorsFound' => 'Errors Found~~',
|
||||
'DBTools:Error' => 'Error~~',
|
||||
'DBTools:Count' => 'Count~~',
|
||||
'DBTools:SQLquery' => 'SQL query~~',
|
||||
'DBTools:FixitSQLquery' => 'SQL query To Fix it (indication)~~',
|
||||
'DBTools:SQLresult' => 'SQL result~~',
|
||||
'DBTools:NoError' => 'The database is OK~~',
|
||||
'DBTools:HideIds' => 'Error List~~',
|
||||
'DBTools:ShowIds' => 'Detailed view~~',
|
||||
'DBTools:ShowReport' => 'Report~~',
|
||||
'DBTools:IntegrityCheck' => 'Integrity check~~',
|
||||
'DBTools:FetchCheck' => 'Fetch Check (long)~~',
|
||||
|
||||
'DBTools:Analyze' => 'Analyze~~',
|
||||
'DBTools:Details' => 'Show Details~~',
|
||||
'DBTools:ShowAll' => 'Show All Errors~~',
|
||||
|
||||
'DBTools:Inconsistencies' => 'Database inconsistencies~~',
|
||||
|
||||
'DBAnalyzer-Integrity-OrphanRecord' => 'Orphan record in `%1$s`, it should have its counterpart in table `%2$s`~~',
|
||||
'DBAnalyzer-Integrity-InvalidExtKey' => 'Invalid external key %1$s (column: `%2$s.%3$s`)~~',
|
||||
'DBAnalyzer-Integrity-MissingExtKey' => 'Missing external key %1$s (column: `%2$s.%3$s`)~~',
|
||||
'DBAnalyzer-Integrity-InvalidValue' => 'Invalid value for %1$s (column: `%2$s.%3$s`)~~',
|
||||
'DBAnalyzer-Integrity-UsersWithoutProfile' => 'Some user accounts have no profile at all~~',
|
||||
'DBAnalyzer-Fetch-Count-Error' => 'Fetch count error in `%1$s`, %2$d entries fetched / %3$d counted~~',
|
||||
));
|
||||
|
||||
// Database Info
|
||||
Dict::Add('DA DA', 'Danish', 'Dansk', array(
|
||||
'DBTools:DatabaseInfo' => 'Database Information~~',
|
||||
'DBTools:Base' => 'Base~~',
|
||||
'DBTools:Size' => 'Size~~',
|
||||
));
|
||||
|
||||
// Lost attachments
|
||||
Dict::Add('DA DA', 'Danish', 'Dansk', array(
|
||||
'DBTools:LostAttachments' => 'Lost attachments~~',
|
||||
'DBTools:LostAttachments:Disclaimer' => 'Here you can search your database for lost or misplaced attachments. This is NOT a data recovery tool, is does not retrieve deleted data.~~',
|
||||
|
||||
'DBTools:LostAttachments:Button:Analyze' => 'Analyze~~',
|
||||
'DBTools:LostAttachments:Button:Restore' => 'Restore~~',
|
||||
'DBTools:LostAttachments:Button:Restore:Confirm' => 'This action cannot be undone, please confirm that you want to restore the selected files.~~',
|
||||
'DBTools:LostAttachments:Button:Busy' => 'Please wait...~~',
|
||||
|
||||
'DBTools:LostAttachments:Step:Analyze' => 'First, search for lost/misplaced attachments by analyzing the database.~~',
|
||||
|
||||
'DBTools:LostAttachments:Step:AnalyzeResults' => 'Analyze results:~~',
|
||||
'DBTools:LostAttachments:Step:AnalyzeResults:None' => 'Great! Every thing seems to be at the right place.~~',
|
||||
'DBTools:LostAttachments:Step:AnalyzeResults:Some' => 'Some attachments (%1$d) seem to be misplaced. Take a look at the following list and check the ones you would like to move.~~',
|
||||
'DBTools:LostAttachments:Step:AnalyzeResults:Item:Filename' => 'Filename~~',
|
||||
'DBTools:LostAttachments:Step:AnalyzeResults:Item:CurrentLocation' => 'Current location~~',
|
||||
'DBTools:LostAttachments:Step:AnalyzeResults:Item:TargetLocation' => 'Move to...~~',
|
||||
|
||||
'DBTools:LostAttachments:Step:RestoreResults' => 'Restore results:~~',
|
||||
'DBTools:LostAttachments:Step:RestoreResults:Results' => '%1$d/%2$d attachments were restored.~~',
|
||||
|
||||
'DBTools:LostAttachments:StoredAsInlineImage' => 'Stored as inline image~~',
|
||||
'DBTools:LostAttachments:History' => 'Attachment "%1$s" restored with DB tools~~'
|
||||
));
|
||||
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.0">
|
||||
<menus>
|
||||
<menu id="AdminTools" xsi:type="MenuGroup" _delta="define_if_not_exists">
|
||||
<rank>80</rank>
|
||||
<enable_admin_only>1</enable_admin_only>
|
||||
</menu>
|
||||
<menu id="DBToolsMenu" xsi:type="WebPageMenuNode" _delta="define">
|
||||
<rank>15</rank>
|
||||
<parent>AdminTools</parent>
|
||||
<url>$pages/exec.php?exec_module=combodo-db-tools&exec_page=dbtools.php&c[menu]=DBToolsMenu</url>
|
||||
<enable_admin_only>1</enable_admin_only>
|
||||
</menu>
|
||||
</menus>
|
||||
</itop_design>
|
||||
355
datamodels/2.x/combodo-db-tools/db_analyzer.class.inc.php
Normal file
355
datamodels/2.x/combodo-db-tools/db_analyzer.class.inc.php
Normal file
@@ -0,0 +1,355 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2013-2020 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
* 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
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* iTop is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
*/
|
||||
|
||||
class DatabaseAnalyzer
|
||||
{
|
||||
var $iTimeLimitPerOperation;
|
||||
|
||||
public function __construct($iTimeLimitPerOperation = null)
|
||||
{
|
||||
$this->iTimeLimitPerOperation = $iTimeLimitPerOperation;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $sSelWrongRecs
|
||||
* @param $sFixitRequest
|
||||
* @param $sErrorDesc
|
||||
* @param $sClass
|
||||
* @param $aErrorsAndFixes
|
||||
*
|
||||
* @throws \MySQLException
|
||||
*/
|
||||
private function ExecQuery($sSelWrongRecs, $sFixitRequest, $sErrorDesc, $sClass, &$aErrorsAndFixes, $aValueNames = array())
|
||||
{
|
||||
if (!is_null($this->iTimeLimitPerOperation))
|
||||
{
|
||||
set_time_limit($this->iTimeLimitPerOperation);
|
||||
}
|
||||
|
||||
$aWrongRecords = CMDBSource::QueryToArray($sSelWrongRecs);
|
||||
if (count($aWrongRecords) > 0)
|
||||
{
|
||||
foreach($aWrongRecords as $aRes)
|
||||
{
|
||||
if (!isset($aErrorsAndFixes[$sClass][$sErrorDesc]))
|
||||
{
|
||||
$aErrorsAndFixes[$sClass][$sErrorDesc] = array(
|
||||
'count' => 1,
|
||||
'query' => $sSelWrongRecs,
|
||||
);
|
||||
if (!empty($sFixitRequest))
|
||||
{
|
||||
$aErrorsAndFixes[$sClass][$sErrorDesc]['fixit'] = array($sFixitRequest);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$aErrorsAndFixes[$sClass][$sErrorDesc]['count'] += 1;
|
||||
}
|
||||
if (empty($aValueNames))
|
||||
{
|
||||
$aValues = array('id' => $aRes['id']);
|
||||
}
|
||||
else
|
||||
{
|
||||
$aValues = array();
|
||||
foreach ($aValueNames as $sValueName)
|
||||
{
|
||||
$aValues[$sValueName] = $aRes[$sValueName];
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($aRes['value']))
|
||||
{
|
||||
$value = $aRes['value'];
|
||||
$aValues['value'] = $value;
|
||||
if (!isset($aErrorsAndFixes[$sClass][$sErrorDesc]['values'][$value]))
|
||||
{
|
||||
$aErrorsAndFixes[$sClass][$sErrorDesc]['values'][$value] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
$aErrorsAndFixes[$sClass][$sErrorDesc]['values'][$value] += 1;
|
||||
}
|
||||
}
|
||||
$aErrorsAndFixes[$sClass][$sErrorDesc]['res'][] = $aValues;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $aClassSelection
|
||||
* @param $iShowId
|
||||
* @return array
|
||||
* @throws CoreException
|
||||
* @throws DictExceptionMissingString
|
||||
* @throws MySQLException
|
||||
* @throws Exception
|
||||
*/
|
||||
public function CheckIntegrity($aClassSelection, $iShowId)
|
||||
{
|
||||
// Getting and setting time limit are not symetric:
|
||||
// www.php.net/manual/fr/function.set-time-limit.php#72305
|
||||
$iPreviousTimeLimit = ini_get('max_execution_time');
|
||||
|
||||
$aErrorsAndFixes = array();
|
||||
|
||||
if (empty($aClassSelection))
|
||||
{
|
||||
$aClassSelection = MetaModel::GetClasses();
|
||||
}
|
||||
else
|
||||
{
|
||||
$aClasses = $aClassSelection;
|
||||
foreach($aClasses as $sClass)
|
||||
{
|
||||
$aExpectedClasses = MetaModel::EnumChildClasses($sClass, ENUM_CHILD_CLASSES_ALL);
|
||||
$aClassSelection = array_merge($aClassSelection, $aExpectedClasses);
|
||||
}
|
||||
$aClassSelection = array_unique($aClassSelection);
|
||||
}
|
||||
|
||||
foreach($aClassSelection as $sClass)
|
||||
{
|
||||
// Check uniqueness rules
|
||||
if (method_exists('MetaModel', 'GetUniquenessRules'))
|
||||
{
|
||||
$aUniquenessRules = MetaModel::GetUniquenessRules($sClass);
|
||||
foreach ($aUniquenessRules as $sUniquenessRuleId => $aUniquenessRuleProperties)
|
||||
{
|
||||
if ($aUniquenessRuleProperties['disabled'] === true)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
$this->CheckUniquenessRule($sClass, $sUniquenessRuleId, $aUniquenessRuleProperties, $aErrorsAndFixes);
|
||||
}
|
||||
}
|
||||
|
||||
if (!MetaModel::HasTable($sClass))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
$sRootClass = MetaModel::GetRootClass($sClass);
|
||||
$sTable = MetaModel::DBGetTable($sClass);
|
||||
$sKeyField = MetaModel::DBGetKey($sClass);
|
||||
|
||||
|
||||
if (!MetaModel::IsStandaloneClass($sClass))
|
||||
{
|
||||
if (!MetaModel::IsRootClass($sClass))
|
||||
{
|
||||
$sRootTable = MetaModel::DBGetTable($sRootClass);
|
||||
$sRootKey = MetaModel::DBGetKey($sRootClass);
|
||||
$sFinalClassField = MetaModel::DBGetClassField($sRootClass);
|
||||
|
||||
$aExpectedClasses = MetaModel::EnumChildClasses($sClass, ENUM_CHILD_CLASSES_ALL);
|
||||
$sExpectedClasses = implode(",", CMDBSource::Quote($aExpectedClasses, true));
|
||||
|
||||
// Check that any record found here has its counterpart in the root table
|
||||
//
|
||||
$sSelect = "SELECT DISTINCT `$sTable`.`$sKeyField` AS id";
|
||||
$sDelete = "DELETE `$sTable`";
|
||||
$sFilter = "FROM `$sTable` LEFT JOIN `$sRootTable` ON `$sTable`.`$sKeyField` = `$sRootTable`.`$sRootKey` WHERE `$sRootTable`.`$sRootKey` IS NULL";
|
||||
$sSelWrongRecs = "$sSelect $sFilter";
|
||||
$sFixitRequest = "$sDelete $sFilter";
|
||||
$this->ExecQuery($sSelWrongRecs, $sFixitRequest, Dict::Format('DBAnalyzer-Integrity-OrphanRecord', $sTable, $sRootTable), $sClass, $aErrorsAndFixes);
|
||||
|
||||
// Check that any record found in the root table and referring to a child class
|
||||
// has its counterpart here (detect orphan nodes -root or in the middle of the hierarchy)
|
||||
//
|
||||
$sSelect = "SELECT DISTINCT `$sRootTable`.`$sRootKey` AS id";
|
||||
$sDelete = "DELETE `$sRootTable`";
|
||||
$sFilter = "FROM `$sRootTable` LEFT JOIN `$sTable` ON `$sRootTable`.`$sRootKey` = `$sTable`.`$sKeyField` WHERE `$sTable`.`$sKeyField` IS NULL AND `$sRootTable`.`$sFinalClassField` IN ($sExpectedClasses)";
|
||||
$sSelWrongRecs = "$sSelect $sFilter";
|
||||
$sFixitRequest = "$sDelete $sFilter";
|
||||
$this->ExecQuery($sSelWrongRecs, $sFixitRequest, Dict::Format('DBAnalyzer-Integrity-OrphanRecord', $sRootTable, $sTable), $sRootClass, $aErrorsAndFixes);
|
||||
}
|
||||
}
|
||||
|
||||
foreach(MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef)
|
||||
{
|
||||
// Skip this attribute if not defined in this table
|
||||
if (!MetaModel::IsAttributeOrigin($sClass, $sAttCode))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($oAttDef->IsExternalKey())
|
||||
{
|
||||
// Check that any external field is pointing to an existing object
|
||||
//
|
||||
$sRemoteClass = $oAttDef->GetTargetClass();
|
||||
$sRemoteTable = MetaModel::DBGetTable($sRemoteClass);
|
||||
$sRemoteKey = MetaModel::DBGetKey($sRemoteClass);
|
||||
|
||||
$aCols = $oAttDef->GetSQLExpressions(); // Workaround a PHP bug: sometimes issuing a Notice if invoking current(somefunc())
|
||||
$sExtKeyField = current($aCols); // get the first column for an external key
|
||||
|
||||
// Note: a class/table may have an external key on itself
|
||||
$sSelect = "SELECT DISTINCT `$sTable`.`$sKeyField` AS id, `$sTable`.`$sExtKeyField` AS value";
|
||||
$sFilter = "FROM `$sTable` LEFT JOIN `$sRemoteTable` AS `{$sRemoteTable}_1` ON `$sTable`.`$sExtKeyField` = `{$sRemoteTable}_1`.`$sRemoteKey`";
|
||||
|
||||
$sFilter = $sFilter." WHERE `{$sRemoteTable}_1`.`$sRemoteKey` IS NULL";
|
||||
// Exclude the records pointing to 0/null from the errors (separate test below)
|
||||
$sFilter .= " AND `$sTable`.`$sExtKeyField` IS NOT NULL";
|
||||
$sFilter .= " AND `$sTable`.`$sExtKeyField` != 0";
|
||||
|
||||
$sSelWrongRecs = "$sSelect $sFilter";
|
||||
|
||||
$sErrorDesc = Dict::Format('DBAnalyzer-Integrity-InvalidExtKey', $sAttCode, $sTable, $sExtKeyField);
|
||||
$this->ExecQuery($sSelWrongRecs, '', $sErrorDesc, $sClass, $aErrorsAndFixes);
|
||||
// Fix it request needs the values of the enum to generate the requests
|
||||
if (isset($aErrorsAndFixes[$sClass][$sErrorDesc]['values']))
|
||||
{
|
||||
$aFixit = array();
|
||||
$aFixit[] = "-- Remove inconsistant entries:";
|
||||
$sIds = implode(', ', array_keys($aErrorsAndFixes[$sClass][$sErrorDesc]['values']));
|
||||
$aFixit[] = "DELETE `$sTable` FROM `$sTable` WHERE `$sTable`.`$sExtKeyField` IN ($sIds)";
|
||||
$aFixit[] = "";
|
||||
$aFixit[] = "-- Or fix inconsistant values: Replace XXX with the appropriate value";
|
||||
foreach (array_keys($aErrorsAndFixes[$sClass][$sErrorDesc]['values']) as $sKey)
|
||||
{
|
||||
$aFixit[] = "UPDATE `$sTable` SET `$sTable`.`$sExtKeyField` = XXX WHERE `$sTable`.`$sExtKeyField` = '$sKey'";
|
||||
}
|
||||
$aErrorsAndFixes[$sClass][$sErrorDesc]['fixit'] = $aFixit;
|
||||
}
|
||||
|
||||
if (!$oAttDef->IsNullAllowed())
|
||||
{
|
||||
$sSelect = "SELECT DISTINCT `$sTable`.`$sKeyField` AS id";
|
||||
$sDelete = "DELETE `$sTable`";
|
||||
$sFilter = "FROM `$sTable` WHERE `$sTable`.`$sExtKeyField` IS NULL OR `$sTable`.`$sExtKeyField` = 0";
|
||||
$sSelWrongRecs = "$sSelect $sFilter";
|
||||
$sFixitRequest = "$sDelete $sFilter";
|
||||
$sErrorDesc = Dict::Format('DBAnalyzer-Integrity-MissingExtKey', $sAttCode, $sTable, $sExtKeyField);
|
||||
$this->ExecQuery($sSelWrongRecs, $sFixitRequest, $sErrorDesc, $sClass, $aErrorsAndFixes);
|
||||
if (isset($aErrorsAndFixes[$sClass][$sErrorDesc]['count']) && ($aErrorsAndFixes[$sClass][$sErrorDesc]['count'] > 0))
|
||||
{
|
||||
$aFixit = $aErrorsAndFixes[$sClass][$sErrorDesc]['fixit'];
|
||||
$aFixit[] = "-- Alternate fix";
|
||||
$aFixit[] = "-- Replace XXX with the appropriate value";
|
||||
$aFixit[] = "UPDATE `$sTable` SET `$sTable`.`$sExtKeyField` = XXX WHERE `$sTable`.`$sExtKeyField` IS NULL OR `$sTable`.`$sExtKeyField` = 0";
|
||||
$aErrorsAndFixes[$sClass][$sErrorDesc]['fixit'] = $aFixit;
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif ($oAttDef->IsDirectField() && !($oAttDef instanceof AttributeTagSet))
|
||||
{
|
||||
// Check that the values fit the allowed values
|
||||
//
|
||||
$aAllowedValues = MetaModel::GetAllowedValues_att($sClass, $sAttCode);
|
||||
if (!is_null($aAllowedValues) && count($aAllowedValues) > 0)
|
||||
{
|
||||
$sExpectedValues = implode(",", CMDBSource::Quote(array_keys($aAllowedValues), true));
|
||||
|
||||
$aCols = $oAttDef->GetSQLExpressions(); // Workaround a PHP bug: sometimes issuing a Notice if invoking current(somefunc())
|
||||
$sMyAttributeField = current($aCols); // get the first column for the moment
|
||||
$sSelWrongRecs = "SELECT DISTINCT `$sTable`.`$sKeyField` AS id, `$sTable`.`$sMyAttributeField` AS value FROM `$sTable` WHERE `$sTable`.`$sMyAttributeField` NOT IN ($sExpectedValues)";
|
||||
$sErrorDesc = Dict::Format('DBAnalyzer-Integrity-InvalidValue', $sAttCode, $sTable, $sMyAttributeField);
|
||||
$this->ExecQuery($sSelWrongRecs, '', $sErrorDesc, $sClass, $aErrorsAndFixes);
|
||||
// Fix it request needs the values of the enum to generate the requests
|
||||
if (isset($aErrorsAndFixes[$sClass][$sErrorDesc]['values']))
|
||||
{
|
||||
if (isset($aErrorsAndFixes[$sClass][$sErrorDesc]['fixit']))
|
||||
{
|
||||
$aFixit = $aErrorsAndFixes[$sClass][$sErrorDesc]['fixit'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$aFixit = array("-- Replace 'XXX' with the appropriate value");
|
||||
}
|
||||
foreach (array_keys($aErrorsAndFixes[$sClass][$sErrorDesc]['values']) as $sKey)
|
||||
{
|
||||
$aFixit[] = "UPDATE `$sTable` SET `$sTable`.`$sMyAttributeField` = 'XXX' WHERE `$sTable`.`$sMyAttributeField` = '$sKey'";
|
||||
}
|
||||
$aErrorsAndFixes[$sClass][$sErrorDesc]['fixit'] = $aFixit;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check user accounts without profile
|
||||
$sUserTable = MetaModel::DBGetTable('User');
|
||||
$sLinkTable = MetaModel::DBGetTable('URP_UserProfile');
|
||||
$sSelect = "SELECT DISTINCT u.id AS id, u.`login` AS value";
|
||||
$sFilter = "FROM `$sUserTable` AS u LEFT JOIN `$sLinkTable` AS l ON l.userid = u.id WHERE l.id IS NULL";
|
||||
$sSelWrongRecs = "$sSelect $sFilter";
|
||||
$sFixit = "-- Remove the corresponding user(s)";
|
||||
$this->ExecQuery($sSelWrongRecs, $sFixit, Dict::S('DBAnalyzer-Integrity-UsersWithoutProfile'), 'User', $aErrorsAndFixes);
|
||||
|
||||
if (!is_null($this->iTimeLimitPerOperation))
|
||||
{
|
||||
set_time_limit($iPreviousTimeLimit);
|
||||
}
|
||||
return $aErrorsAndFixes;
|
||||
}
|
||||
|
||||
private function CheckUniquenessRule($sClass, $sUniquenessRuleId, $aUniquenessRuleProperties, &$aErrorsAndFixes)
|
||||
{
|
||||
$sOqlUniquenessQuery = "SELECT $sClass";
|
||||
if (!(empty($sUniquenessFilter = $aUniquenessRuleProperties['filter'])))
|
||||
{
|
||||
$sOqlUniquenessQuery .= ' WHERE '.$sUniquenessFilter;
|
||||
}
|
||||
$oUniquenessQuery = DBObjectSearch::FromOQL($sOqlUniquenessQuery);
|
||||
|
||||
$aValueNames = array();
|
||||
$aGroupByExpr = array();
|
||||
foreach ($aUniquenessRuleProperties['attributes'] as $sAttributeCode)
|
||||
{
|
||||
$oExpr = Expression::FromOQL("$sClass.$sAttributeCode");
|
||||
$aGroupByExpr[$sAttributeCode] = $oExpr;
|
||||
$aValueNames[] = $sAttributeCode;
|
||||
}
|
||||
|
||||
$aSelectExpr = array();
|
||||
|
||||
$sSQLUniquenessQuery = $oUniquenessQuery->MakeGroupByQuery(array(), $aGroupByExpr, false, $aSelectExpr);
|
||||
|
||||
$sSQLUniquenessQuery .= ' having count(*) > 1';
|
||||
|
||||
$sErrorDesc = $this->GetUniquenessRuleMessage($sClass, $sUniquenessRuleId);
|
||||
|
||||
$this->ExecQuery($sSQLUniquenessQuery, '', $sErrorDesc, $sClass, $aErrorsAndFixes, $aValueNames);
|
||||
if (isset($aErrorsAndFixes[$sClass][$sErrorDesc]['res']))
|
||||
{
|
||||
$aFixit = array("-- In order to get the duplicates, run the following queries:");
|
||||
foreach ($aErrorsAndFixes[$sClass][$sErrorDesc]['res'] as $aValues)
|
||||
{
|
||||
$oFixSearch = new DBObjectSearch($sClass);
|
||||
foreach ($aValues as $sAttCode => $sValue)
|
||||
{
|
||||
$oFixSearch->AddCondition($sAttCode, $sValue, '=');
|
||||
}
|
||||
$aFixit[] = $oFixSearch->MakeSelectQuery().';';
|
||||
$aFixit[] = "";
|
||||
}
|
||||
$aErrorsAndFixes[$sClass][$sErrorDesc]['fixit'] = $aFixit;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
private function GetUniquenessRuleMessage($sCurrentClass, $sUniquenessRuleId)
|
||||
{
|
||||
// we could add also a specific message if user is admin ("dict key is missing")
|
||||
return Dict::Format('Core:UniquenessDefaultError', $sUniquenessRuleId);
|
||||
}
|
||||
}
|
||||
602
datamodels/2.x/combodo-db-tools/dbtools.php
Normal file
602
datamodels/2.x/combodo-db-tools/dbtools.php
Normal file
@@ -0,0 +1,602 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2013-2020 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
* 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
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* iTop is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
*/
|
||||
|
||||
@include_once('../../approot.inc.php');
|
||||
@include_once('../approot.inc.php');
|
||||
require_once(APPROOT.'application/application.inc.php');
|
||||
require_once(APPROOT.'application/itopwebpage.class.inc.php');
|
||||
require_once(APPROOT.'application/ajaxwebpage.class.inc.php');
|
||||
require_once(APPROOT.'application/startup.inc.php');
|
||||
require_once(APPROOT.'application/loginwebpage.class.inc.php');
|
||||
|
||||
require_once('db_analyzer.class.inc.php');
|
||||
|
||||
const MAX_RESULTS = 10;
|
||||
|
||||
/**
|
||||
* @param iTopWebPage $oP
|
||||
* @param ApplicationContext $oAppContext
|
||||
*
|
||||
* @return \iTopWebPage
|
||||
* @throws CoreException
|
||||
* @throws DictExceptionMissingString
|
||||
* @throws MySQLException
|
||||
*/
|
||||
function DisplayDBInconsistencies(iTopWebPage &$oP, ApplicationContext &$oAppContext)
|
||||
{
|
||||
$iShowId = intval(utils::ReadParam('show_id', '0'));
|
||||
$sErrorLabelSelection = utils::ReadParam('error_selection', '');
|
||||
$sClassSelection = utils::ReadParam('class_selection', '');
|
||||
if (!empty($sClassSelection))
|
||||
{
|
||||
$aClassSelection = explode(",", $sClassSelection);
|
||||
}
|
||||
else
|
||||
{
|
||||
$aClassSelection = array();
|
||||
}
|
||||
$sClassSelection = utils::ReadParam('class_selection', '');
|
||||
|
||||
$oP->SetCurrentTab(Dict::S('DBTools:Inconsistencies'));
|
||||
|
||||
$bRunAnalysis = intval(utils::ReadParam('run_analysis', '0'));
|
||||
if ($bRunAnalysis)
|
||||
{
|
||||
$oDBAnalyzer = new DatabaseAnalyzer();
|
||||
$aResults = $oDBAnalyzer->CheckIntegrity($aClassSelection, $iShowId);
|
||||
if (empty($aResults))
|
||||
{
|
||||
$oP->p('<div class="header_message message_ok">'.Dict::S('DBTools:NoError').'</div>');
|
||||
}
|
||||
}
|
||||
|
||||
$oP->add('<div style="padding: 15px; background: #ddd;">');
|
||||
$oP->add("<form>");
|
||||
$oP->add("<table border=0>");
|
||||
|
||||
$oP->add("<tr><td>");
|
||||
$sChecked = ($iShowId == 0) ? 'checked' : '';
|
||||
$oP->add("<label><input type=\"radio\" $sChecked name=\"show_id\" value=\"0\">".Dict::S('DBTools:HideIds').'</label>');
|
||||
$oP->add("</td><td>");
|
||||
$sChecked = ($iShowId == 1) ? 'checked' : '';
|
||||
$oP->add("<label><input type=\"radio\" $sChecked name=\"show_id\" value=\"1\">".Dict::S('DBTools:ShowIds').'</label>');
|
||||
$oP->add("</td><td>");
|
||||
$sChecked = ($iShowId == 3) ? 'checked' : '';
|
||||
$oP->add("<label><input type=\"radio\" $sChecked name=\"show_id\" value=\"3\">".Dict::S('DBTools:ShowReport').'</label>');
|
||||
$oP->add("</td></tr>\n");
|
||||
|
||||
$oP->add("</table><br>\n");
|
||||
|
||||
$oP->add("<input type=\"submit\" value=\"".Dict::S('DBTools:Analyze')."\">\n");
|
||||
$oP->add('<input type="hidden" name="class_selection" value="'.$sClassSelection.'"/>');
|
||||
$oP->add('<input type="hidden" name="error_selection" value="'.$sErrorLabelSelection.'"/>');
|
||||
$oP->add('<input type="hidden" name="run_analysis" value="1"/>');
|
||||
$oP->add('<input type="hidden" name="exec_module" value="combodo-db-tools"/>');
|
||||
$oP->add('<input type="hidden" name="exec_page" value="dbtools.php"/>');
|
||||
$oP->add($oAppContext->GetForForm());
|
||||
$oP->add("</form>\n");
|
||||
$oP->add('</div>');
|
||||
|
||||
|
||||
if (!empty($sErrorLabelSelection) || !empty($sClassSelection))
|
||||
{
|
||||
$oP->add("<br>");
|
||||
$oP->add("<form>");
|
||||
$oP->add('<input type="hidden" name="show_id" value="0"/>');
|
||||
$oP->add('<input type="hidden" name="class_selection" value=""/>');
|
||||
$oP->add('<input type="hidden" name="error_selection" value=""/>');
|
||||
$oP->add('<input type="hidden" name="exec_module" value="combodo-db-tools"/>');
|
||||
$oP->add('<input type="hidden" name="exec_page" value="dbtools.php"/>');
|
||||
$oP->add("<input type=\"submit\" value=\"".Dict::S('DBTools:ShowAll')."\">\n");
|
||||
$oP->add("</form>\n");
|
||||
}
|
||||
|
||||
if (!empty($aResults))
|
||||
{
|
||||
|
||||
if ($iShowId == 3)
|
||||
{
|
||||
DisplayInconsistenciesReport($aResults);
|
||||
}
|
||||
|
||||
$oP->p(Dict::S('DBTools:ErrorsFound'));
|
||||
|
||||
$oP->add('<table class="listResults"><tr><th>'.Dict::S('DBTools:Class').'</th><th>'.Dict::S('DBTools:Count').'</th><th>'.Dict::S('DBTools:Error').'</th></tr>');
|
||||
$bTable = true;
|
||||
foreach($aResults as $sClass => $aErrorList)
|
||||
{
|
||||
foreach($aErrorList as $sErrorLabel => $aError)
|
||||
{
|
||||
if (!empty($sErrorLabelSelection) && ($sErrorLabel != $sErrorLabelSelection))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$bTable)
|
||||
{
|
||||
$oP->add('<br>');
|
||||
$oP->add('<table class="listResults"><tr><th></th><th>Class</th><th>Count</th><th>Error</th></tr>');
|
||||
$bTable = true;
|
||||
}
|
||||
|
||||
$oP->add('<tr>');
|
||||
|
||||
|
||||
$oP->add('<td>'.MetaModel::GetName($sClass).' ('.$sClass.')</td>');
|
||||
$iCount = $aError['count'];
|
||||
$oP->add('<td>'.$iCount.'</td>');
|
||||
$oP->add('<td>'.$sErrorLabel.'</td>');
|
||||
$oP->add('</tr>');
|
||||
|
||||
if ($iShowId > 0)
|
||||
{
|
||||
$oP->add('</table>');
|
||||
$bTable = false;
|
||||
$oP->p(Dict::S('DBTools:SQLquery'));
|
||||
$sQuery = $aError['query'];
|
||||
$oP->add('<div style="padding: 15px; background: #f1f1f1;">');
|
||||
$oP->add('<code>'.$sQuery.'</code>');
|
||||
$oP->add('</div>');
|
||||
|
||||
if (isset($aError['fixit']))
|
||||
{
|
||||
$oP->p(Dict::S('DBTools:FixitSQLquery'));
|
||||
$aQueries = $aError['fixit'];
|
||||
$oP->add('<div style="padding: 15px; background: #f1f1f1;">');
|
||||
foreach($aQueries as $sFixQuery)
|
||||
{
|
||||
$oP->add('<pre>'.$sFixQuery.'</pre>');
|
||||
}
|
||||
$oP->add('<br></div>');
|
||||
}
|
||||
|
||||
$oP->p(Dict::S('DBTools:SQLresult'));
|
||||
$sQueryResult = '';
|
||||
$iCount = count($aError['res']);
|
||||
$iMaxCount = MAX_RESULTS;
|
||||
foreach($aError['res'] as $aRes)
|
||||
{
|
||||
$iMaxCount--;
|
||||
if ($iMaxCount < 0)
|
||||
{
|
||||
$sQueryResult .= 'Displayed '.MAX_RESULTS."/$iCount results.<br>";
|
||||
break;
|
||||
}
|
||||
foreach($aRes as $sKey => $sValue)
|
||||
{
|
||||
$sQueryResult .= "'$sKey'='$sValue' ";
|
||||
}
|
||||
$sQueryResult .= '<br>';
|
||||
}
|
||||
$oP->add('<div style="padding: 15px; background: #f1f1f1;">');
|
||||
$oP->add('<code>'.$sQueryResult.'</code>');
|
||||
$oP->add('</div>');
|
||||
}
|
||||
}
|
||||
}
|
||||
$oP->add('</table>');
|
||||
}
|
||||
return $oP;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $aResults
|
||||
*
|
||||
* @return mixed
|
||||
* @throws CoreException
|
||||
* @throws DictExceptionMissingString
|
||||
*/
|
||||
function DisplayInconsistenciesReport($aResults)
|
||||
{
|
||||
$sDBToolsFolder = str_replace("\\", '/', APPROOT.'log/');
|
||||
$sReportFile = 'dbtools-report-'.date('Y-m-d-H-i-s');
|
||||
|
||||
$fReport = fopen($sDBToolsFolder.$sReportFile.'.txt', 'w');
|
||||
fwrite($fReport, 'Database Maintenance tools: '.date('Y-m-d H:i:s')."\r\n");
|
||||
foreach($aResults as $sClass => $aErrorList)
|
||||
{
|
||||
fwrite($fReport, '');
|
||||
foreach($aErrorList as $sErrorLabel => $aError)
|
||||
{
|
||||
fwrite($fReport, "\r\n----------\r\n");
|
||||
fwrite($fReport, 'Class: '.MetaModel::GetName($sClass).' ('.$sClass.")\r\n");
|
||||
$iCount = $aError['count'];
|
||||
fwrite($fReport, 'Count: '.$iCount."\r\n");
|
||||
fwrite($fReport, 'Error: '.$sErrorLabel."\r\n");
|
||||
$sQuery = $aError['query'];
|
||||
fwrite($fReport, 'Query: '.$sQuery."\r\n");
|
||||
|
||||
if (isset($aError['fixit']))
|
||||
{
|
||||
fwrite($fReport, "\r\nFix it (indication):\r\n\r\n");
|
||||
$aFixitQueries = $aError['fixit'];
|
||||
foreach($aFixitQueries as $sFixitQuery)
|
||||
{
|
||||
fwrite($fReport, "$sFixitQuery\r\n");
|
||||
}
|
||||
fwrite($fReport, "\r\n");
|
||||
}
|
||||
|
||||
$sQueryResult = '';
|
||||
$aIdList = array();
|
||||
foreach($aError['res'] as $aRes)
|
||||
{
|
||||
foreach($aRes as $sKey => $sValue)
|
||||
{
|
||||
$sQueryResult .= "'$sKey'='$sValue' ";
|
||||
if ($sKey == 'id')
|
||||
{
|
||||
$aIdList[] = $sValue;
|
||||
}
|
||||
}
|
||||
$sQueryResult .= "\r\n";
|
||||
|
||||
}
|
||||
fwrite($fReport, "Result: \r\n".$sQueryResult);
|
||||
$sIdList = '('.implode(',', $aIdList).')';
|
||||
fwrite($fReport, 'Ids: '.$sIdList."\r\n");
|
||||
}
|
||||
}
|
||||
fclose($fReport);
|
||||
|
||||
$oArchive = new ZipArchive();
|
||||
$oArchive->open($sDBToolsFolder.$sReportFile.'.zip', ZipArchive::CREATE);
|
||||
$oArchive->addFile($sDBToolsFolder.$sReportFile.'.txt', $sReportFile.'.txt');
|
||||
$oArchive->close();
|
||||
unlink($sDBToolsFolder.$sReportFile.'.txt');
|
||||
$sReportFile = $sDBToolsFolder.$sReportFile.'.zip';
|
||||
|
||||
|
||||
header('Content-Description: File Transfer');
|
||||
header('Content-Type: multipart/x-zip');
|
||||
header('Content-Disposition: inline; filename="'.basename($sReportFile).'"');
|
||||
header('Expires: 0');
|
||||
header('Cache-Control: must-revalidate');
|
||||
header('Pragma: public');
|
||||
header('Content-Length: '.filesize($sReportFile));
|
||||
readfile($sReportFile);
|
||||
unlink($sReportFile);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float
|
||||
* @throws MySQLException
|
||||
* @throws MySQLHasGoneAwayException
|
||||
*/
|
||||
function GetDatabaseSize()
|
||||
{
|
||||
$sShema = CMDBSource::DBName();
|
||||
|
||||
$sReq = <<<EOF
|
||||
SELECT round(sum(data_length+index_length)/1024/1024,2) AS sz
|
||||
FROM information_schema.tables
|
||||
WHERE table_schema = '$sShema';
|
||||
EOF;
|
||||
|
||||
$oResult = CMDBSource::Query($sReq);
|
||||
if ($oResult !== false)
|
||||
{
|
||||
$aRow = $oResult->fetch_assoc();
|
||||
$sSize = $aRow['sz'];
|
||||
return $sSize;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param iTopWebPage $oP
|
||||
* @param ApplicationContext $oAppContext
|
||||
*
|
||||
* @return \iTopWebPage
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
*/
|
||||
function DisplayDatabaseInfo(iTopWebPage &$oP, ApplicationContext &$oAppContext)
|
||||
{
|
||||
// Build HTML
|
||||
$oP->SetCurrentTab(Dict::S('DBTools:DatabaseInfo'));
|
||||
|
||||
$oP->add('<div style="padding: 15px; background: #ddd;">');
|
||||
$oP->add('<table class="listResults"><tr><th>'.Dict::S('DBTools:Base').'</th><th>'.Dict::S('DBTools:Size').'</th></tr>');
|
||||
|
||||
$oP->add('<tr>');
|
||||
$oP->add('<td>');
|
||||
$oP->add(CMDBSource::DBName());
|
||||
$oP->add('</td>');
|
||||
$oP->add('<td>');
|
||||
$fSize = GetDatabaseSize();
|
||||
$oP->add("$fSize MB");
|
||||
$oP->add('</td>');
|
||||
$oP->add('</tr>');
|
||||
$oP->add('</table>');
|
||||
|
||||
$oP->add('</div>');
|
||||
|
||||
return $oP;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param iTopWebPage $oP
|
||||
* @param ApplicationContext $oAppContext
|
||||
*
|
||||
* @return \iTopWebPage
|
||||
* @throws CoreException
|
||||
* @throws MySQLException
|
||||
* @throws \Exception
|
||||
*/
|
||||
function DisplayLostAttachments(iTopWebPage &$oP, ApplicationContext &$oAppContext)
|
||||
{
|
||||
// Retrieve parameters
|
||||
$sStepName = utils::ReadParam('step_name');
|
||||
$aRecordsToClean = utils::ReadParam('dbt-cbx', array(), false, 'raw_data');
|
||||
|
||||
$iRestoredItemsCount = 0;
|
||||
$iRecordsToCleanCount = count($aRecordsToClean);
|
||||
$aErrorsReport = array();
|
||||
|
||||
$bDoAnalyze = in_array($sStepName, array('analyze', 'restore'));
|
||||
$bDoRestore = in_array($sStepName, array('restore'));
|
||||
|
||||
// Build HTML
|
||||
$oP->SetCurrentTab(Dict::S('DBTools:LostAttachments'));
|
||||
|
||||
$oP->add('<div class="db-tools-tab-content">');
|
||||
$oP->add('<div class="dbt-lostattachments">');
|
||||
|
||||
$oP->add('<div class="header_message message_info">'.Dict::S('DBTools:LostAttachments:Disclaimer').'</div>');
|
||||
$oP->add('<div class="dbt-steps">');
|
||||
$oP->add('<form>');
|
||||
$oP->add('<input type="hidden" name="exec_module" value="combodo-db-tools"/>');
|
||||
$oP->add('<input type="hidden" name="exec_page" value="dbtools.php"/>');
|
||||
|
||||
// Step 1: Analyze DB
|
||||
$oP->add('<div class="dbt-step"><p class="dbt-step-description"><span class="dbt-step-number">1.</span><span>'.Dict::S('DBTools:LostAttachments:Step:Analyze').'</span></p><button type="submit" name="step_name" value="analyze">'.Dict::S('DBTools:LostAttachments:Button:Analyze') .'</button></div>');
|
||||
|
||||
// Step 2: Display results
|
||||
if($bDoAnalyze)
|
||||
{
|
||||
// Check if we have to restore some items first
|
||||
if($bDoRestore)
|
||||
{
|
||||
foreach($aRecordsToClean as $sRecordToClean)
|
||||
{
|
||||
utils::PushArchiveMode(false); // For iTop < 2.5, the application can be wrongly set to archive mode true when it fails from retrieving an object. See r5340.
|
||||
try
|
||||
{
|
||||
// Retrieve attachment
|
||||
$aLocationParts = explode('::', $sRecordToClean);
|
||||
/** @var \DBObject $oOriginObject */
|
||||
$oOriginObject = MetaModel::GetObject($aLocationParts[0], $aLocationParts[1], true, true);
|
||||
/** @var \ormDocument $oOrmDocument */
|
||||
$oOrmDocument = $oOriginObject->Get('contents');
|
||||
|
||||
// Retrieve target object
|
||||
$sTargetClass = $oOriginObject->Get('item_class');
|
||||
$sTargetId = $oOriginObject->Get('item_id');
|
||||
/** @var \DBObject $oTargetObject */
|
||||
$oTargetObject = MetaModel::GetObject($sTargetClass, $sTargetId, true, true);
|
||||
|
||||
// Put it on the target object
|
||||
/** @var \Attachment $oAttachment */
|
||||
$oAttachment = MetaModel::NewObject('Attachment');
|
||||
$oAttachment->Set('item_class', $sTargetClass);
|
||||
$oAttachment->Set('item_id', $sTargetId);
|
||||
$oAttachment->Set('item_org_id', $oTargetObject->Get('org_id'));
|
||||
$oAttachment->Set('contents', $oOrmDocument);
|
||||
$oAttachment->DBInsert();
|
||||
|
||||
// Put history entry
|
||||
$sHistoryEntry = Dict::Format('DBTools:LostAttachments:History', $oOrmDocument->GetFileName());
|
||||
CMDBObject::SetTrackInfo(UserRights::GetUserFriendlyName());
|
||||
$oChangeOp = MetaModel::NewObject('CMDBChangeOpPlugin');
|
||||
/** @var \Change $oChange */
|
||||
$oChange = CMDBObject::GetCurrentChange();
|
||||
$oChangeOp->Set('change', $oChange->GetKey());
|
||||
$oChangeOp->Set('objclass', $sTargetClass);
|
||||
$oChangeOp->Set('objkey', $sTargetId);
|
||||
$oChangeOp->Set('description', $sHistoryEntry);
|
||||
$oChangeOp->DBInsert();
|
||||
|
||||
// Remove origin object (should only be done for InlineImage)
|
||||
$oOriginObject->DBDelete();
|
||||
|
||||
$iRestoredItemsCount++;
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
$aErrorsReport[] = 'Could not restore attachment from '.$sRecordToClean.', cause: '.$e->getMessage();
|
||||
}
|
||||
utils::PopArchiveMode();
|
||||
}
|
||||
}
|
||||
|
||||
// Search attachments stored as inline images
|
||||
$sInlineImageDBTable = MetaModel::DBGetTable('InlineImage');
|
||||
$sSelWrongRecs = 'SELECT id, secret, "InlineImage" AS current_class, id AS current_id, item_class AS target_class, item_id AS target_id, contents_filename AS filename FROM '.$sInlineImageDBTable.' WHERE contents_mimetype NOT LIKE "image/%"';
|
||||
$aWrongRecords = CMDBSource::QueryToArray($sSelWrongRecs);
|
||||
|
||||
$oP->add('<div class="dbt-step">');
|
||||
$oP->add('<p class="dbt-step-description"><span class="dbt-step-number">2.</span><span>'.Dict::S('DBTools:LostAttachments:Step:AnalyzeResults').'</span></p>');
|
||||
|
||||
if(empty($aWrongRecords))
|
||||
{
|
||||
$oP->add('<div class="header_message message_ok">'.Dict::S('DBTools:LostAttachments:Step:AnalyzeResults:None').'</div>');
|
||||
}
|
||||
else
|
||||
{
|
||||
$oP->add('<div class="header_message message_error">'.Dict::Format('DBTools:LostAttachments:Step:AnalyzeResults:Some', count($aWrongRecords)).'</div>');
|
||||
|
||||
// Display errors as table
|
||||
$oP->add('<table class="listResults">');
|
||||
$oP->add('<tr><th><input type="checkbox" class="dbt-toggler-cbx" /></th><th>'.Dict::S('DBTools:LostAttachments:Step:AnalyzeResults:Item:Filename').'</th><th>'.Dict::S('DBTools:LostAttachments:Step:AnalyzeResults:Item:CurrentLocation').'</th><th>'.Dict::S('DBTools:LostAttachments:Step:AnalyzeResults:Item:TargetLocation').'</th></tr>');
|
||||
|
||||
foreach($aWrongRecords as $iIndex => $aWrongRecord)
|
||||
{
|
||||
|
||||
$sCurrentClass = $aWrongRecord['current_class'];
|
||||
$sCurrentId = $aWrongRecord['current_id'];
|
||||
$sRecordToClean = Dict::S('DBTools:LostAttachments:StoredAsInlineImage');
|
||||
|
||||
$sTargetClass = $aWrongRecord['target_class'];
|
||||
$sTargetId = $aWrongRecord['target_id'];
|
||||
$sTargetLocation = '<a href="'.ApplicationContext::MakeObjectUrl($sTargetClass, $sTargetId).'" target="_blank">'.$sTargetClass.'::'.$sTargetId.'</a>';
|
||||
|
||||
$sFilename = '<a href="'.utils::GetAbsoluteUrlAppRoot().INLINEIMAGE_DOWNLOAD_URL.$aWrongRecord['id'].'&s='.$aWrongRecord['secret'].'" target="_blank">'.$aWrongRecord['filename'].'</a>';
|
||||
|
||||
$sRowClass = ($iIndex % 2 === 0) ? 'odd' : 'even'; // (Starts at 0, not 1)
|
||||
$oP->add('<tr class="'.$sRowClass.'"><td><input type="checkbox" class="dbt-cbx" name="dbt-cbx[]" value="'.$sCurrentClass.'::'.$sCurrentId.'" /></td><td>'.$sFilename.'</td><td>'.$sRecordToClean.'</td><td>'.$sTargetLocation.'</td></tr>');
|
||||
}
|
||||
|
||||
$oP->add('</table>');
|
||||
$oP->add('<div><button type="submit" name="step_name" value="restore" disabled>'.Dict::S('DBTools:LostAttachments:Button:Restore').'</button></div>');
|
||||
|
||||
// JS to handle checkboxes and button
|
||||
$oP->add_ready_script(
|
||||
<<<EOF
|
||||
// Check all / none checkboxes
|
||||
$('.dbt-lostattachments .dbt-toggler-cbx').on('click', function(){
|
||||
$('.dbt-lostattachments .dbt-cbx').prop('checked', $(this).prop('checked'));
|
||||
|
||||
// Disable restore button if at lest one checkbox clicked
|
||||
var bDisableButton = ($('.dbt-lostattachments .dbt-cbx:checked').length === 0)
|
||||
$('.dbt-lostattachments button[name="step_name"][value="restore"]').prop('disabled', bDisableButton);
|
||||
});
|
||||
|
||||
// Click on a checkbox
|
||||
$('.dbt-lostattachments .dbt-cbx').on('click', function(){
|
||||
// Disable restore button if at lest one checkbox clicked
|
||||
var bDisableButton = ($('.dbt-lostattachments .dbt-cbx:checked').length === 0)
|
||||
$('.dbt-lostattachments button[name="step_name"][value="restore"]').prop('disabled', bDisableButton);
|
||||
|
||||
// Uncheck global checkbox
|
||||
if( $('.dbt-lostattachments .dbt-cbx:not(:checked)').length > 0 )
|
||||
{
|
||||
$('.dbt-lostattachments .dbt-toggler-cbx').prop('checked', false);
|
||||
}
|
||||
});
|
||||
EOF
|
||||
);
|
||||
}
|
||||
|
||||
$oP->add('</div>');
|
||||
}
|
||||
|
||||
// Step 3: Restore results
|
||||
if($bDoRestore)
|
||||
{
|
||||
$oP->add('<div class="dbt-step">');
|
||||
$oP->add('<p class="dbt-step-description"><span class="dbt-step-number">3.</span><span>'.Dict::S('DBTools:LostAttachments:Step:RestoreResults').'</span></p>');
|
||||
|
||||
$oP->add('<div class="header_message message_info">'.Dict::Format('DBTools:LostAttachments:Step:RestoreResults:Results', $iRestoredItemsCount, $iRecordsToCleanCount).'</div>');
|
||||
|
||||
if(!empty($aErrorsReport))
|
||||
{
|
||||
foreach($aErrorsReport as $sErrorReport)
|
||||
{
|
||||
$oP->add('<div class="header_message message_error">'.$sErrorReport.'</div>');
|
||||
}
|
||||
}
|
||||
|
||||
$oP->add('</div>');
|
||||
}
|
||||
|
||||
$oP->add($oAppContext->GetForForm());
|
||||
$oP->add('</form>');
|
||||
$oP->add('</div>');
|
||||
|
||||
$oP->add('</div>');
|
||||
$oP->add('</div>');
|
||||
|
||||
// Buttons disabling on click
|
||||
$sConfirmText = Dict::S('DBTools:LostAttachments:Button:Restore:Confirm');
|
||||
$sButtonBusyText = Dict::S('DBTools:LostAttachments:Button:Busy');
|
||||
$oP->add_ready_script(
|
||||
<<<EOF
|
||||
$('.dbt-lostattachments button[name="step_name"]').on('click', function(){
|
||||
|
||||
if($(this).val() === 'restore')
|
||||
{
|
||||
if(!confirm('{$sConfirmText}'))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
//$(this).prop('disabled', true);
|
||||
$(this).text('{$sButtonBusyText}');
|
||||
});
|
||||
EOF
|
||||
);
|
||||
|
||||
return $oP;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// Main program
|
||||
//
|
||||
try
|
||||
{
|
||||
if (method_exists('ApplicationMenu', 'CheckMenuIdEnabled'))
|
||||
{
|
||||
LoginWebPage::DoLogin(); // Check user rights and prompt if needed
|
||||
ApplicationMenu::CheckMenuIdEnabled('DBToolsMenu');
|
||||
}
|
||||
else
|
||||
{
|
||||
LoginWebPage::DoLogin(true); // Check user rights and prompt if needed
|
||||
}
|
||||
|
||||
$oAppContext = new ApplicationContext();
|
||||
|
||||
|
||||
$sPageTitle = Dict::S('DBTools:Title');
|
||||
$sPageId = 'db-tools';
|
||||
|
||||
$oP = new iTopWebPage($sPageTitle);
|
||||
$oP->add_saas('env-'.utils::GetCurrentEnvironment().'/combodo-db-tools/default.scss');
|
||||
|
||||
$oP->add(
|
||||
<<<EOF
|
||||
<div class="page_header">
|
||||
<h1>$sPageTitle</h1>
|
||||
</div>
|
||||
EOF
|
||||
);
|
||||
$oP->AddTabContainer('db-tools');
|
||||
$oP->SetCurrentTabContainer('db-tools');
|
||||
|
||||
// Database Info
|
||||
$oP = DisplayDatabaseInfo($oP, $oAppContext);
|
||||
|
||||
// DB Inconsistences
|
||||
$oP = DisplayDBInconsistencies($oP, $oAppContext);
|
||||
|
||||
// Lost attachments
|
||||
$oP = DisplayLostAttachments($oP, $oAppContext);
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
$oP->p('<b>'.$e->getMessage().'</b>');
|
||||
}
|
||||
|
||||
if (isset($oP))
|
||||
{
|
||||
$oP->output();
|
||||
}
|
||||
82
datamodels/2.x/combodo-db-tools/de.dict.combodo-db-tools.php
Normal file
82
datamodels/2.x/combodo-db-tools/de.dict.combodo-db-tools.php
Normal file
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2013-2020 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
* 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
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* iTop is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
*/
|
||||
Dict::Add('DE DE', 'German', 'Deutsch', array(
|
||||
// Dictionary entries go here
|
||||
'Menu:DBToolsMenu' => 'DB Tools',
|
||||
'DBTools:Class' => 'Klasse',
|
||||
'DBTools:Title' => 'Datenbank-Pflege-Tools',
|
||||
'DBTools:ErrorsFound' => 'Fehler gefunden',
|
||||
'DBTools:Error' => 'Fehler',
|
||||
'DBTools:Count' => 'Anzahl',
|
||||
'DBTools:SQLquery' => 'SQL Query',
|
||||
'DBTools:FixitSQLquery' => 'SQL query To Fix it (indication)~~',
|
||||
'DBTools:SQLresult' => 'SQL Ergebnis',
|
||||
'DBTools:NoError' => 'Die Datenbank ist OK',
|
||||
'DBTools:HideIds' => 'Fehler',
|
||||
'DBTools:ShowIds' => 'Fehler und Werte',
|
||||
'DBTools:ShowReport' => 'Report',
|
||||
'DBTools:IntegrityCheck' => 'Integritätscheck',
|
||||
'DBTools:FetchCheck' => 'Fetch Check (dauert länger)',
|
||||
|
||||
'DBTools:Analyze' => 'Analysiere',
|
||||
'DBTools:Details' => 'Details anzeigen',
|
||||
'DBTools:ShowAll' => 'Alle Fehler anzeigen',
|
||||
|
||||
'DBTools:Inconsistencies' => 'Datenbank-Inkonsistenzen',
|
||||
|
||||
'DBAnalyzer-Integrity-OrphanRecord' => 'Verwaister Eintrag in `%1$s`, er sollte eine Entsprechung in Tabelle `%2$s` haben',
|
||||
'DBAnalyzer-Integrity-InvalidExtKey' => 'Ungültiger Externer Key %1$s (Spalte: `%2$s.%3$s`)',
|
||||
'DBAnalyzer-Integrity-MissingExtKey' => 'Fehlender Externer Key %1$s (Spalte: `%2$s.%3$s`)',
|
||||
'DBAnalyzer-Integrity-InvalidValue' => 'Ungültiger Wert für %1$s (Spalte: `%2$s.%3$s`)',
|
||||
'DBAnalyzer-Integrity-UsersWithoutProfile' => 'Manche Benutzerkonten haben keinerlei zugewiesenes Profi',
|
||||
'DBAnalyzer-Fetch-Count-Error' => 'Fetch-Count-Fehler in `%1$s`, %2$d Einträge geholt (fetched) / %3$d gezählt',
|
||||
));
|
||||
|
||||
// Database Info
|
||||
Dict::Add('DE DE', 'German', 'Deutsch', array(
|
||||
'DBTools:DatabaseInfo' => 'Datenbank-Information',
|
||||
'DBTools:Base' => 'Datenbank',
|
||||
'DBTools:Size' => 'Größe',
|
||||
));
|
||||
|
||||
// Lost attachments
|
||||
Dict::Add('DE DE', 'German', 'Deutsch', array(
|
||||
'DBTools:LostAttachments' => 'Verlorene Attachments',
|
||||
'DBTools:LostAttachments:Disclaimer' => 'Hier können Sie Ihre Datenbank nach verlorenen oder falsch platzierten Attachments durchsuchen. Dies ist kein Recovery-Tool - es stellt keine gelöschten Daten wieder her.',
|
||||
|
||||
'DBTools:LostAttachments:Button:Analyze' => 'Analysieren',
|
||||
'DBTools:LostAttachments:Button:Restore' => 'Wiederherstellen',
|
||||
'DBTools:LostAttachments:Button:Restore:Confirm' => 'Diese Aktion kann nicht rückgängig gemacht werden, bitte bestätigen Sie dass Sie die ausgewählten Dateien wiederherstellen möchten.',
|
||||
'DBTools:LostAttachments:Button:Busy' => 'Bitte warten...',
|
||||
|
||||
'DBTools:LostAttachments:Step:Analyze' => 'Suche zunächst nach verlorenen / falsch platzierten Attachments, mittels einer Analyse der Datenbank',
|
||||
|
||||
'DBTools:LostAttachments:Step:AnalyzeResults' => 'Analyseergebnisse:',
|
||||
'DBTools:LostAttachments:Step:AnalyzeResults:None' => 'Toll! Alles scheint am richtigen Ort zu sein.',
|
||||
'DBTools:LostAttachments:Step:AnalyzeResults:Some' => 'Manche Attachments scheinen am falschen Ort zu sein. Werfen Sie einen Blick auf die folgende Liste und wählen Sie diejenigen aus, die Sie gerne verschieben möchten.',
|
||||
'DBTools:LostAttachments:Step:AnalyzeResults:Item:Filename' => 'Dateiname',
|
||||
'DBTools:LostAttachments:Step:AnalyzeResults:Item:CurrentLocation' => 'Derzeitiger Ort',
|
||||
'DBTools:LostAttachments:Step:AnalyzeResults:Item:TargetLocation' => 'Verschieben nach...',
|
||||
|
||||
'DBTools:LostAttachments:Step:RestoreResults' => 'Restore-Ergebnisse:',
|
||||
'DBTools:LostAttachments:Step:RestoreResults:Results' => '%1$d/%2$d Attachments wurden wiederhergestellt.',
|
||||
|
||||
'DBTools:LostAttachments:StoredAsInlineImage' => 'Als Inline-Bild gespeichert',
|
||||
'DBTools:LostAttachments:History' => 'Attachment "%1$s" mit DB-Tools wiederhergestellt'
|
||||
));
|
||||
36
datamodels/2.x/combodo-db-tools/default.css
Normal file
36
datamodels/2.x/combodo-db-tools/default.css
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) 2013-2020 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
* 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
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* iTop is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
*/
|
||||
|
||||
.db-tools-tab-content .dbt-lostattachments .dbt-steps .dbt-step {
|
||||
margin-top: 30px;
|
||||
/* This is to avoid long exception message on restore errors */
|
||||
}
|
||||
.db-tools-tab-content .dbt-lostattachments .dbt-steps .dbt-step .dbt-step-description {
|
||||
padding: 0;
|
||||
margin: 0px 0px 5px 0px;
|
||||
}
|
||||
.db-tools-tab-content .dbt-lostattachments .dbt-steps .dbt-step .dbt-step-number {
|
||||
margin-right: 0.3em;
|
||||
}
|
||||
.db-tools-tab-content .dbt-lostattachments .dbt-steps .dbt-step .listResults tr > *:first-child {
|
||||
text-align: center;
|
||||
}
|
||||
.db-tools-tab-content .dbt-lostattachments .dbt-steps .dbt-step .message_error {
|
||||
max-height: 150px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
48
datamodels/2.x/combodo-db-tools/default.scss
Normal file
48
datamodels/2.x/combodo-db-tools/default.scss
Normal file
@@ -0,0 +1,48 @@
|
||||
/*!
|
||||
* Copyright (C) 2013-2020 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
* 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
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* iTop is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
*/
|
||||
|
||||
.db-tools-tab-content{
|
||||
.dbt-lostattachments{
|
||||
.dbt-steps{
|
||||
.dbt-step{
|
||||
margin-top: 30px;
|
||||
|
||||
.dbt-step-description{
|
||||
padding: 0;
|
||||
margin: 0px 0px 5px 0px;
|
||||
}
|
||||
|
||||
.dbt-step-number{
|
||||
margin-right: 0.3em;
|
||||
}
|
||||
|
||||
.listResults{
|
||||
tr>*:first-child{
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
/* This is to avoid long exception message on restore errors */
|
||||
.message_error{
|
||||
max-height: 150px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
84
datamodels/2.x/combodo-db-tools/en.dict.combodo-db-tools.php
Normal file
84
datamodels/2.x/combodo-db-tools/en.dict.combodo-db-tools.php
Normal file
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2013-2020 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
* 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
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* iTop is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
*/
|
||||
|
||||
// Database inconsistencies
|
||||
Dict::Add('EN US', 'English', 'English', array(
|
||||
// Dictionary entries go here
|
||||
'Menu:DBToolsMenu' => 'DB Tools',
|
||||
'DBTools:Class' => 'Class',
|
||||
'DBTools:Title' => 'Database Maintenance Tools',
|
||||
'DBTools:ErrorsFound' => 'Errors Found',
|
||||
'DBTools:Error' => 'Error',
|
||||
'DBTools:Count' => 'Count',
|
||||
'DBTools:SQLquery' => 'SQL query',
|
||||
'DBTools:FixitSQLquery' => 'SQL query To Fix it (indication)',
|
||||
'DBTools:SQLresult' => 'SQL result',
|
||||
'DBTools:NoError' => 'The database is OK',
|
||||
'DBTools:HideIds' => 'Error List',
|
||||
'DBTools:ShowIds' => 'Detailed view',
|
||||
'DBTools:ShowReport' => 'Report',
|
||||
'DBTools:IntegrityCheck' => 'Integrity check',
|
||||
'DBTools:FetchCheck' => 'Fetch Check (long)',
|
||||
|
||||
'DBTools:Analyze' => 'Analyze',
|
||||
'DBTools:Details' => 'Show Details',
|
||||
'DBTools:ShowAll' => 'Show All Errors',
|
||||
|
||||
'DBTools:Inconsistencies' => 'Database inconsistencies',
|
||||
|
||||
'DBAnalyzer-Integrity-OrphanRecord' => 'Orphan record in `%1$s`, it should have its counterpart in table `%2$s`',
|
||||
'DBAnalyzer-Integrity-InvalidExtKey' => 'Invalid external key %1$s (column: `%2$s.%3$s`)',
|
||||
'DBAnalyzer-Integrity-MissingExtKey' => 'Missing external key %1$s (column: `%2$s.%3$s`)',
|
||||
'DBAnalyzer-Integrity-InvalidValue' => 'Invalid value for %1$s (column: `%2$s.%3$s`)',
|
||||
'DBAnalyzer-Integrity-UsersWithoutProfile' => 'Some user accounts have no profile at all',
|
||||
'DBAnalyzer-Fetch-Count-Error' => 'Fetch count error in `%1$s`, %2$d entries fetched / %3$d counted',
|
||||
));
|
||||
|
||||
// Database Info
|
||||
Dict::Add('EN US', 'English', 'English', array(
|
||||
'DBTools:DatabaseInfo' => 'Database Information',
|
||||
'DBTools:Base' => 'Base',
|
||||
'DBTools:Size' => 'Size',
|
||||
));
|
||||
|
||||
// Lost attachments
|
||||
Dict::Add('EN US', 'English', 'English', array(
|
||||
'DBTools:LostAttachments' => 'Lost attachments',
|
||||
'DBTools:LostAttachments:Disclaimer' => 'Here you can search your database for lost or misplaced attachments. This is NOT a data recovery tool, is does not retrieve deleted data.',
|
||||
|
||||
'DBTools:LostAttachments:Button:Analyze' => 'Analyze',
|
||||
'DBTools:LostAttachments:Button:Restore' => 'Restore',
|
||||
'DBTools:LostAttachments:Button:Restore:Confirm' => 'This action cannot be undone, please confirm that you want to restore the selected files.',
|
||||
'DBTools:LostAttachments:Button:Busy' => 'Please wait...',
|
||||
|
||||
'DBTools:LostAttachments:Step:Analyze' => 'First, search for lost/misplaced attachments by analyzing the database.',
|
||||
|
||||
'DBTools:LostAttachments:Step:AnalyzeResults' => 'Analyze results:',
|
||||
'DBTools:LostAttachments:Step:AnalyzeResults:None' => 'Great! Every thing seems to be at the right place.',
|
||||
'DBTools:LostAttachments:Step:AnalyzeResults:Some' => 'Some attachments (%1$d) seem to be misplaced. Take a look at the following list and check the ones you would like to move.',
|
||||
'DBTools:LostAttachments:Step:AnalyzeResults:Item:Filename' => 'Filename',
|
||||
'DBTools:LostAttachments:Step:AnalyzeResults:Item:CurrentLocation' => 'Current location',
|
||||
'DBTools:LostAttachments:Step:AnalyzeResults:Item:TargetLocation' => 'Move to...',
|
||||
|
||||
'DBTools:LostAttachments:Step:RestoreResults' => 'Restore results:',
|
||||
'DBTools:LostAttachments:Step:RestoreResults:Results' => '%1$d/%2$d attachments were restored.',
|
||||
|
||||
'DBTools:LostAttachments:StoredAsInlineImage' => 'Stored as inline image',
|
||||
'DBTools:LostAttachments:History' => 'Attachment "%1$s" restored with DB tools'
|
||||
));
|
||||
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2013-2020 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
* 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
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* iTop is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
*/
|
||||
// Database inconsistencies
|
||||
Dict::Add('ES CR', 'Spanish', 'Español, Castellaño', array(
|
||||
// Dictionary entries go here
|
||||
'Menu:DBToolsMenu' => 'DB Tools~~',
|
||||
'DBTools:Class' => 'Class~~',
|
||||
'DBTools:Title' => 'Database Maintenance Tools~~',
|
||||
'DBTools:ErrorsFound' => 'Errors Found~~',
|
||||
'DBTools:Error' => 'Error~~',
|
||||
'DBTools:Count' => 'Count~~',
|
||||
'DBTools:SQLquery' => 'SQL query~~',
|
||||
'DBTools:FixitSQLquery' => 'SQL query To Fix it (indication)~~',
|
||||
'DBTools:SQLresult' => 'SQL result~~',
|
||||
'DBTools:NoError' => 'The database is OK~~',
|
||||
'DBTools:HideIds' => 'Error List~~',
|
||||
'DBTools:ShowIds' => 'Detailed view~~',
|
||||
'DBTools:ShowReport' => 'Report~~',
|
||||
'DBTools:IntegrityCheck' => 'Integrity check~~',
|
||||
'DBTools:FetchCheck' => 'Fetch Check (long)~~',
|
||||
|
||||
'DBTools:Analyze' => 'Analyze~~',
|
||||
'DBTools:Details' => 'Show Details~~',
|
||||
'DBTools:ShowAll' => 'Show All Errors~~',
|
||||
|
||||
'DBTools:Inconsistencies' => 'Database inconsistencies~~',
|
||||
|
||||
'DBAnalyzer-Integrity-OrphanRecord' => 'Orphan record in `%1$s`, it should have its counterpart in table `%2$s`~~',
|
||||
'DBAnalyzer-Integrity-InvalidExtKey' => 'Invalid external key %1$s (column: `%2$s.%3$s`)~~',
|
||||
'DBAnalyzer-Integrity-MissingExtKey' => 'Missing external key %1$s (column: `%2$s.%3$s`)~~',
|
||||
'DBAnalyzer-Integrity-InvalidValue' => 'Invalid value for %1$s (column: `%2$s.%3$s`)~~',
|
||||
'DBAnalyzer-Integrity-UsersWithoutProfile' => 'Some user accounts have no profile at all~~',
|
||||
'DBAnalyzer-Fetch-Count-Error' => 'Fetch count error in `%1$s`, %2$d entries fetched / %3$d counted~~',
|
||||
));
|
||||
|
||||
// Database Info
|
||||
Dict::Add('ES CR', 'Spanish', 'Español, Castellaño', array(
|
||||
'DBTools:DatabaseInfo' => 'Database Information~~',
|
||||
'DBTools:Base' => 'Base~~',
|
||||
'DBTools:Size' => 'Size~~',
|
||||
));
|
||||
|
||||
// Lost attachments
|
||||
Dict::Add('ES CR', 'Spanish', 'Español, Castellaño', array(
|
||||
'DBTools:LostAttachments' => 'Lost attachments~~',
|
||||
'DBTools:LostAttachments:Disclaimer' => 'Here you can search your database for lost or misplaced attachments. This is NOT a data recovery tool, is does not retrieve deleted data.~~',
|
||||
|
||||
'DBTools:LostAttachments:Button:Analyze' => 'Analyze~~',
|
||||
'DBTools:LostAttachments:Button:Restore' => 'Restore~~',
|
||||
'DBTools:LostAttachments:Button:Restore:Confirm' => 'This action cannot be undone, please confirm that you want to restore the selected files.~~',
|
||||
'DBTools:LostAttachments:Button:Busy' => 'Please wait...~~',
|
||||
|
||||
'DBTools:LostAttachments:Step:Analyze' => 'First, search for lost/misplaced attachments by analyzing the database.~~',
|
||||
|
||||
'DBTools:LostAttachments:Step:AnalyzeResults' => 'Analyze results:~~',
|
||||
'DBTools:LostAttachments:Step:AnalyzeResults:None' => 'Great! Every thing seems to be at the right place.~~',
|
||||
'DBTools:LostAttachments:Step:AnalyzeResults:Some' => 'Some attachments (%1$d) seem to be misplaced. Take a look at the following list and check the ones you would like to move.~~',
|
||||
'DBTools:LostAttachments:Step:AnalyzeResults:Item:Filename' => 'Filename~~',
|
||||
'DBTools:LostAttachments:Step:AnalyzeResults:Item:CurrentLocation' => 'Current location~~',
|
||||
'DBTools:LostAttachments:Step:AnalyzeResults:Item:TargetLocation' => 'Move to...~~',
|
||||
|
||||
'DBTools:LostAttachments:Step:RestoreResults' => 'Restore results:~~',
|
||||
'DBTools:LostAttachments:Step:RestoreResults:Results' => '%1$d/%2$d attachments were restored.~~',
|
||||
|
||||
'DBTools:LostAttachments:StoredAsInlineImage' => 'Stored as inline image~~',
|
||||
'DBTools:LostAttachments:History' => 'Attachment "%1$s" restored with DB tools~~'
|
||||
));
|
||||
82
datamodels/2.x/combodo-db-tools/fr.dict.combodo-db-tools.php
Normal file
82
datamodels/2.x/combodo-db-tools/fr.dict.combodo-db-tools.php
Normal file
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2013-2020 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
* 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
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* iTop is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
*/
|
||||
Dict::Add('FR FR', 'French', 'Français', array(
|
||||
// Dictionary entries go here
|
||||
'Menu:DBToolsMenu' => 'Outils BDD',
|
||||
'DBTools:Class' => 'Classe',
|
||||
'DBTools:Title' => 'Outils maintenance base de données',
|
||||
'DBTools:ErrorsFound' => 'Erreurs trouvées',
|
||||
'DBTools:Error' => 'Erreur',
|
||||
'DBTools:Count' => 'Nombre',
|
||||
'DBTools:SQLquery' => 'Requête SQL',
|
||||
'DBTools:FixitSQLquery' => 'Requête SQL pour nettoyer la base (indication)',
|
||||
'DBTools:SQLresult' => 'Résultat SQL',
|
||||
'DBTools:NoError' => 'La base de données est OK',
|
||||
'DBTools:HideIds' => 'Erreurs',
|
||||
'DBTools:ShowIds' => 'Détails des erreurs',
|
||||
'DBTools:ShowReport' => 'Rapport',
|
||||
'DBTools:IntegrityCheck' => 'Contrôle d\'intégrité',
|
||||
'DBTools:FetchCheck' => 'Contrôle de récupération (long)',
|
||||
|
||||
'DBTools:Analyze' => 'Analyser',
|
||||
'DBTools:Details' => 'Afficher détails',
|
||||
'DBTools:ShowAll' => 'Afficher toutes les erreurs',
|
||||
|
||||
'DBTools:Inconsistencies' => 'Incohérences de base de données',
|
||||
|
||||
'DBAnalyzer-Integrity-OrphanRecord' => 'Enregistrement orphelin dans `%1$s`, il devrait avoir son équivalent dans la tableit `%2$s`',
|
||||
'DBAnalyzer-Integrity-InvalidExtKey' => 'Clef externe invalide %1$s (colonne: `%2$s.%3$s`)',
|
||||
'DBAnalyzer-Integrity-MissingExtKey' => 'Clef externe manquante %1$s (colonne: `%2$s.%3$s`)',
|
||||
'DBAnalyzer-Integrity-InvalidValue' => 'Valeur invalide pour %1$s (colonne: `%2$s.%3$s`)',
|
||||
'DBAnalyzer-Integrity-UsersWithoutProfile' => 'Certains comptes utilisateurs n\'ont aucun profile',
|
||||
'DBAnalyzer-Fetch-Count-Error' => 'Erreur de récupération dans `%1$s`, %2$d enregistrements récupérés / %3$d comptés',
|
||||
));
|
||||
|
||||
// Database Info
|
||||
Dict::Add('FR FR', 'French', 'Français', array(
|
||||
'DBTools:DatabaseInfo' => 'Information Base de Données',
|
||||
'DBTools:Base' => 'Base',
|
||||
'DBTools:Size' => 'Taille',
|
||||
));
|
||||
|
||||
// Lost attachments
|
||||
Dict::Add('FR FR', 'French', 'Français', array(
|
||||
'DBTools:LostAttachments' => 'Pièces jointes perdues',
|
||||
'DBTools:LostAttachments:Disclaimer' => 'Ici vous pouvez retrouver des pièces jointes perdues ou égarées dans votre base de données. Ceci n\'est PAS un outil de récupération des données, il ne récupère pas les données effacées.',
|
||||
|
||||
'DBTools:LostAttachments:Button:Analyze' => 'Analyser',
|
||||
'DBTools:LostAttachments:Button:Restore' => 'Restaurer',
|
||||
'DBTools:LostAttachments:Button:Restore:Confirm' => 'Cet action ne peut être annuler, veuillez confirmer que vous voulez restaurer les fichiers sélectionnés.',
|
||||
'DBTools:LostAttachments:Button:Busy' => 'Patientez ...',
|
||||
|
||||
'DBTools:LostAttachments:Step:Analyze' => 'Tout d\'abord, scannez la base de données à la recherche de pièces jointes perdues/égarées.',
|
||||
|
||||
'DBTools:LostAttachments:Step:AnalyzeResults' => 'Résultat de l\'analyse :',
|
||||
'DBTools:LostAttachments:Step:AnalyzeResults:None' => 'Parfait ! Il semble que tout soit en ordre.',
|
||||
'DBTools:LostAttachments:Step:AnalyzeResults:Some' => 'Certaines pièces jointes (%1$d) semblent être au mauvais endroit. Examinez la liste suivante et cochez celles que vous souhaitez déplacer.',
|
||||
'DBTools:LostAttachments:Step:AnalyzeResults:Item:Filename' => 'Nom de fichier',
|
||||
'DBTools:LostAttachments:Step:AnalyzeResults:Item:CurrentLocation' => 'Emplacement actuel',
|
||||
'DBTools:LostAttachments:Step:AnalyzeResults:Item:TargetLocation' => 'Déplacer vers ...',
|
||||
|
||||
'DBTools:LostAttachments:Step:RestoreResults' => 'Résultats de la restauration :',
|
||||
'DBTools:LostAttachments:Step:RestoreResults:Results' => '%1$d/%2$d pièces jointes ont été restaurées.',
|
||||
|
||||
'DBTools:LostAttachments:StoredAsInlineImage' => 'Stockée comme "InlineImage"',
|
||||
'DBTools:LostAttachments:History' => 'Pièce jointe "%1$s" restaurée avec l\'outil de BDD'
|
||||
));
|
||||
83
datamodels/2.x/combodo-db-tools/hu.dict.combodo-db-tools.php
Normal file
83
datamodels/2.x/combodo-db-tools/hu.dict.combodo-db-tools.php
Normal file
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2013-2020 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
* 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
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* iTop is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
*/
|
||||
// Database inconsistencies
|
||||
Dict::Add('HU HU', 'Hungarian', 'Magyar', array(
|
||||
// Dictionary entries go here
|
||||
'Menu:DBToolsMenu' => 'DB Tools~~',
|
||||
'DBTools:Class' => 'Class~~',
|
||||
'DBTools:Title' => 'Database Maintenance Tools~~',
|
||||
'DBTools:ErrorsFound' => 'Errors Found~~',
|
||||
'DBTools:Error' => 'Error~~',
|
||||
'DBTools:Count' => 'Count~~',
|
||||
'DBTools:SQLquery' => 'SQL query~~',
|
||||
'DBTools:FixitSQLquery' => 'SQL query To Fix it (indication)~~',
|
||||
'DBTools:SQLresult' => 'SQL result~~',
|
||||
'DBTools:NoError' => 'The database is OK~~',
|
||||
'DBTools:HideIds' => 'Error List~~',
|
||||
'DBTools:ShowIds' => 'Detailed view~~',
|
||||
'DBTools:ShowReport' => 'Report~~',
|
||||
'DBTools:IntegrityCheck' => 'Integrity check~~',
|
||||
'DBTools:FetchCheck' => 'Fetch Check (long)~~',
|
||||
|
||||
'DBTools:Analyze' => 'Analyze~~',
|
||||
'DBTools:Details' => 'Show Details~~',
|
||||
'DBTools:ShowAll' => 'Show All Errors~~',
|
||||
|
||||
'DBTools:Inconsistencies' => 'Database inconsistencies~~',
|
||||
|
||||
'DBAnalyzer-Integrity-OrphanRecord' => 'Orphan record in `%1$s`, it should have its counterpart in table `%2$s`~~',
|
||||
'DBAnalyzer-Integrity-InvalidExtKey' => 'Invalid external key %1$s (column: `%2$s.%3$s`)~~',
|
||||
'DBAnalyzer-Integrity-MissingExtKey' => 'Missing external key %1$s (column: `%2$s.%3$s`)~~',
|
||||
'DBAnalyzer-Integrity-InvalidValue' => 'Invalid value for %1$s (column: `%2$s.%3$s`)~~',
|
||||
'DBAnalyzer-Integrity-UsersWithoutProfile' => 'Some user accounts have no profile at all~~',
|
||||
'DBAnalyzer-Fetch-Count-Error' => 'Fetch count error in `%1$s`, %2$d entries fetched / %3$d counted~~',
|
||||
));
|
||||
|
||||
// Database Info
|
||||
Dict::Add('HU HU', 'Hungarian', 'Magyar', array(
|
||||
'DBTools:DatabaseInfo' => 'Database Information~~',
|
||||
'DBTools:Base' => 'Base~~',
|
||||
'DBTools:Size' => 'Size~~',
|
||||
));
|
||||
|
||||
// Lost attachments
|
||||
Dict::Add('HU HU', 'Hungarian', 'Magyar', array(
|
||||
'DBTools:LostAttachments' => 'Lost attachments~~',
|
||||
'DBTools:LostAttachments:Disclaimer' => 'Here you can search your database for lost or misplaced attachments. This is NOT a data recovery tool, is does not retrieve deleted data.~~',
|
||||
|
||||
'DBTools:LostAttachments:Button:Analyze' => 'Analyze~~',
|
||||
'DBTools:LostAttachments:Button:Restore' => 'Restore~~',
|
||||
'DBTools:LostAttachments:Button:Restore:Confirm' => 'This action cannot be undone, please confirm that you want to restore the selected files.~~',
|
||||
'DBTools:LostAttachments:Button:Busy' => 'Please wait...~~',
|
||||
|
||||
'DBTools:LostAttachments:Step:Analyze' => 'First, search for lost/misplaced attachments by analyzing the database.~~',
|
||||
|
||||
'DBTools:LostAttachments:Step:AnalyzeResults' => 'Analyze results:~~',
|
||||
'DBTools:LostAttachments:Step:AnalyzeResults:None' => 'Great! Every thing seems to be at the right place.~~',
|
||||
'DBTools:LostAttachments:Step:AnalyzeResults:Some' => 'Some attachments (%1$d) seem to be misplaced. Take a look at the following list and check the ones you would like to move.~~',
|
||||
'DBTools:LostAttachments:Step:AnalyzeResults:Item:Filename' => 'Filename~~',
|
||||
'DBTools:LostAttachments:Step:AnalyzeResults:Item:CurrentLocation' => 'Current location~~',
|
||||
'DBTools:LostAttachments:Step:AnalyzeResults:Item:TargetLocation' => 'Move to...~~',
|
||||
|
||||
'DBTools:LostAttachments:Step:RestoreResults' => 'Restore results:~~',
|
||||
'DBTools:LostAttachments:Step:RestoreResults:Results' => '%1$d/%2$d attachments were restored.~~',
|
||||
|
||||
'DBTools:LostAttachments:StoredAsInlineImage' => 'Stored as inline image~~',
|
||||
'DBTools:LostAttachments:History' => 'Attachment "%1$s" restored with DB tools~~'
|
||||
));
|
||||
83
datamodels/2.x/combodo-db-tools/it.dict.combodo-db-tools.php
Normal file
83
datamodels/2.x/combodo-db-tools/it.dict.combodo-db-tools.php
Normal file
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2013-2020 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
* 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
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* iTop is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
*/
|
||||
// Database inconsistencies
|
||||
Dict::Add('IT IT', 'Italian', 'Italiano', array(
|
||||
// Dictionary entries go here
|
||||
'Menu:DBToolsMenu' => 'DB Tools~~',
|
||||
'DBTools:Class' => 'Class~~',
|
||||
'DBTools:Title' => 'Database Maintenance Tools~~',
|
||||
'DBTools:ErrorsFound' => 'Errors Found~~',
|
||||
'DBTools:Error' => 'Error~~',
|
||||
'DBTools:Count' => 'Count~~',
|
||||
'DBTools:SQLquery' => 'SQL query~~',
|
||||
'DBTools:FixitSQLquery' => 'SQL query To Fix it (indication)~~',
|
||||
'DBTools:SQLresult' => 'SQL result~~',
|
||||
'DBTools:NoError' => 'The database is OK~~',
|
||||
'DBTools:HideIds' => 'Error List~~',
|
||||
'DBTools:ShowIds' => 'Detailed view~~',
|
||||
'DBTools:ShowReport' => 'Report~~',
|
||||
'DBTools:IntegrityCheck' => 'Integrity check~~',
|
||||
'DBTools:FetchCheck' => 'Fetch Check (long)~~',
|
||||
|
||||
'DBTools:Analyze' => 'Analyze~~',
|
||||
'DBTools:Details' => 'Show Details~~',
|
||||
'DBTools:ShowAll' => 'Show All Errors~~',
|
||||
|
||||
'DBTools:Inconsistencies' => 'Database inconsistencies~~',
|
||||
|
||||
'DBAnalyzer-Integrity-OrphanRecord' => 'Orphan record in `%1$s`, it should have its counterpart in table `%2$s`~~',
|
||||
'DBAnalyzer-Integrity-InvalidExtKey' => 'Invalid external key %1$s (column: `%2$s.%3$s`)~~',
|
||||
'DBAnalyzer-Integrity-MissingExtKey' => 'Missing external key %1$s (column: `%2$s.%3$s`)~~',
|
||||
'DBAnalyzer-Integrity-InvalidValue' => 'Invalid value for %1$s (column: `%2$s.%3$s`)~~',
|
||||
'DBAnalyzer-Integrity-UsersWithoutProfile' => 'Some user accounts have no profile at all~~',
|
||||
'DBAnalyzer-Fetch-Count-Error' => 'Fetch count error in `%1$s`, %2$d entries fetched / %3$d counted~~',
|
||||
));
|
||||
|
||||
// Database Info
|
||||
Dict::Add('IT IT', 'Italian', 'Italiano', array(
|
||||
'DBTools:DatabaseInfo' => 'Database Information~~',
|
||||
'DBTools:Base' => 'Base~~',
|
||||
'DBTools:Size' => 'Size~~',
|
||||
));
|
||||
|
||||
// Lost attachments
|
||||
Dict::Add('IT IT', 'Italian', 'Italiano', array(
|
||||
'DBTools:LostAttachments' => 'Lost attachments~~',
|
||||
'DBTools:LostAttachments:Disclaimer' => 'Here you can search your database for lost or misplaced attachments. This is NOT a data recovery tool, is does not retrieve deleted data.~~',
|
||||
|
||||
'DBTools:LostAttachments:Button:Analyze' => 'Analyze~~',
|
||||
'DBTools:LostAttachments:Button:Restore' => 'Restore~~',
|
||||
'DBTools:LostAttachments:Button:Restore:Confirm' => 'This action cannot be undone, please confirm that you want to restore the selected files.~~',
|
||||
'DBTools:LostAttachments:Button:Busy' => 'Please wait...~~',
|
||||
|
||||
'DBTools:LostAttachments:Step:Analyze' => 'First, search for lost/misplaced attachments by analyzing the database.~~',
|
||||
|
||||
'DBTools:LostAttachments:Step:AnalyzeResults' => 'Analyze results:~~',
|
||||
'DBTools:LostAttachments:Step:AnalyzeResults:None' => 'Great! Every thing seems to be at the right place.~~',
|
||||
'DBTools:LostAttachments:Step:AnalyzeResults:Some' => 'Some attachments (%1$d) seem to be misplaced. Take a look at the following list and check the ones you would like to move.~~',
|
||||
'DBTools:LostAttachments:Step:AnalyzeResults:Item:Filename' => 'Filename~~',
|
||||
'DBTools:LostAttachments:Step:AnalyzeResults:Item:CurrentLocation' => 'Current location~~',
|
||||
'DBTools:LostAttachments:Step:AnalyzeResults:Item:TargetLocation' => 'Move to...~~',
|
||||
|
||||
'DBTools:LostAttachments:Step:RestoreResults' => 'Restore results:~~',
|
||||
'DBTools:LostAttachments:Step:RestoreResults:Results' => '%1$d/%2$d attachments were restored.~~',
|
||||
|
||||
'DBTools:LostAttachments:StoredAsInlineImage' => 'Stored as inline image~~',
|
||||
'DBTools:LostAttachments:History' => 'Attachment "%1$s" restored with DB tools~~'
|
||||
));
|
||||
83
datamodels/2.x/combodo-db-tools/ja.dict.combodo-db-tools.php
Normal file
83
datamodels/2.x/combodo-db-tools/ja.dict.combodo-db-tools.php
Normal file
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2013-2020 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
* 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
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* iTop is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
*/
|
||||
// Database inconsistencies
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
// Dictionary entries go here
|
||||
'Menu:DBToolsMenu' => 'DB Tools~~',
|
||||
'DBTools:Class' => 'Class~~',
|
||||
'DBTools:Title' => 'Database Maintenance Tools~~',
|
||||
'DBTools:ErrorsFound' => 'Errors Found~~',
|
||||
'DBTools:Error' => 'Error~~',
|
||||
'DBTools:Count' => 'Count~~',
|
||||
'DBTools:SQLquery' => 'SQL query~~',
|
||||
'DBTools:FixitSQLquery' => 'SQL query To Fix it (indication)~~',
|
||||
'DBTools:SQLresult' => 'SQL result~~',
|
||||
'DBTools:NoError' => 'The database is OK~~',
|
||||
'DBTools:HideIds' => 'Error List~~',
|
||||
'DBTools:ShowIds' => 'Detailed view~~',
|
||||
'DBTools:ShowReport' => 'Report~~',
|
||||
'DBTools:IntegrityCheck' => 'Integrity check~~',
|
||||
'DBTools:FetchCheck' => 'Fetch Check (long)~~',
|
||||
|
||||
'DBTools:Analyze' => 'Analyze~~',
|
||||
'DBTools:Details' => 'Show Details~~',
|
||||
'DBTools:ShowAll' => 'Show All Errors~~',
|
||||
|
||||
'DBTools:Inconsistencies' => 'Database inconsistencies~~',
|
||||
|
||||
'DBAnalyzer-Integrity-OrphanRecord' => 'Orphan record in `%1$s`, it should have its counterpart in table `%2$s`~~',
|
||||
'DBAnalyzer-Integrity-InvalidExtKey' => 'Invalid external key %1$s (column: `%2$s.%3$s`)~~',
|
||||
'DBAnalyzer-Integrity-MissingExtKey' => 'Missing external key %1$s (column: `%2$s.%3$s`)~~',
|
||||
'DBAnalyzer-Integrity-InvalidValue' => 'Invalid value for %1$s (column: `%2$s.%3$s`)~~',
|
||||
'DBAnalyzer-Integrity-UsersWithoutProfile' => 'Some user accounts have no profile at all~~',
|
||||
'DBAnalyzer-Fetch-Count-Error' => 'Fetch count error in `%1$s`, %2$d entries fetched / %3$d counted~~',
|
||||
));
|
||||
|
||||
// Database Info
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'DBTools:DatabaseInfo' => 'Database Information~~',
|
||||
'DBTools:Base' => 'Base~~',
|
||||
'DBTools:Size' => 'Size~~',
|
||||
));
|
||||
|
||||
// Lost attachments
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'DBTools:LostAttachments' => 'Lost attachments~~',
|
||||
'DBTools:LostAttachments:Disclaimer' => 'Here you can search your database for lost or misplaced attachments. This is NOT a data recovery tool, is does not retrieve deleted data.~~',
|
||||
|
||||
'DBTools:LostAttachments:Button:Analyze' => 'Analyze~~',
|
||||
'DBTools:LostAttachments:Button:Restore' => 'Restore~~',
|
||||
'DBTools:LostAttachments:Button:Restore:Confirm' => 'This action cannot be undone, please confirm that you want to restore the selected files.~~',
|
||||
'DBTools:LostAttachments:Button:Busy' => 'Please wait...~~',
|
||||
|
||||
'DBTools:LostAttachments:Step:Analyze' => 'First, search for lost/misplaced attachments by analyzing the database.~~',
|
||||
|
||||
'DBTools:LostAttachments:Step:AnalyzeResults' => 'Analyze results:~~',
|
||||
'DBTools:LostAttachments:Step:AnalyzeResults:None' => 'Great! Every thing seems to be at the right place.~~',
|
||||
'DBTools:LostAttachments:Step:AnalyzeResults:Some' => 'Some attachments (%1$d) seem to be misplaced. Take a look at the following list and check the ones you would like to move.~~',
|
||||
'DBTools:LostAttachments:Step:AnalyzeResults:Item:Filename' => 'Filename~~',
|
||||
'DBTools:LostAttachments:Step:AnalyzeResults:Item:CurrentLocation' => 'Current location~~',
|
||||
'DBTools:LostAttachments:Step:AnalyzeResults:Item:TargetLocation' => 'Move to...~~',
|
||||
|
||||
'DBTools:LostAttachments:Step:RestoreResults' => 'Restore results:~~',
|
||||
'DBTools:LostAttachments:Step:RestoreResults:Results' => '%1$d/%2$d attachments were restored.~~',
|
||||
|
||||
'DBTools:LostAttachments:StoredAsInlineImage' => 'Stored as inline image~~',
|
||||
'DBTools:LostAttachments:History' => 'Attachment "%1$s" restored with DB tools~~'
|
||||
));
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user