mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-14 07:54:10 +01:00
Compare commits
479 Commits
feature/as
...
feature/25
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8fc5dadad9 | ||
|
|
036a5d623b | ||
|
|
e8e8828f66 | ||
|
|
bbdef6b730 | ||
|
|
dd2f6e7413 | ||
|
|
ab4993debe | ||
|
|
455ce42a2f | ||
|
|
f4ebbfe8ea | ||
|
|
8d9069728a | ||
|
|
80c699c56a | ||
|
|
e923c0fef3 | ||
|
|
70fd8ed128 | ||
|
|
196ceba1bb | ||
|
|
7d82057e66 | ||
|
|
fc9abc95cb | ||
|
|
ddff020a1d | ||
|
|
b803db38b9 | ||
|
|
010edf1407 | ||
|
|
0006491304 | ||
|
|
e0674fb797 | ||
|
|
f4fbbf3a4f | ||
|
|
392957d849 | ||
|
|
71604e65d2 | ||
|
|
648692409b | ||
|
|
950f283e9b | ||
|
|
10e2679887 | ||
|
|
8e789d51ce | ||
|
|
7ed43c3e50 | ||
|
|
90fc39c409 | ||
|
|
88a0678149 | ||
|
|
1f7d9c0d0f | ||
|
|
e4c025a7f6 | ||
|
|
f9d1475147 | ||
|
|
be173eaf1b | ||
|
|
b7e69c65a8 | ||
|
|
980cecccad | ||
|
|
e2115e61df | ||
|
|
e013c28d67 | ||
|
|
f7d37b7ee1 | ||
|
|
a2b1b77798 | ||
|
|
aa048b65f3 | ||
|
|
c1e915188a | ||
|
|
4b374c7e9e | ||
|
|
554fec71f0 | ||
|
|
c4385c1627 | ||
|
|
2cf62dc72e | ||
|
|
ecf4658d2c | ||
|
|
26826197ce | ||
|
|
f52bfddc58 | ||
|
|
540ff50ce1 | ||
|
|
fa41afccc8 | ||
|
|
31db7201c6 | ||
|
|
4375e4085c | ||
|
|
fbfbc78e2d | ||
|
|
6746136db3 | ||
|
|
ccb60a2d41 | ||
|
|
b799a38ec4 | ||
|
|
ff3da21f36 | ||
|
|
2ee4595952 | ||
|
|
40a1ca98e1 | ||
|
|
ab28f59a19 | ||
|
|
4a6804d084 | ||
|
|
1e4cf8931b | ||
|
|
3c2a4c880b | ||
|
|
28ddfe763c | ||
|
|
ad814df467 | ||
|
|
bcc42a09e3 | ||
|
|
e655e80157 | ||
|
|
1098e68bd0 | ||
|
|
b48e3e8bc5 | ||
|
|
346b105054 | ||
|
|
14095baf67 | ||
|
|
199e02aa43 | ||
|
|
30ff03bce0 | ||
|
|
a4d1218707 | ||
|
|
b0bf38f0a4 | ||
|
|
ec72dc9cff | ||
|
|
ea9c458c9f | ||
|
|
500ae157b3 | ||
|
|
5de3a5331b | ||
|
|
fddf54b863 | ||
|
|
9fba36ae29 | ||
|
|
d2ca1d59a6 | ||
|
|
714079df9f | ||
|
|
b18733ac31 | ||
|
|
32ce6ac336 | ||
|
|
36de69b3d0 | ||
|
|
17b05efbba | ||
|
|
079cceb48b | ||
|
|
0c5e032d9a | ||
|
|
407b41155c | ||
|
|
c2479757f4 | ||
|
|
2d27794f85 | ||
|
|
47f0302967 | ||
|
|
d9f49a7958 | ||
|
|
8da798be3b | ||
|
|
e49b3c7366 | ||
|
|
d54abbe401 | ||
|
|
23a84b7864 | ||
|
|
5836b2a403 | ||
|
|
50feffe40f | ||
|
|
c9682227b8 | ||
|
|
b7f0915e2f | ||
|
|
de93208fde | ||
|
|
e07e435f65 | ||
|
|
d8876eef24 | ||
|
|
e05b519215 | ||
|
|
67e288fbc8 | ||
|
|
621b71f672 | ||
|
|
4adefa5cd8 | ||
|
|
4993240c19 | ||
|
|
c21169d6a7 | ||
|
|
af78129b7d | ||
|
|
3175734b4f | ||
|
|
a27a4d9f64 | ||
|
|
132876fc57 | ||
|
|
a454e9cb84 | ||
|
|
7e6389eac2 | ||
|
|
4b86b1680b | ||
|
|
1d6d58384c | ||
|
|
f1f2a74394 | ||
|
|
bf575889cc | ||
|
|
43a9fee52b | ||
|
|
fd1a457ac3 | ||
|
|
afd8c487c4 | ||
|
|
41b92e2d3d | ||
|
|
b12d185376 | ||
|
|
eaac1c293e | ||
|
|
f7a97bd590 | ||
|
|
29136c269a | ||
|
|
1db8aa811e | ||
|
|
d44d538faf | ||
|
|
8f5cb404c4 | ||
|
|
caef7a244e | ||
|
|
bd514f7a9a | ||
|
|
212b98724b | ||
|
|
afcbc8ce40 | ||
|
|
df68d2a8da | ||
|
|
6870d4f4db | ||
|
|
7553ee2510 | ||
|
|
1a999b1a1c | ||
|
|
182ae5d3aa | ||
|
|
4edaacc2f5 | ||
|
|
c98a11623e | ||
|
|
9feb15f5f6 | ||
|
|
a7941c932b | ||
|
|
4cfc2a1b26 | ||
|
|
7db88f256f | ||
|
|
0066b24e8f | ||
|
|
1b96f5b071 | ||
|
|
4b2ae38173 | ||
|
|
a13e2b0b00 | ||
|
|
8f09b8149b | ||
|
|
ff69719b8e | ||
|
|
9c35d9edc2 | ||
|
|
f9f75f9117 | ||
|
|
48e3d7f67f | ||
|
|
0246951cf8 | ||
|
|
fbd76e6969 | ||
|
|
559fe0be01 | ||
|
|
e6a8238924 | ||
|
|
496f548aea | ||
|
|
4a2e37fa84 | ||
|
|
315f275a6d | ||
|
|
d6118d5a96 | ||
|
|
572793b7b8 | ||
|
|
391ec877c8 | ||
|
|
4151aa5ac1 | ||
|
|
c36939cf85 | ||
|
|
3b0897fd9c | ||
|
|
a11c87c6c2 | ||
|
|
0a2492228b | ||
|
|
36a1dbd34d | ||
|
|
fc988d1eb0 | ||
|
|
8d0f685fad | ||
|
|
9974d59f15 | ||
|
|
47aee14362 | ||
|
|
a31e3450bf | ||
|
|
c931e3f18a | ||
|
|
185e03d8e8 | ||
|
|
e8f0542f11 | ||
|
|
69fa0f71d0 | ||
|
|
03e8e77596 | ||
|
|
c67bf66bd9 | ||
|
|
3c23b04608 | ||
|
|
0891272aa3 | ||
|
|
c6c3f7b421 | ||
|
|
5f3aa0d083 | ||
|
|
046ce13073 | ||
|
|
a64ab695ce | ||
|
|
020e58b112 | ||
|
|
c372707124 | ||
|
|
6a462d25e0 | ||
|
|
288ffd1830 | ||
|
|
02c3ca4724 | ||
|
|
5b5ab86862 | ||
|
|
62122b0ee6 | ||
|
|
7aaa4a2b0d | ||
|
|
786651b35c | ||
|
|
30b793eed8 | ||
|
|
3f3d9b3d2e | ||
|
|
dc3c6ea6ce | ||
|
|
a73321dd02 | ||
|
|
3edcdc452e | ||
|
|
0c93971e13 | ||
|
|
5a59b1870d | ||
|
|
19bb7e5043 | ||
|
|
8e08be2258 | ||
|
|
22834d32a3 | ||
|
|
23407cd095 | ||
|
|
8403273c0b | ||
|
|
d5dc3c0d74 | ||
|
|
fbbdcfa7b9 | ||
|
|
7a528e276f | ||
|
|
ed55bfa6aa | ||
|
|
7f62a78529 | ||
|
|
cf51bddbc9 | ||
|
|
adf3902c37 | ||
|
|
6f5bed6b98 | ||
|
|
7079cab1de | ||
|
|
19188ac2fc | ||
|
|
d543e311dd | ||
|
|
19ea531961 | ||
|
|
9bee4bdb5c | ||
|
|
2b4e2939fe | ||
|
|
2c8eac0e3b | ||
|
|
2dd38e81c5 | ||
|
|
c052c40f9d | ||
|
|
89fff9075d | ||
|
|
97b4c80e0b | ||
|
|
905388825c | ||
|
|
d02dec7a09 | ||
|
|
438ecfebdf | ||
|
|
8aa7e52fa2 | ||
|
|
27642d5872 | ||
|
|
4754009d4f | ||
|
|
967911c538 | ||
|
|
b3f069fec0 | ||
|
|
59db7535c3 | ||
|
|
f1657ac695 | ||
|
|
d307f4861f | ||
|
|
6341e7e263 | ||
|
|
0efec39071 | ||
|
|
e1ebeac986 | ||
|
|
68c5d7d33b | ||
|
|
2cefaba0d8 | ||
|
|
a57de6f090 | ||
|
|
6e63254a6b | ||
|
|
2ae2407c24 | ||
|
|
d970f0e1e4 | ||
|
|
b3ce941e5a | ||
|
|
8976ad3635 | ||
|
|
03d12d2485 | ||
|
|
582da19aaa | ||
|
|
62aa33f0f3 | ||
|
|
8bb75006ba | ||
|
|
b1881f1847 | ||
|
|
03759dffbb | ||
|
|
ada0126f9e | ||
|
|
d897ddeed3 | ||
|
|
eb14ef3c30 | ||
|
|
e12f6c92b2 | ||
|
|
1dbc62ddf1 | ||
|
|
e6ac5f48b7 | ||
|
|
d32b6cc0b9 | ||
|
|
63b70aa99b | ||
|
|
71e006054d | ||
|
|
65c23c58c3 | ||
|
|
8605d8667d | ||
|
|
084b10a9a6 | ||
|
|
5ee18637bb | ||
|
|
bdbdd812e9 | ||
|
|
2d43b8946d | ||
|
|
e5100ddeed | ||
|
|
ea9588761d | ||
|
|
16b34ab4e7 | ||
|
|
7bb8fbc793 | ||
|
|
0816d3c84a | ||
|
|
66c5034ff2 | ||
|
|
03c097f5a1 | ||
|
|
87ca02dba3 | ||
|
|
f4ba1a15fe | ||
|
|
1977fe8cb0 | ||
|
|
91d0209253 | ||
|
|
3bee8de25e | ||
|
|
52db2a58ea | ||
|
|
16f0927d92 | ||
|
|
bd64479687 | ||
|
|
8436970132 | ||
|
|
08f35f451f | ||
|
|
dd441afa22 | ||
|
|
5d8184a673 | ||
|
|
db91ed0c1d | ||
|
|
e890d62ab1 | ||
|
|
6d2b457185 | ||
|
|
4328fc78dc | ||
|
|
37914e2b7f | ||
|
|
0551102364 | ||
|
|
1ca369041d | ||
|
|
2a6a4d3460 | ||
|
|
9edc15f50d | ||
|
|
6acb89a2fc | ||
|
|
19803c004d | ||
|
|
20de262e25 | ||
|
|
c870fc5922 | ||
|
|
09c4a4361a | ||
|
|
3544aa4d50 | ||
|
|
d080898b1d | ||
|
|
78282a80ef | ||
|
|
3c8a198738 | ||
|
|
4205988f79 | ||
|
|
517ef9f3cf | ||
|
|
f6d94ec2b5 | ||
|
|
0d9210777c | ||
|
|
bd86e02872 | ||
|
|
095fed9d4c | ||
|
|
734424aa8a | ||
|
|
bf467f664c | ||
|
|
51d960a229 | ||
|
|
63d7a25982 | ||
|
|
614cf7b3c8 | ||
|
|
ea20d30ad1 | ||
|
|
3fc16deed2 | ||
|
|
78e51c1209 | ||
|
|
b96ff56dfd | ||
|
|
bdeed2a14c | ||
|
|
a63813f284 | ||
|
|
0ec54bccd2 | ||
|
|
aa83d1160c | ||
|
|
dab7fb6c53 | ||
|
|
bdd188f9e8 | ||
|
|
6d1abd17a2 | ||
|
|
149fdbe9e4 | ||
|
|
23ba1b41e3 | ||
|
|
c958f45433 | ||
|
|
506780ceed | ||
|
|
bf2d70f952 | ||
|
|
73f2311ca4 | ||
|
|
6c4e0c3718 | ||
|
|
28c4ebc7ea | ||
|
|
d692e1562d | ||
|
|
4284ed955b | ||
|
|
854290dd2d | ||
|
|
1cf995b0c1 | ||
|
|
284aa0a20f | ||
|
|
a5887e20be | ||
|
|
f0acbdf478 | ||
|
|
8a2770cf13 | ||
|
|
27c1a23ecf | ||
|
|
67089a6ad2 | ||
|
|
a711e39976 | ||
|
|
c1535f07fb | ||
|
|
97ddb2e214 | ||
|
|
a2adfe31d8 | ||
|
|
b3c4edc332 | ||
|
|
3b680a6f94 | ||
|
|
9e92a88cba | ||
|
|
38dbae2bb6 | ||
|
|
b830398ca3 | ||
|
|
1e7d1c48c3 | ||
|
|
5bfe501bf4 | ||
|
|
e55d12fae6 | ||
|
|
0d8857f989 | ||
|
|
81688e9c86 | ||
|
|
51ceadd882 | ||
|
|
71d2ed0402 | ||
|
|
a09521ca6b | ||
|
|
17b2bb058d | ||
|
|
9433fbbfd1 | ||
|
|
ae5b9aac8a | ||
|
|
7088047a5e | ||
|
|
b5d8740ab0 | ||
|
|
e0e5b094a4 | ||
|
|
9dc21cc91f | ||
|
|
99c16135c3 | ||
|
|
849f74147c | ||
|
|
3543115730 | ||
|
|
1f5c1df50c | ||
|
|
d917a4cad3 | ||
|
|
6bc96fb6eb | ||
|
|
22dbb0984d | ||
|
|
5c5a184388 | ||
|
|
3ee0b3a5e1 | ||
|
|
16907d414e | ||
|
|
e928054e9c | ||
|
|
b5eb93dbd1 | ||
|
|
31a4c38638 | ||
|
|
d6c73c8142 | ||
|
|
2ed9dc6f31 | ||
|
|
fa51ef1adb | ||
|
|
f2b2d422a6 | ||
|
|
c58161b9b4 | ||
|
|
0a32ddb8e2 | ||
|
|
161a05132b | ||
|
|
3967a82719 | ||
|
|
ce9425f273 | ||
|
|
4af8f54f26 | ||
|
|
bb904d7ec3 | ||
|
|
426da64c46 | ||
|
|
6b4bfb0238 | ||
|
|
8420ef38ac | ||
|
|
db8f657c8e | ||
|
|
a3d881715e | ||
|
|
db9e932fc1 | ||
|
|
0cd9b08bcb | ||
|
|
4b7d589c9f | ||
|
|
2554477987 | ||
|
|
3d0dc422dc | ||
|
|
b469a16a05 | ||
|
|
995d6654fd | ||
|
|
57892f58d8 | ||
|
|
5c4def502c | ||
|
|
0d61f5ac6b | ||
|
|
86cfe10e96 | ||
|
|
8042364a3b | ||
|
|
9b29c45f2b | ||
|
|
d10d5a6062 | ||
|
|
cc38a03d17 | ||
|
|
e640443ea5 | ||
|
|
7f7cf50143 | ||
|
|
3c639bdce3 | ||
|
|
77448a7fc9 | ||
|
|
41c2a9e97a | ||
|
|
080c72eec7 | ||
|
|
c8de4a4682 | ||
|
|
c4d465574c | ||
|
|
d776589fed | ||
|
|
22895462df | ||
|
|
34f4c4102d | ||
|
|
8c79499ace | ||
|
|
e7c62c9ef2 | ||
|
|
96154bd02d | ||
|
|
6ecf784bc5 | ||
|
|
8748a1e51d | ||
|
|
ffad7784aa | ||
|
|
d4dc6c1860 | ||
|
|
a1f92a1b4c | ||
|
|
33a61a6daa | ||
|
|
0ddd73bb36 | ||
|
|
a0a61837e7 | ||
|
|
b8d6990f17 | ||
|
|
4b47eae92c | ||
|
|
7dff1bb26f | ||
|
|
7e0e511b4b | ||
|
|
1e5cb01b15 | ||
|
|
159496afd7 | ||
|
|
9178144675 | ||
|
|
5264edb7ea | ||
|
|
bcf05493d7 | ||
|
|
599d34921f | ||
|
|
f5646d6794 | ||
|
|
842dce7c9c | ||
|
|
cf15f087d4 | ||
|
|
376ec1763f | ||
|
|
45d29cf3b4 | ||
|
|
68d16625ce | ||
|
|
412cef4893 | ||
|
|
2f6980ab2b | ||
|
|
cab3705ed1 | ||
|
|
69d33d03c8 | ||
|
|
9a7a4b6056 | ||
|
|
b3b0c2966b | ||
|
|
92b4e4bb94 | ||
|
|
3e28ec3cd4 | ||
|
|
a4fae555c7 | ||
|
|
dbc6b955b4 | ||
|
|
786be188e4 | ||
|
|
7821a9552d | ||
|
|
2377bd8eac | ||
|
|
3be8fa7a80 | ||
|
|
12bdead661 | ||
|
|
ad8d49a6af | ||
|
|
0612903c7b | ||
|
|
3c68bd0c37 | ||
|
|
7a178e9d9f | ||
|
|
1c643aa36c | ||
|
|
40c76eb36a | ||
|
|
f5190a9dcd | ||
|
|
254c4f5065 |
@@ -1,938 +0,0 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2024 Combodo SAS
|
||||
//
|
||||
// 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/>
|
||||
|
||||
use Combodo\iTop\Application\TwigBase\Twig\TwigHelper;
|
||||
use Combodo\iTop\Application\UI\Base\Component\DataTable\DataTableUIBlockFactory;
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
use Combodo\iTop\Service\Notification\NotificationsRepository;
|
||||
use Combodo\iTop\Service\Notification\NotificationsService;
|
||||
use Combodo\iTop\Service\Router\Router;
|
||||
|
||||
/**
|
||||
* Persistent classes (internal): user defined actions
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
|
||||
require_once(APPROOT.'/core/asynctask.class.inc.php');
|
||||
require_once(APPROOT.'/core/email.class.inc.php');
|
||||
|
||||
/**
|
||||
* A user defined action, to customize the application
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
abstract class Action extends cmdbAbstractObject
|
||||
{
|
||||
/**
|
||||
* @throws \CoreException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "grant_by_profile,core/cmdb",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "name",
|
||||
"complementary_name_attcode" => ['finalclass', 'description'],
|
||||
"state_attcode" => "status",
|
||||
"reconc_keys" => ['name'],
|
||||
"db_table" => "priv_action",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "realclass",
|
||||
"style" => new ormStyle("ibo-dm-class--Action", "ibo-dm-class-alt--Action", "var(--ibo-dm-class--Action--main-color)", "var(--ibo-dm-class--Action--complementary-color)", null, '../images/icons/icons8-in-transit.svg'),
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values" => null, "sql" => "name", "default_value" => null, "is_null_allowed" => false, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values" => null, "sql" => "description", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("status", array(
|
||||
"allowed_values" => new ValueSetEnum(array('test' => 'Being tested', 'enabled' => 'In production', 'disabled' => 'Inactive')),
|
||||
"styled_values" => [
|
||||
'test' => new ormStyle('ibo-dm-enum--Action-status-test', 'ibo-dm-enum-alt--Action-status-test', 'var(--ibo-dm-enum--Action-status-test--main-color)', 'var(--ibo-dm-enum--Action-status-test--complementary-color)', null, null),
|
||||
'enabled' => new ormStyle('ibo-dm-enum--Action-status-enabled', 'ibo-dm-enum-alt--Action-status-enabled', 'var(--ibo-dm-enum--Action-status-enabled--main-color)', 'var(--ibo-dm-enum--Action-status-enabled--complementary-color)', 'fas fa-check', null),
|
||||
'disabled' => new ormStyle('ibo-dm-enum--Action-status-disabled', 'ibo-dm-enum-alt--Action-status-disabled', 'var(--ibo-dm-enum--Action-status-disabled--main-color)', 'var(--ibo-dm-enum--Action-status-disabled--complementary-color)', null, null),
|
||||
],
|
||||
"display_style" => 'list',
|
||||
"sql" => "status",
|
||||
"default_value" => "test",
|
||||
"is_null_allowed" => false,
|
||||
"depends_on" => array(),
|
||||
)));
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect("trigger_list",
|
||||
array("linked_class" => "lnkTriggerAction", "ext_key_to_me" => "action_id", "ext_key_to_remote" => "trigger_id", "allowed_values" => null, "count_min" => 0, "count_max" => 0, "depends_on" => array(), "display_style" => 'property')));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("asynchronous", array("allowed_values" => new ValueSetEnum(['use_global_setting' => 'Use global settings','yes' => 'Yes' ,'no' => 'No']), "sql" => "asynchronous", "default_value" => 'use_global_setting', "is_null_allowed" => false, "depends_on" => array())));
|
||||
|
||||
// Display lists
|
||||
// - Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('details', array('name', 'description', 'status', 'trigger_list'));
|
||||
// - Attributes to be displayed for a list
|
||||
MetaModel::Init_SetZListItems('list', array('finalclass', 'name', 'description', 'status'));
|
||||
// Search criteria
|
||||
// - Default criteria of the search form
|
||||
MetaModel::Init_SetZListItems('default_search', array('name', 'description', 'status'));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Encapsulate the execution of the action and handle failure & logging
|
||||
*
|
||||
* @param \Trigger $oTrigger
|
||||
* @param array $aContextArgs
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function DoExecute($oTrigger, $aContextArgs);
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public function IsActive()
|
||||
{
|
||||
switch($this->Get('status'))
|
||||
{
|
||||
case 'enabled':
|
||||
case 'test':
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the current action status is set on "test"
|
||||
*
|
||||
* @return bool
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public function IsBeingTested()
|
||||
{
|
||||
switch($this->Get('status'))
|
||||
{
|
||||
case 'test':
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public function AfterInsert()
|
||||
{
|
||||
parent::AfterInsert();
|
||||
$this->DoCheckIfHasTrigger();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public function AfterUpdate()
|
||||
{
|
||||
parent::AfterUpdate();
|
||||
$this->DoCheckIfHasTrigger();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the Action has at least 1 trigger linked. Otherwise, it adds a warning.
|
||||
* @return void
|
||||
* @since 3.0.0
|
||||
*/
|
||||
protected function DoCheckIfHasTrigger()
|
||||
{
|
||||
$oTriggersSet = $this->Get('trigger_list');
|
||||
if ($oTriggersSet->Count() === 0) {
|
||||
$this->m_aCheckWarnings[] = Dict::S('Action:WarningNoTriggerLinked');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 3.2.0 N°5472 method creation
|
||||
*/
|
||||
public function DisplayBareRelations(WebPage $oPage, $bEditMode = false)
|
||||
{
|
||||
parent::DisplayBareRelations($oPage, false);
|
||||
|
||||
if ($oPage instanceof iTopWebPage && !$this->IsNew()) {
|
||||
$this->GenerateLastExecutionsTab($oPage, $bEditMode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 3.2.0 N°5472 method creation
|
||||
*/
|
||||
protected function GenerateLastExecutionsTab(iTopWebPage $oPage, $bEditMode)
|
||||
{
|
||||
$oRouter = Router::GetInstance();
|
||||
$sActionLastExecutionsPageUrl = $oRouter->GenerateUrl('notifications.action.last_executions_tab', ['action_id' => $this->GetKey()]);
|
||||
$oPage->AddAjaxTab('action_errors', $sActionLastExecutionsPageUrl, false, Dict::S('Action:last_executions_tab'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Combodo\iTop\Application\WebPage\WebPage $oPage
|
||||
*
|
||||
* @throws \ApplicationException
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \ConfigException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \DictExceptionMissingString
|
||||
* @throws \InvalidConfigParamException
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
* @throws \OQLException
|
||||
* @throws \ReflectionException
|
||||
* @since 3.2.0 N°5472 method creation
|
||||
*/
|
||||
public function GetLastExecutionsTabContent(WebPage $oPage): void
|
||||
{
|
||||
$oConfig = utils::GetConfig();
|
||||
$sLastExecutionDaysConfigParamName = 'notifications.last_executions_days';
|
||||
$iLastExecutionDays = $oConfig->Get($sLastExecutionDaysConfigParamName);
|
||||
|
||||
if ($iLastExecutionDays < 0) {
|
||||
throw new InvalidConfigParamException("Invalid value for {$sLastExecutionDaysConfigParamName} config parameter. Param desc: " . $oConfig->GetDescription($sLastExecutionDaysConfigParamName));
|
||||
}
|
||||
|
||||
$sActionQueryOql = 'SELECT EventNotification WHERE action_id = :action_id';
|
||||
$aActionQueryParams = ['action_id' => $this->GetKey()];
|
||||
if ($iLastExecutionDays > 0) {
|
||||
$sActionQueryOql .= ' AND date > DATE_SUB(NOW(), INTERVAL :days DAY)';
|
||||
$aActionQueryParams['days'] = $iLastExecutionDays;
|
||||
$sActionQueryLimit = Dict::Format('Action:last_executions_tab_limit_days', $iLastExecutionDays);
|
||||
} else {
|
||||
$sActionQueryLimit = Dict::S('Action:last_executions_tab_limit_none');
|
||||
}
|
||||
|
||||
$oActionFilter = DBObjectSearch::FromOQL($sActionQueryOql, $aActionQueryParams);
|
||||
$oSet = new DBObjectSet($oActionFilter, ['date' => false]);
|
||||
|
||||
$sPanelTitle = Dict::Format('Action:last_executions_tab_panel_title', $sActionQueryLimit);
|
||||
$oExecutionsListBlock = DataTableUIBlockFactory::MakeForResult($oPage, 'action_executions_list', $oSet, ['panel_title' => $sPanelTitle]);
|
||||
|
||||
$oPage->AddUiBlock($oExecutionsListBlock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Will be overloaded by the children classes to return the value of their global asynchronous setting (eg. `email_asynchronous` for `\ActionEmail`, `prefer_asynchronous` for `\ActionWebhook`, ...)
|
||||
*
|
||||
* @return bool true if the global setting for this kind of action if to be executed asynchronously, false otherwise.
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public static function GetAsynchronousGlobalSetting(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool true if that action instance should be executed asynchronously, otherwise false
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function IsAsynchronous(): bool
|
||||
{
|
||||
$sAsynchronous = $this->Get('asynchronous');
|
||||
if ($sAsynchronous === 'use_global_setting') {
|
||||
return static::GetAsynchronousGlobalSetting();
|
||||
}
|
||||
return $sAsynchronous === 'yes';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A notification
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
abstract class ActionNotification extends Action
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "grant_by_profile,core/cmdb",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "name",
|
||||
"complementary_name_attcode" => ['finalclass', 'description'],
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => ['name'],
|
||||
"db_table" => "priv_action_notification",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
|
||||
// Display lists
|
||||
// - Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('details', array('name', 'description', 'status', 'trigger_list'));
|
||||
// - Attributes to be displayed for a list
|
||||
MetaModel::Init_SetZListItems('list', array('finalclass', 'description', 'status'));
|
||||
MetaModel::Init_AddAttribute(new AttributeApplicationLanguage("language", array("sql"=>"language", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
|
||||
// Search criteria
|
||||
// - Criteria of the std search form
|
||||
// MetaModel::Init_SetZListItems('standard_search', array('name'));
|
||||
// - Default criteria of the search form
|
||||
// MetaModel::Init_SetZListItems('default_search', array('name'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $sLanguage
|
||||
* @param $sLanguageCode
|
||||
*
|
||||
* @return array [$sPreviousLanguage, $aPreviousPluginProperties]
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \DictExceptionUnknownLanguage
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function SetNotificationLanguage($sLanguage = null, $sLanguageCode = null){
|
||||
$sPreviousLanguage = Dict::GetUserLanguage();
|
||||
$aPreviousPluginProperties = ApplicationContext::GetPluginProperties('QueryLocalizerPlugin');
|
||||
$sLanguage = $sLanguage ?? $this->Get('language');
|
||||
$sLanguageCode = $sLanguageCode ?? $sLanguage;
|
||||
if (!utils::IsNullOrEmptyString($sLanguage)) {
|
||||
// If a language is specified for this action, force this language
|
||||
// when rendering all placeholders inside this message
|
||||
Dict::SetUserLanguage($sLanguage);
|
||||
AttributeDateTime::LoadFormatFromConfig();
|
||||
ApplicationContext::SetPluginProperty('QueryLocalizerPlugin', 'language_code', $sLanguageCode);
|
||||
}
|
||||
return [$sPreviousLanguage, $aPreviousPluginProperties];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An email notification
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
class ActionEmail extends ActionNotification
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
* @since 3.0.1
|
||||
*/
|
||||
const ENUM_HEADER_NAME_MESSAGE_ID = 'Message-ID';
|
||||
/**
|
||||
* @var string
|
||||
* @since 3.0.1
|
||||
*/
|
||||
const ENUM_HEADER_NAME_REFERENCES = 'References';
|
||||
/**
|
||||
* @var string
|
||||
* @since 3.1.0
|
||||
*/
|
||||
const TEMPLATE_BODY_CONTENT = '$content$';
|
||||
/**
|
||||
* Wraps the 'body' of the message for previewing inside an IFRAME -- i.e. without any of the iTop stylesheets being applied
|
||||
* @var string
|
||||
* @since 3.1.0
|
||||
*/
|
||||
const CONTENT_HIGHLIGHT = '<div style="border:2px dashed #6800ff;position:relative;padding:2px;margin-top:14px;"><div style="background-color:#6800ff;color:#fff;font-family:Courier New, sans-serif;font-size:14px;line-height:16px;padding:3px;display:block;position:absolute;top:-22px;right:0;">$content$</div>%s</div>';
|
||||
/**
|
||||
* Wraps a placeholder of the email's body for previewing inside an IFRAME -- i.e. without any of the iTop stylesheets being applied
|
||||
* @var string
|
||||
*/
|
||||
const FIELD_HIGHLIGHT = '<span style="background-color:#6800ff;color:#fff;font-size:smaller;font-family:Courier New, sans-serif;padding:2px;">\\$$1\\$</span>';
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "grant_by_profile,core/cmdb,application",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "name",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array('name'),
|
||||
"db_table" => "priv_action_email",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
'style' => new ormStyle(null, null, null, null, null, '../images/icons/icons8-mailing.svg'),
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeEmailAddress("test_recipient", array("allowed_values" => null, "sql" => "test_recipient", "default_value" => "", "is_null_allowed" => true, "depends_on" => array())));
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeString("from", array("allowed_values" => null, "sql" => "from", "default_value" => null, "is_null_allowed" => false, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("from_label", array("allowed_values" => null, "sql" => "from_label", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("reply_to", array("allowed_values" => null, "sql" => "reply_to", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("reply_to_label", array("allowed_values" => null, "sql" => "reply_to_label", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeOQL("to", array("allowed_values" => null, "sql" => "to", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeOQL("cc", array("allowed_values" => null, "sql" => "cc", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeOQL("bcc", array("allowed_values" => null, "sql" => "bcc", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeTemplateString("subject", array("allowed_values" => null, "sql" => "subject", "default_value" => null, "is_null_allowed" => false, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeTemplateHTML("body", array("allowed_values" => null, "sql" => "body", "default_value" => null, "is_null_allowed" => false, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("importance", array("allowed_values" => new ValueSetEnum('low,normal,high'), "sql" => "importance", "default_value" => 'normal', "is_null_allowed" => false, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeBlob("html_template", array("is_null_allowed"=>true, "depends_on"=>array(), "always_load_in_tables"=>false)));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("ignore_notify", array("allowed_values" => new ValueSetEnum('yes,no'), "sql" => "ignore_notify", "default_value" => 'yes', "is_null_allowed" => false, "depends_on" => array())));
|
||||
|
||||
|
||||
// Display lists
|
||||
// - Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('details', array(
|
||||
'col:col1' => array(
|
||||
'fieldset:ActionEmail:main' => array(
|
||||
0 => 'name',
|
||||
1 => 'description',
|
||||
2 => 'status',
|
||||
3 => 'language',
|
||||
4 => 'html_template',
|
||||
5 => 'subject',
|
||||
6 => 'body',
|
||||
// 5 => 'importance', not handled when sending the mail, better hide it then
|
||||
),
|
||||
'fieldset:ActionEmail:trigger' => array(
|
||||
0 => 'trigger_list',
|
||||
1 => 'asynchronous'
|
||||
),
|
||||
),
|
||||
'col:col2' => array(
|
||||
'fieldset:ActionEmail:recipients' => array(
|
||||
0 => 'from',
|
||||
1 => 'from_label',
|
||||
2 => 'reply_to',
|
||||
3 => 'reply_to_label',
|
||||
4 => 'test_recipient',
|
||||
5 => 'ignore_notify',
|
||||
6 => 'to',
|
||||
7 => 'cc',
|
||||
8 => 'bcc',
|
||||
),
|
||||
),
|
||||
));
|
||||
|
||||
// - Attributes to be displayed for a list
|
||||
MetaModel::Init_SetZListItems('list', array('status', 'to', 'subject', 'language'));
|
||||
// Search criteria
|
||||
// - Standard criteria of the search
|
||||
MetaModel::Init_SetZListItems('standard_search', array('name', 'description', 'status', 'subject', 'language'));
|
||||
// - Default criteria for the search
|
||||
MetaModel::Init_SetZListItems('default_search', array('name', 'description', 'status', 'subject', 'language'));
|
||||
}
|
||||
|
||||
// count the recipients found
|
||||
protected $m_iRecipients;
|
||||
|
||||
// Errors management : not that simple because we need that function to be
|
||||
// executed in the background, while making sure that any issue would be reported clearly
|
||||
protected $m_aMailErrors; //array of strings explaining the issue
|
||||
|
||||
/**
|
||||
* Return the list of emails as a string, or a detailed error description
|
||||
*
|
||||
* @param string $sRecipAttCode
|
||||
* @param array $aArgs
|
||||
*
|
||||
* @return string
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreCannotSaveObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \CoreWarning
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
protected function FindRecipients($sRecipAttCode, $aArgs)
|
||||
{
|
||||
$oTrigger = $aArgs['trigger->object()'] ?? null;
|
||||
$sOQL = $this->Get($sRecipAttCode);
|
||||
if (utils::IsNullOrEmptyString($sOQL)) return '';
|
||||
|
||||
try
|
||||
{
|
||||
$oSearch = DBObjectSearch::FromOQL($sOQL);
|
||||
if ($this->Get('ignore_notify') === 'no') {
|
||||
// In theory, it is possible to notify *any* kind of object,
|
||||
// as long as there is an email attribute in the class
|
||||
// So let's not assume that the selected class is a Person
|
||||
$sFirstSelectedClass = $oSearch->GetClass();
|
||||
if (MetaModel::IsValidAttCode($sFirstSelectedClass, 'notify')) {
|
||||
$oSearch->AddCondition('notify', 'yes');
|
||||
}
|
||||
}
|
||||
$oSearch->AllowAllData();
|
||||
}
|
||||
catch (OQLException $e)
|
||||
{
|
||||
$this->m_aMailErrors[] = "query syntax error for recipient '$sRecipAttCode'";
|
||||
return $e->getMessage();
|
||||
}
|
||||
|
||||
$sClass = $oSearch->GetClass();
|
||||
// Determine the email attribute (the first one will be our choice)
|
||||
foreach (MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef)
|
||||
{
|
||||
if ($oAttDef instanceof AttributeEmailAddress)
|
||||
{
|
||||
$sEmailAttCode = $sAttCode;
|
||||
// we've got one, exit the loop
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!isset($sEmailAttCode))
|
||||
{
|
||||
$this->m_aMailErrors[] = "wrong target for recipient '$sRecipAttCode'";
|
||||
return "The objects of the class '$sClass' do not have any email attribute";
|
||||
}
|
||||
|
||||
if($oTrigger !== null && in_array('Contact', MetaModel::EnumParentClasses($sClass, ENUM_CHILD_CLASSES_ALL), true)) {
|
||||
$aArgs['trigger_id'] = $oTrigger->GetKey();
|
||||
$aArgs['action_id'] = $this->GetKey();
|
||||
|
||||
$sSubscribedContactsOQL = NotificationsRepository::GetInstance()->GetSearchOQLContactUnsubscribedByTriggerAndAction();
|
||||
$sSubscribedContactsOQL->ApplyParameters($aArgs);
|
||||
$sAlias = $oSearch->GetClassAlias();
|
||||
$oSearch->AddConditionExpression(Expression::FromOQL("`$sAlias`.id NOT IN ($sSubscribedContactsOQL)"));
|
||||
}
|
||||
|
||||
$oSet = new DBObjectSet($oSearch, array() /* order */, $aArgs);
|
||||
$aRecipients = array();
|
||||
while ($oObj = $oSet->Fetch())
|
||||
{
|
||||
$sAddress = trim($oObj->Get($sEmailAttCode));
|
||||
if (utils::IsNotNullOrEmptyString($sAddress))
|
||||
{
|
||||
$aRecipients[] = $sAddress;
|
||||
$this->m_iRecipients++;
|
||||
}
|
||||
if ($oTrigger !== null && in_array('Contact', MetaModel::EnumParentClasses($sClass, ENUM_CHILD_CLASSES_ALL), true)) {
|
||||
NotificationsService::GetInstance()->RegisterSubscription($oTrigger, $this, $oObj);
|
||||
}
|
||||
}
|
||||
return implode(', ', $aRecipients);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \CoreWarning
|
||||
*/
|
||||
public function DoExecute($oTrigger, $aContextArgs)
|
||||
{
|
||||
if (MetaModel::IsLogEnabledNotification())
|
||||
{
|
||||
$oLog = new EventNotificationEmail();
|
||||
if ($this->IsBeingTested())
|
||||
{
|
||||
$oLog->Set('message', 'TEST - Notification sent ('.$this->Get('test_recipient').')');
|
||||
}
|
||||
else
|
||||
{
|
||||
$oLog->Set('message', 'Notification pending');
|
||||
}
|
||||
$oLog->Set('userinfo', UserRights::GetUser());
|
||||
$oLog->Set('trigger_id', $oTrigger->GetKey());
|
||||
$oLog->Set('action_id', $this->GetKey());
|
||||
$oLog->Set('object_id', $aContextArgs['this->object()']->GetKey());
|
||||
$oLog->Set('object_class', get_class($aContextArgs['this->object()']));
|
||||
// Must be inserted now so that it gets a valid id that will make the link
|
||||
// between an eventual asynchronous task (queued) and the log
|
||||
$oLog->DBInsertNoReload();
|
||||
}
|
||||
else
|
||||
{
|
||||
$oLog = null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$sRes = $this->_DoExecute($oTrigger, $aContextArgs, $oLog);
|
||||
|
||||
if ($this->IsBeingTested())
|
||||
{
|
||||
$sPrefix = 'TEST ('.$this->Get('test_recipient').') - ';
|
||||
}
|
||||
else
|
||||
{
|
||||
$sPrefix = '';
|
||||
}
|
||||
|
||||
if ($oLog)
|
||||
{
|
||||
$oLog->Set('message', $sPrefix . $sRes);
|
||||
$oLog->DBUpdate();
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
if ($oLog)
|
||||
{
|
||||
$oLog->Set('message', 'Error: '.$e->getMessage());
|
||||
|
||||
try
|
||||
{
|
||||
$oLog->DBUpdate();
|
||||
}
|
||||
catch (Exception $eSecondTryUpdate)
|
||||
{
|
||||
IssueLog::Error("Failed to process email ".$oLog->GetKey()." - reason: ".$e->getMessage()."\nTrace:\n".$e->getTraceAsString());
|
||||
|
||||
$oLog->Set('message', 'Error: more details in the log for email "'.$oLog->GetKey().'"');
|
||||
$oLog->DBUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Trigger $oTrigger
|
||||
* @param array $aContextArgs
|
||||
* @param \EventNotification $oLog
|
||||
*
|
||||
* @return string
|
||||
* @throws \CoreException
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function _DoExecute($oTrigger, $aContextArgs, &$oLog)
|
||||
{
|
||||
$sStyles = file_get_contents(APPROOT . utils::GetCSSFromSASS("css/email.scss"));
|
||||
$sStyles .= MetaModel::GetConfig()->Get('email_css');
|
||||
|
||||
$oEmail = new EMail();
|
||||
|
||||
$aEmailContent = $this->PrepareMessageContent($aContextArgs, $oLog);
|
||||
$oEmail->SetSubject($aEmailContent['subject']);
|
||||
$oEmail->SetBody($aEmailContent['body'], 'text/html', $sStyles);
|
||||
$oEmail->SetRecipientTO($aEmailContent['to']);
|
||||
$oEmail->SetRecipientCC($aEmailContent['cc']);
|
||||
$oEmail->SetRecipientBCC($aEmailContent['bcc']);
|
||||
$oEmail->SetRecipientFrom($aEmailContent['from'], $aEmailContent['from_label']);
|
||||
$oEmail->SetRecipientReplyTo($aEmailContent['reply_to'], $aEmailContent['reply_to_label']);
|
||||
$oEmail->SetReferences($aEmailContent['references']);
|
||||
$oEmail->SetMessageId($aEmailContent['message_id']);
|
||||
$oEmail->SetInReplyTo($aEmailContent['in_reply_to']);
|
||||
|
||||
foreach($aEmailContent['attachments'] as $aAttachment) {
|
||||
$oEmail->AddAttachment($aAttachment['data'], $aAttachment['filename'], $aAttachment['mime_type']);
|
||||
}
|
||||
|
||||
if (empty($this->m_aMailErrors))
|
||||
{
|
||||
if ($this->m_iRecipients == 0)
|
||||
{
|
||||
return 'No recipient';
|
||||
}
|
||||
else
|
||||
{
|
||||
$aErrors = [];
|
||||
$iRes = $oEmail->Send($aErrors, $this->IsAsynchronous() ? Email::ENUM_SEND_FORCE_ASYNCHRONOUS : Email::ENUM_SEND_FORCE_SYNCHRONOUS, $oLog);
|
||||
switch ($iRes)
|
||||
{
|
||||
case EMAIL_SEND_OK:
|
||||
return "Sent";
|
||||
|
||||
case EMAIL_SEND_PENDING:
|
||||
return "Pending";
|
||||
|
||||
case EMAIL_SEND_ERROR:
|
||||
return "Errors: ".implode(', ', $aErrors);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (is_array($this->m_aMailErrors) && count($this->m_aMailErrors) > 0) {
|
||||
$sError = implode(', ', $this->m_aMailErrors);
|
||||
} else {
|
||||
$sError = 'Unknown reason';
|
||||
}
|
||||
|
||||
return 'Notification was not sent: '.$sError;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $aContextArgs
|
||||
* @param \EventNotification $oLog
|
||||
*
|
||||
* @return array
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreCannotSaveObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \CoreWarning
|
||||
* @throws \DictExceptionMissingString
|
||||
* @throws \DictExceptionUnknownLanguage
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
* @throws \OQLException
|
||||
* @since 3.1.0 N°918
|
||||
*/
|
||||
protected function PrepareMessageContent($aContextArgs, &$oLog): array
|
||||
{
|
||||
$aMessageContent = [
|
||||
'to' => '',
|
||||
'cc' => '',
|
||||
'bcc' => '',
|
||||
'from' => '',
|
||||
'from_label' => '',
|
||||
'reply_to' => '',
|
||||
'reply_to_label' => '',
|
||||
'subject' => '',
|
||||
'body' => '',
|
||||
'references' => '',
|
||||
'message_id' => '',
|
||||
'in_reply_to' => '',
|
||||
'attachments' => [],
|
||||
];
|
||||
$sPreviousUrlMaker = ApplicationContext::SetUrlMakerClass();
|
||||
[$sPreviousLanguage, $aPreviousPluginProperties] = $this->SetNotificationLanguage();
|
||||
|
||||
try
|
||||
{
|
||||
$this->m_iRecipients = 0;
|
||||
$this->m_aMailErrors = array();
|
||||
|
||||
// Determine recipients
|
||||
//
|
||||
$aMessageContent['to'] = $this->FindRecipients('to', $aContextArgs);
|
||||
$aMessageContent['cc'] = $this->FindRecipients('cc', $aContextArgs);
|
||||
$aMessageContent['bcc'] = $this->FindRecipients('bcc', $aContextArgs);
|
||||
|
||||
$aMessageContent['from'] = MetaModel::ApplyParams($this->Get('from'), $aContextArgs);
|
||||
$aMessageContent['from_label'] = MetaModel::ApplyParams($this->Get('from_label'), $aContextArgs);
|
||||
$aMessageContent['reply_to'] = MetaModel::ApplyParams($this->Get('reply_to'), $aContextArgs);
|
||||
$aMessageContent['reply_to_label'] = MetaModel::ApplyParams($this->Get('reply_to_label'), $aContextArgs);
|
||||
|
||||
$aMessageContent['subject'] = MetaModel::ApplyParams($this->Get('subject'), $aContextArgs);
|
||||
$sBody = $this->BuildMessageBody(false);
|
||||
$aMessageContent['body'] = MetaModel::ApplyParams($sBody, $aContextArgs);
|
||||
|
||||
$oObj = $aContextArgs['this->object()'];
|
||||
$aMessageContent['message_id'] = $this->GenerateIdentifierForHeaders($oObj, static::ENUM_HEADER_NAME_MESSAGE_ID);
|
||||
$aMessageContent['references'] = $this->GenerateIdentifierForHeaders($oObj, static::ENUM_HEADER_NAME_REFERENCES);
|
||||
}
|
||||
catch (Exception $e) {
|
||||
/** @noinspection PhpUnhandledExceptionInspection */
|
||||
throw $e;
|
||||
}
|
||||
finally {
|
||||
ApplicationContext::SetUrlMakerClass($sPreviousUrlMaker);
|
||||
$this->SetNotificationLanguage($sPreviousLanguage, $aPreviousPluginProperties['language_code'] ?? null);
|
||||
}
|
||||
|
||||
if (!is_null($oLog)) {
|
||||
// Note: we have to secure this because those values are calculated
|
||||
// inside the try statement, and we would like to keep track of as
|
||||
// many data as we could while some variables may still be undefined
|
||||
if (isset($aMessageContent['to'])) {
|
||||
$oLog->Set('to', $aMessageContent['to']);
|
||||
}
|
||||
if (isset($aMessageContent['cc'])) {
|
||||
$oLog->Set('cc', $aMessageContent['cc']);
|
||||
}
|
||||
if (isset($aMessageContent['bcc'])) {
|
||||
$oLog->Set('bcc', $aMessageContent['bcc']);
|
||||
}
|
||||
if (isset($aMessageContent['from'])) {
|
||||
$oLog->Set('from', $aMessageContent['from']);
|
||||
}
|
||||
if (isset($aMessageContent['subject'])) {
|
||||
$oLog->Set('subject', $aMessageContent['subject']);
|
||||
}
|
||||
if (isset($aMessageContent['body'])) {
|
||||
$oLog->Set('body', HTMLSanitizer::Sanitize($aMessageContent['body']));
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->IsBeingTested()) {
|
||||
$sTestBody = $aMessageContent['body'];
|
||||
$sTestBody .= "<div style=\"border: dashed;\">\n";
|
||||
$sTestBody .= "<h1>Testing email notification ".$this->GetHyperlink()."</h1>\n";
|
||||
$sTestBody .= "<p>The email should be sent with the following properties\n";
|
||||
$sTestBody .= "<ul>\n";
|
||||
$sTestBody .= "<li>TO: {$aMessageContent['to']}</li>\n";
|
||||
$sTestBody .= "<li>CC: {$aMessageContent['cc']}</li>\n";
|
||||
$sTestBody .= "<li>BCC: {$aMessageContent['bcc']}</li>\n";
|
||||
$sTestBody .= empty($aMessageContent['from_label']) ? "<li>From: {$aMessageContent['from']}</li>\n" : "<li>From: {$aMessageContent['from_label']} <{$aMessageContent['from']}></li>\n";
|
||||
$sTestBody .= empty($aMessageContent['reply_to_label']) ? "<li>Reply-To: {$aMessageContent['reply_to']}</li>\n" : "<li>Reply-To: {$aMessageContent['reply_to_label']} <{$aMessageContent['reply_to']}></li>\n";
|
||||
$sTestBody .= "<li>References: {$aMessageContent['references']}</li>\n";
|
||||
$sTestBody .= "</ul>\n";
|
||||
$sTestBody .= "</p>\n";
|
||||
$sTestBody .= "</div>\n";
|
||||
$aMessageContent['subject'] = 'TEST['.$aMessageContent['subject'].']';
|
||||
$aMessageContent['body'] = $sTestBody;
|
||||
$aMessageContent['to'] = $this->Get('test_recipient');
|
||||
// N°6677 Ensure emails in test are never sent to cc'd and bcc'd addresses
|
||||
$aMessageContent['cc'] = '';
|
||||
$aMessageContent['bcc'] = '';
|
||||
}
|
||||
// Note: N°4849 We pass the "References" identifier instead of the "Message-ID" on purpose as we want notifications emails to group around the triggering iTop object, not just the users' replies to the notification
|
||||
$aMessageContent['in_reply_to'] = $aMessageContent['references'];
|
||||
|
||||
if (isset($aContextArgs['attachments']))
|
||||
{
|
||||
$aAttachmentReport = array();
|
||||
/** @var \ormDocument $oDocument */
|
||||
foreach($aContextArgs['attachments'] as $oDocument)
|
||||
{
|
||||
$aMessageContent['attachments'][] = ['data' => $oDocument->GetData(), 'filename' => $oDocument->GetFileName(), 'mime_type' => $oDocument->GetMimeType()];
|
||||
$aAttachmentReport[] = array($oDocument->GetFileName(), $oDocument->GetMimeType(), strlen($oDocument->GetData() ?? ''));
|
||||
}
|
||||
$oLog->Set('attachments', $aAttachmentReport);
|
||||
}
|
||||
|
||||
return $aMessageContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \DBObject $oObject
|
||||
* @param string $sHeaderName {@see \ActionEmail::ENUM_HEADER_NAME_REFERENCES}, {@see \ActionEmail::ENUM_HEADER_NAME_MESSAGE_ID}
|
||||
*
|
||||
* @return string The formatted identifier for $sHeaderName based on $oObject
|
||||
* @throws \Exception
|
||||
* @since 3.1.0 N°4849
|
||||
*/
|
||||
protected function GenerateIdentifierForHeaders(DBObject $oObject, string $sHeaderName): string
|
||||
{
|
||||
$sObjClass = get_class($oObject);
|
||||
$sObjId = $oObject->GetKey();
|
||||
$sAppName = utils::Sanitize(ITOP_APPLICATION_SHORT, '', utils::ENUM_SANITIZATION_FILTER_VARIABLE_NAME);
|
||||
|
||||
switch ($sHeaderName) {
|
||||
case static::ENUM_HEADER_NAME_MESSAGE_ID:
|
||||
case static::ENUM_HEADER_NAME_REFERENCES:
|
||||
// Prefix
|
||||
$sPrefix = sprintf('%s_%s_%d', $sAppName, $sObjClass, $sObjId);
|
||||
if ($sHeaderName === static::ENUM_HEADER_NAME_MESSAGE_ID) {
|
||||
$sPrefix .= sprintf('_%F', microtime(true /* get as float*/));
|
||||
}
|
||||
// Suffix
|
||||
$sSuffix = sprintf('@%s.openitop.org', MetaModel::GetEnvironmentId());
|
||||
// Identifier
|
||||
$sIdentifier = $sPrefix.$sSuffix;
|
||||
if ($sHeaderName === static::ENUM_HEADER_NAME_REFERENCES) {
|
||||
$sIdentifier = "<$sIdentifier>";
|
||||
}
|
||||
|
||||
return $sIdentifier;
|
||||
}
|
||||
|
||||
// Requested header name invalid
|
||||
$sErrorMessage = sprintf('%s: Could not generate identifier for header "%s", only %s are supported', static::class, $sHeaderName, implode(' / ', [static::ENUM_HEADER_NAME_MESSAGE_ID, static::ENUM_HEADER_NAME_REFERENCES]));
|
||||
IssueLog::Error($sErrorMessage, LogChannels::NOTIFICATIONS, [
|
||||
'Object' => $sObjClass.'::'.$sObjId.' ('.$oObject->GetRawName().')',
|
||||
'Action' => get_class($this).'::'.$this->GetKey().' ('.$this->GetRawName().')',
|
||||
]);
|
||||
throw new Exception($sErrorMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compose the body of the message from the 'body' attribute and the HTML template (if any)
|
||||
* @since 3.1.0 N°4849
|
||||
* @param bool $bHighlightPlaceholders If true add some extra HTML around placeholders to highlight them
|
||||
* @return string
|
||||
*/
|
||||
protected function BuildMessageBody(bool $bHighlightPlaceholders = false): string
|
||||
{
|
||||
// Wrap content with a specific class in order to apply styles of HTML fields through the emogrifier (see `css/email.scss`)
|
||||
$sBody = <<<HTML
|
||||
<div class="email-is-html-content">
|
||||
{$this->Get('body')}
|
||||
</div>
|
||||
HTML;
|
||||
|
||||
/** @var ormDocument $oHtmlTemplate */
|
||||
$oHtmlTemplate = $this->Get('html_template');
|
||||
if ($oHtmlTemplate && !$oHtmlTemplate->IsEmpty()) {
|
||||
$sHtmlTemplate = $oHtmlTemplate->GetData();
|
||||
if (false !== mb_strpos($sHtmlTemplate, static::TEMPLATE_BODY_CONTENT)) {
|
||||
if ($bHighlightPlaceholders) {
|
||||
// Highlight the $content$ block
|
||||
$sBody = sprintf(static::CONTENT_HIGHLIGHT, $sBody);
|
||||
}
|
||||
$sBody = str_replace(static::TEMPLATE_BODY_CONTENT, $sBody, $oHtmlTemplate->GetData()); // str_replace is ok as long as both strings are well-formed UTF-8
|
||||
} else {
|
||||
$sBody = $oHtmlTemplate->GetData();
|
||||
}
|
||||
}
|
||||
if($bHighlightPlaceholders) {
|
||||
// Highlight all placeholders
|
||||
$sBody = preg_replace('/\\$([^$]+)\\$/', static::FIELD_HIGHLIGHT, $sBody);
|
||||
}
|
||||
return $sBody;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 3.1.0 N°4849
|
||||
* @inheritDoc
|
||||
* @see cmdbAbstractObject::DisplayBareRelations()
|
||||
*/
|
||||
public function DisplayBareRelations(WebPage $oPage, $bEditMode = false)
|
||||
{
|
||||
parent::DisplayBareRelations($oPage, false);
|
||||
if (!$bEditMode) {
|
||||
$oPage->SetCurrentTab('action_email__preview', Dict::S('ActionEmail:preview_tab'), Dict::S('ActionEmail:preview_tab+'));
|
||||
$sBody = $this->BuildMessageBody(true);
|
||||
TwigHelper::RenderIntoPage($oPage, APPROOT.'/', 'templates/datamodel/ActionEmail/email-notification-preview', ['iframe_content' => $sBody]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 3.1.0
|
||||
* @inheritDoc
|
||||
* @see cmdbAbstractObject::DoCheckToWrite()
|
||||
*/
|
||||
public function DoCheckToWrite()
|
||||
{
|
||||
parent::DoCheckToWrite();
|
||||
$oHtmlTemplate = $this->Get('html_template');
|
||||
if ($oHtmlTemplate && !$oHtmlTemplate->IsEmpty()) {
|
||||
if (false === mb_strpos($oHtmlTemplate->GetData(), static::TEMPLATE_BODY_CONTENT)) {
|
||||
$this->m_aCheckWarnings[] = Dict::Format('ActionEmail:content_placeholder_missing', static::TEMPLATE_BODY_CONTENT, Dict::S('Class:ActionEmail/Attribute:body'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public static function GetAsynchronousGlobalSetting(): bool
|
||||
{
|
||||
return utils::GetConfig()->Get('email_asynchronous');
|
||||
}
|
||||
}
|
||||
@@ -1,544 +0,0 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2024 Combodo SAS
|
||||
//
|
||||
// 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/>
|
||||
use Combodo\iTop\Service\Notification\Event\EventNotificationNewsroomService;
|
||||
|
||||
|
||||
/**
|
||||
* Persistent classes (internal): user defined actions
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
|
||||
class ExecAsyncTask implements iBackgroundProcess
|
||||
{
|
||||
public function GetPeriodicity()
|
||||
{
|
||||
return 2; // seconds
|
||||
}
|
||||
|
||||
public function Process($iTimeLimit)
|
||||
{
|
||||
$sNow = date(AttributeDateTime::GetSQLFormat());
|
||||
// Criteria: planned, and expected to occur... ASAP or in the past
|
||||
$sOQL = "SELECT AsyncTask WHERE (status = 'planned') AND (ISNULL(planned) OR (planned < '$sNow'))";
|
||||
$iProcessed = 0;
|
||||
while (time() < $iTimeLimit)
|
||||
{
|
||||
// Next one ?
|
||||
$oSet = new CMDBObjectSet(DBObjectSearch::FromOQL($sOQL), array('created' => true) /* order by*/, array(), null, 1 /* limit count */);
|
||||
$oTask = $oSet->Fetch();
|
||||
if (is_null($oTask))
|
||||
{
|
||||
// Nothing to be done
|
||||
break;
|
||||
}
|
||||
$iProcessed++;
|
||||
if ($oTask->Process())
|
||||
{
|
||||
$oTask->DBDelete();
|
||||
}
|
||||
}
|
||||
return "processed $iProcessed tasks";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
abstract class AsyncTask extends DBObject
|
||||
{
|
||||
/**
|
||||
* @throws \CoreException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "core/cmdb",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => array('created'),
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_async_task",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "realclass",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
|
||||
// Null is allowed to ease the migration from iTop 2.0.2 and earlier, when the status did not exist, and because the default value is not taken into account in the SQL definition
|
||||
// The value is set from null to planned in the setup program
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("status", array("allowed_values"=>new ValueSetEnum('planned,running,idle,error'), "sql"=>"status", "default_value"=>"planned", "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeDateTime("created", array("allowed_values"=>null, "sql"=>"created", "default_value"=>"NOW()", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeDateTime("started", array("allowed_values"=>null, "sql"=>"started", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeDateTime("planned", array("allowed_values"=>null, "sql"=>"planned", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("event_id", array("targetclass"=>"Event", "jointype"=> "", "allowed_values"=>null, "sql"=>"event_id", "is_null_allowed"=>true, "on_target_delete"=>DEL_SILENT, "depends_on"=>array())));
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeInteger("remaining_retries", array("allowed_values"=>null, "sql"=>"remaining_retries", "default_value"=>0, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeInteger("last_error_code", array("allowed_values"=>null, "sql"=>"last_error_code", "default_value"=>0, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("last_error", array("allowed_values"=>null, "sql"=>"last_error", "default_value"=>'', "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeDateTime("last_attempt", array("allowed_values"=>null, "sql"=>"last_attempt", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
}
|
||||
|
||||
/**
|
||||
* Every is fine
|
||||
*/
|
||||
const OK = 0;
|
||||
/**
|
||||
* The task no longer exists
|
||||
*/
|
||||
const DELETED = 1;
|
||||
/**
|
||||
* The task is already being executed
|
||||
*/
|
||||
const ALREADY_RUNNING = 2;
|
||||
|
||||
/**
|
||||
* The current process requests the ownership on the task.
|
||||
* In case the task can be accessed concurrently, this function can be overloaded to add a critical section.
|
||||
* The function must not block the caller if another process is already owning the task
|
||||
*
|
||||
* @return integer A code among OK/DELETED/ALREADY_RUNNING.
|
||||
*/
|
||||
public function MarkAsRunning()
|
||||
{
|
||||
try
|
||||
{
|
||||
if ($this->Get('status') == 'running')
|
||||
{
|
||||
return self::ALREADY_RUNNING;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->Set('status', 'running');
|
||||
$this->Set('started', time());
|
||||
$this->DBUpdate();
|
||||
return self::OK;
|
||||
}
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
// Corrupted task !! (for example: "Failed to reload object")
|
||||
IssueLog::Error('Failed to process async task #'.$this->GetKey().' - reason: '.$e->getMessage().' - fatal error, deleting the task.');
|
||||
if ($this->Get('event_id') != 0)
|
||||
{
|
||||
$oEventLog = MetaModel::GetObject('Event', $this->Get('event_id'));
|
||||
$oEventLog->Set('message', 'Failed, corrupted data: '.$e->getMessage());
|
||||
$oEventLog->DBUpdate();
|
||||
}
|
||||
$this->DBDelete();
|
||||
return self::DELETED;
|
||||
}
|
||||
}
|
||||
|
||||
public function GetRetryDelay($iErrorCode = null)
|
||||
{
|
||||
$iRetryDelay = 600;
|
||||
$aRetries = MetaModel::GetConfig()->Get('async_task_retries');
|
||||
if (is_array($aRetries) && array_key_exists(get_class($this), $aRetries))
|
||||
{
|
||||
$aConfig = $aRetries[get_class($this)];
|
||||
$iRetryDelay = $aConfig['retry_delay'] ?? $iRetryDelay;
|
||||
}
|
||||
return $iRetryDelay;
|
||||
}
|
||||
|
||||
public function GetMaxRetries($iErrorCode = null)
|
||||
{
|
||||
$iMaxRetries = 0;
|
||||
$aRetries = MetaModel::GetConfig()->Get('async_task_retries');
|
||||
if (is_array($aRetries) && array_key_exists(get_class($this), $aRetries))
|
||||
{
|
||||
$aConfig = $aRetries[get_class($this)];
|
||||
$iMaxRetries = $aConfig['max_retries'] ?? $iMaxRetries;
|
||||
}
|
||||
return $iMaxRetries;
|
||||
}
|
||||
|
||||
public function IsRetryDelayExponential()
|
||||
{
|
||||
$bExponential = false;
|
||||
$aRetries = MetaModel::GetConfig()->Get('async_task_retries');
|
||||
if (is_array($aRetries) && array_key_exists(get_class($this), $aRetries))
|
||||
{
|
||||
$aConfig = $aRetries[get_class($this)];
|
||||
$bExponential = (bool) ($aConfig['exponential_delay'] ?? $bExponential);
|
||||
}
|
||||
return $bExponential;
|
||||
}
|
||||
|
||||
public static function CheckRetryConfig(Config $oConfig, $sAsyncTaskClass)
|
||||
{
|
||||
$aMessages = [];
|
||||
$aRetries = $oConfig->Get('async_task_retries');
|
||||
if (is_array($aRetries) && array_key_exists($sAsyncTaskClass, $aRetries))
|
||||
{
|
||||
$aValidKeys = array("retry_delay", "max_retries", "exponential_delay");
|
||||
$aConfig = $aRetries[$sAsyncTaskClass];
|
||||
if (!is_array($aConfig))
|
||||
{
|
||||
$aMessages[] = Dict::Format('Class:AsyncTask:InvalidConfig_Class_Keys', $sAsyncTaskClass, implode(', ', $aValidKeys));
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach($aConfig as $key => $value)
|
||||
{
|
||||
if (!in_array($key, $aValidKeys))
|
||||
{
|
||||
$aMessages[] = Dict::Format('Class:AsyncTask:InvalidConfig_Class_InvalidKey_Keys', $sAsyncTaskClass, $key, implode(', ', $aValidKeys));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $aMessages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the delay to wait for the "next retry", based on the given parameters
|
||||
* @param bool $bIsExponential
|
||||
* @param int $iRetryDelay
|
||||
* @param int $iMaxRetries
|
||||
* @param int $iRemainingRetries
|
||||
* @return int
|
||||
*/
|
||||
public static function GetNextRetryDelay($bIsExponential, $iRetryDelay, $iMaxRetries, $iRemainingRetries)
|
||||
{
|
||||
if ($bIsExponential)
|
||||
{
|
||||
$iExponent = $iMaxRetries - $iRemainingRetries;
|
||||
if ($iExponent < 0) $iExponent = 0; // Safety net in case on configuration change in the middle of retries
|
||||
return $iRetryDelay * (2 ** $iExponent);
|
||||
}
|
||||
else
|
||||
{
|
||||
return $iRetryDelay;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Override to notify people that a task cannot be performed
|
||||
*/
|
||||
protected function OnDefinitiveFailure()
|
||||
{
|
||||
}
|
||||
|
||||
protected function OnInsert()
|
||||
{
|
||||
$this->Set('created', time());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean True if the task record can be deleted
|
||||
*/
|
||||
public function Process()
|
||||
{
|
||||
// By default: consider that the task is not completed
|
||||
$bRet = false;
|
||||
|
||||
// Attempt to take the ownership
|
||||
$iStatus = $this->MarkAsRunning();
|
||||
if ($iStatus == self::OK)
|
||||
{
|
||||
try
|
||||
{
|
||||
$sStatus = $this->DoProcess();
|
||||
if ($this->Get('event_id') != 0)
|
||||
{
|
||||
$oEventLog = MetaModel::GetObject('Event', $this->Get('event_id'));
|
||||
$oEventLog->Set('message', $sStatus);
|
||||
$oEventLog->DBUpdate();
|
||||
}
|
||||
$bRet = true;
|
||||
} catch (Exception $e)
|
||||
{
|
||||
$this->HandleError($e->getMessage(), $e->getCode());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Already done or being handled by another process... skip...
|
||||
$bRet = false;
|
||||
}
|
||||
|
||||
return $bRet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridable to extend the behavior in case of error (logging)
|
||||
*/
|
||||
protected function HandleError($sErrorMessage, $iErrorCode)
|
||||
{
|
||||
if ($this->Get('last_attempt') == '')
|
||||
{
|
||||
// First attempt
|
||||
$this->Set('remaining_retries', $this->GetMaxRetries($iErrorCode));
|
||||
}
|
||||
|
||||
$this->SetTrim('last_error', $sErrorMessage);
|
||||
$this->Set('last_error_code', $iErrorCode); // Note: can be ZERO !!!
|
||||
$this->Set('last_attempt', time());
|
||||
|
||||
$iRemaining = $this->Get('remaining_retries');
|
||||
if ($iRemaining > 0)
|
||||
{
|
||||
$iRetryDelay = $this->GetRetryDelay($iErrorCode);
|
||||
$iNextRetryDelay = static::GetNextRetryDelay($this->IsRetryDelayExponential(), $iRetryDelay, $this->GetMaxRetries($iErrorCode), $iRemaining);
|
||||
IssueLog::Info('Failed to process async task #'.$this->GetKey().' - reason: '.$sErrorMessage.' - remaining retries: '.$iRemaining.' - next retry in '.$iNextRetryDelay.'s');
|
||||
if ($this->Get('event_id') != 0)
|
||||
{
|
||||
$oEventLog = MetaModel::GetObject('Event', $this->Get('event_id'));
|
||||
$oEventLog->Set('message', "$sErrorMessage\nFailed to process async task. Remaining retries: $iRemaining. Next retry in {$iNextRetryDelay}s");
|
||||
try
|
||||
{
|
||||
$oEventLog->DBUpdate();
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
$oEventLog->Set('message', "Failed to process async task. Remaining retries: $iRemaining. Next retry in {$iNextRetryDelay}s, more details in the log");
|
||||
$oEventLog->DBUpdate();
|
||||
}
|
||||
}
|
||||
$this->Set('remaining_retries', $iRemaining - 1);
|
||||
$this->Set('status', 'planned');
|
||||
$this->Set('started', null);
|
||||
$this->Set('planned', time() + $iNextRetryDelay);
|
||||
}
|
||||
else
|
||||
{
|
||||
IssueLog::Error('Failed to process async task #'.$this->GetKey().' - reason: '.$sErrorMessage);
|
||||
if ($this->Get('event_id') != 0)
|
||||
{
|
||||
$oEventLog = MetaModel::GetObject('Event', $this->Get('event_id'));
|
||||
$oEventLog->Set('message', "$sErrorMessage\nFailed to process async task.");
|
||||
try
|
||||
{
|
||||
$oEventLog->DBUpdate();
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
$oEventLog->Set('message', 'Failed to process async task, more details in the log');
|
||||
$oEventLog->DBUpdate();
|
||||
}
|
||||
}
|
||||
$this->Set('status', 'error');
|
||||
$this->Set('started', null);
|
||||
$this->Set('planned', null);
|
||||
$this->OnDefinitiveFailure();
|
||||
}
|
||||
$this->DBUpdate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws an exception (message and code)
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract public function DoProcess();
|
||||
|
||||
/**
|
||||
* Describes the error codes that DoProcess can return by the mean of exceptions
|
||||
*/
|
||||
static public function EnumErrorCodes()
|
||||
{
|
||||
return array();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An email notification
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
class AsyncSendEmail extends AsyncTask
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "core/cmdb",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "created",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_async_send_email",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeInteger("version", array("allowed_values"=>null, "sql"=>"version", "default_value"=>Email::ORIGINAL_FORMAT, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("to", array("allowed_values"=>null, "sql"=>"to", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("subject", array("allowed_values"=>null, "sql"=>"subject", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeLongText("message", array("allowed_values"=>null, "sql"=>"message", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
|
||||
// Display lists
|
||||
// MetaModel::Init_SetZListItems('details', array('name', 'description', 'status', 'test_recipient', 'from', 'reply_to', 'to', 'cc', 'bcc', 'subject', 'body', 'importance', 'trigger_list')); // Attributes to be displayed for the complete details
|
||||
// MetaModel::Init_SetZListItems('list', array('name', 'status', 'to', 'subject')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
|
||||
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
|
||||
}
|
||||
|
||||
static public function AddToQueue(EMail $oEMail, $oLog)
|
||||
{
|
||||
$oNew = MetaModel::NewObject(__class__);
|
||||
if ($oLog)
|
||||
{
|
||||
$oNew->Set('event_id', $oLog->GetKey());
|
||||
}
|
||||
$oNew->Set('to', $oEMail->GetRecipientTO(true /* string */));
|
||||
$oNew->Set('subject', $oEMail->GetSubject());
|
||||
|
||||
$oNew->Set('version', 2);
|
||||
$sMessage = $oEMail->SerializeV2();
|
||||
$oNew->Set('message', $sMessage);
|
||||
$oNew->DBInsert();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public function DoProcess()
|
||||
{
|
||||
$sMessage = $this->Get('message');
|
||||
$iVersion = (int) $this->Get('version');
|
||||
switch($iVersion)
|
||||
{
|
||||
case Email::FORMAT_V2:
|
||||
$oEMail = Email::UnSerializeV2($sMessage);
|
||||
break;
|
||||
|
||||
case Email::ORIGINAL_FORMAT:
|
||||
$oEMail = unserialize($sMessage);
|
||||
break;
|
||||
|
||||
default:
|
||||
return 'Unknown version of the serialization format: '.$iVersion;
|
||||
}
|
||||
$iRes = $oEMail->Send($aIssues, true /* force synchro !!!!! */);
|
||||
switch ($iRes)
|
||||
{
|
||||
case EMAIL_SEND_OK:
|
||||
return "Sent";
|
||||
|
||||
case EMAIL_SEND_PENDING:
|
||||
return "Bug - the email should be sent in synchronous mode";
|
||||
|
||||
case EMAIL_SEND_ERROR:
|
||||
if (is_array($aIssues)) {
|
||||
$sMessage = "Sending eMail failed: ".implode(', ', $aIssues);
|
||||
} else {
|
||||
$sMessage = "Sending eMail failed.";
|
||||
}
|
||||
throw new Exception($sMessage);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An async notification to be sent to iTop users through the newsroom
|
||||
* @since 3.2.0
|
||||
*/
|
||||
class AsyncSendNewsroom extends AsyncTask {
|
||||
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "core/cmdb",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "created",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_async_send_newsroom",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeText("recipients", array("allowed_values"=>null, "sql"=>"recipients", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("action_id", array("targetclass"=>"Action", "allowed_values"=>null, "sql"=>"action_id", "default_value"=>null, "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("trigger_id", array("targetclass"=>"Trigger", "allowed_values"=>null, "sql"=>"trigger_id", "default_value"=>null, "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("title", array("allowed_values"=>null, "sql"=>"title", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("message", array("allowed_values"=>null, "sql"=>"message", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeInteger("object_id", array("allowed_values"=>null, "sql"=>"object_id", "default_value"=>null, "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("object_class", array("allowed_values"=>null, "sql"=>"object_class", "default_value"=>null, "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("url", array("allowed_values"=>null, "sql"=>"url", "default_value"=>null, "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeDateTime("date", array("allowed_values"=>null, "sql"=>"date", "default_value"=>'NOW()', "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreCannotSaveObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \CoreWarning
|
||||
* @throws \MySQLException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public static function AddToQueue(int $iActionId, int $iTriggerId, array $aRecipients, string $sMessage, string $sTitle, string $sUrl, int $iObjectId, ?string $sObjectClass): void
|
||||
{
|
||||
$oNew = new static();
|
||||
$oNew->Set('action_id', $iActionId);
|
||||
$oNew->Set('trigger_id', $iTriggerId);
|
||||
$oNew->Set('recipients', json_encode($aRecipients));
|
||||
$oNew->Set('message', $sMessage);
|
||||
$oNew->Set('title', $sTitle);
|
||||
$oNew->Set('url', $sUrl);
|
||||
$oNew->Set('object_id', $iObjectId);
|
||||
$oNew->Set('object_class', $sObjectClass);
|
||||
$oNew->SetCurrentDate('date');
|
||||
|
||||
$oNew->DBInsert();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function DoProcess()
|
||||
{
|
||||
$oAction = MetaModel::GetObject('Action', $this->Get('action_id'));
|
||||
$iTriggerId = $this->Get('trigger_id');
|
||||
$aRecipients = json_decode($this->Get('recipients'));
|
||||
$sMessage = $this->Get('message');
|
||||
$sTitle = $this->Get('title');
|
||||
$sUrl = $this->Get('url');
|
||||
$iObjectId = $this->Get('object_id');
|
||||
$sObjectClass = $this->Get('object_class');
|
||||
$sDate = $this->Get('date');
|
||||
|
||||
foreach ($aRecipients as $iRecipientId)
|
||||
{
|
||||
$oEvent = EventNotificationNewsroomService::MakeEventFromAction($oAction, $iRecipientId, $iTriggerId, $sMessage, $sTitle, $sUrl, $iObjectId, $sObjectClass, $sDate);
|
||||
$oEvent->DBInsertNoReload();
|
||||
}
|
||||
|
||||
return "Sent";
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -26,17 +26,54 @@ MetaModel::IncludeModule('application/query.class.inc.php');
|
||||
MetaModel::IncludeModule('setup/moduleinstallation.class.inc.php');
|
||||
|
||||
|
||||
MetaModel::IncludeModule('core/event.class.inc.php');
|
||||
MetaModel::IncludeModule('core/action.class.inc.php');
|
||||
MetaModel::IncludeModule('core/trigger.class.inc.php');
|
||||
MetaModel::IncludeModule('core/bulkexport.class.inc.php');
|
||||
MetaModel::IncludeModule(APPROOT.'/sources/Application/DataModel/Event/Event.php');
|
||||
MetaModel::IncludeModule(APPROOT.'/sources/Application/DataModel/Event/EventNotification.php');
|
||||
MetaModel::IncludeModule(APPROOT.'/sources/Application/DataModel/Event/EventNotificationEmail.php');
|
||||
MetaModel::IncludeModule(APPROOT.'/sources/Application/DataModel/Event/EventIssue.php');
|
||||
MetaModel::IncludeModule(APPROOT.'/sources/Application/DataModel/Event/EventWebService.php');
|
||||
MetaModel::IncludeModule(APPROOT.'/sources/Application/DataModel/Event/EventRestService.php');
|
||||
MetaModel::IncludeModule(APPROOT.'/sources/Application/DataModel/Event/EventLoginUsage.php');
|
||||
MetaModel::IncludeModule(APPROOT.'/sources/Application/DataModel/Event/EventOnObject.php');
|
||||
|
||||
MetaModel::IncludeModule(APPROOT.'/sources/Core/DataModel/AsyncTask/ExecAsyncTask.php');
|
||||
MetaModel::IncludeModule(APPROOT.'/sources/Core/DataModel/AsyncTask/AsyncTask.php');
|
||||
MetaModel::IncludeModule(APPROOT.'/sources/Core/DataModel/AsyncTask/AsyncSendEmail.php');
|
||||
MetaModel::IncludeModule(APPROOT.'/sources/Core/DataModel/AsyncTask/ExecAsyncTask.php');
|
||||
MetaModel::IncludeModule(APPROOT.'/sources/Core/DataModel/AsyncTask/AsyncSendNewsroom.php');
|
||||
|
||||
MetaModel::IncludeModule(APPROOT.'/core/email.class.inc.php');
|
||||
|
||||
MetaModel::IncludeModule(APPROOT.'/sources/Application/DataModel/TriggerAndAction/Action.php');
|
||||
MetaModel::IncludeModule(APPROOT.'/sources/Application/DataModel/TriggerAndAction/ActionNotification.php');
|
||||
MetaModel::IncludeModule(APPROOT.'/sources/Application/DataModel/TriggerAndAction/ActionEmail.php');
|
||||
MetaModel::IncludeModule(APPROOT.'/sources/Application/DataModel/TriggerAndAction/lnkTriggerAction.php');
|
||||
MetaModel::IncludeModule(APPROOT.'/sources/Application/DataModel/TriggerAndAction/Trigger.php');
|
||||
MetaModel::IncludeModule(APPROOT.'/sources/Application/DataModel/TriggerAndAction/TriggerOnAttributeBlobDownload.php');
|
||||
MetaModel::IncludeModule(APPROOT.'/sources/Application/DataModel/TriggerAndAction/TriggerOnObject.php');
|
||||
MetaModel::IncludeModule(APPROOT.'/sources/Application/DataModel/TriggerAndAction/TriggerOnObjectCreate.php');
|
||||
MetaModel::IncludeModule(APPROOT.'/sources/Application/DataModel/TriggerAndAction/TriggerOnObjectDelete.php');
|
||||
MetaModel::IncludeModule(APPROOT.'/sources/Application/DataModel/TriggerAndAction/TriggerOnObjectMention.php');
|
||||
MetaModel::IncludeModule(APPROOT.'/sources/Application/DataModel/TriggerAndAction/TriggerOnObjectUpdate.php');
|
||||
MetaModel::IncludeModule(APPROOT.'/sources/Application/DataModel/TriggerAndAction/TriggerOnPortalUpdate.php');
|
||||
MetaModel::IncludeModule(APPROOT.'/sources/Application/DataModel/TriggerAndAction/TriggerOnStateChange.php');
|
||||
MetaModel::IncludeModule(APPROOT.'/sources/Application/DataModel/TriggerAndAction/TriggerOnStateEnter.php');
|
||||
MetaModel::IncludeModule(APPROOT.'/sources/Application/DataModel/TriggerAndAction/TriggerOnStateLeave.php');
|
||||
MetaModel::IncludeModule(APPROOT.'/sources/Application/DataModel/TriggerAndAction/TriggerOnThresholdReached.php');
|
||||
|
||||
//MetaModel::IncludeModule('core/bulkexport.class.inc.php');
|
||||
MetaModel::IncludeModule(APPROOT.'/sources/Application/BulkExport/BulkExport.php');
|
||||
MetaModel::IncludeModule(APPROOT.'/sources/Application/BulkExport/BulkExportException.php');
|
||||
MetaModel::IncludeModule(APPROOT.'/sources/Application/BulkExport/BulkExportMissingParameterException.php');
|
||||
MetaModel::IncludeModule(APPROOT.'/sources/Application/BulkExport/BulkExportResultGC.php');
|
||||
|
||||
MetaModel::IncludeModule('core/ownershiplock.class.inc.php');
|
||||
MetaModel::IncludeModule('core/tagsetfield.class.inc.php');
|
||||
MetaModel::IncludeModule(APPROOT.'/sources/Core/DataModel/TagSetFieldData.php');
|
||||
MetaModel::IncludeModule('synchro/synchrodatasource.class.inc.php');
|
||||
MetaModel::IncludeModule('core/backgroundtask.class.inc.php');
|
||||
MetaModel::IncludeModule(APPROOT.'/sources/Core/DataModel/BackgroundTask.php');
|
||||
MetaModel::IncludeModule('core/inlineimage.class.inc.php');
|
||||
MetaModel::IncludeModule('core/counter.class.inc.php');
|
||||
MetaModel::IncludeModule('core/TemporaryObjectDescriptor.php');
|
||||
//MetaModel::IncludeModule('core/counter.class.inc.php');
|
||||
MetaModel::IncludeModule(APPROOT.'/sources/Core/DataModel/KeyValueStore.php');
|
||||
MetaModel::IncludeModule(APPROOT.'/sources/Core/DataModel/TemporaryObjectDescriptor.php');
|
||||
|
||||
MetaModel::IncludeModule('webservices/webservices.basic.php');
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,514 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2013-2024 Combodo SAS
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
use Combodo\iTop\Application\WebPage\Page;
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
|
||||
define('EXPORTER_DEFAULT_CHUNK_SIZE', 1000);
|
||||
|
||||
class BulkExportException extends Exception
|
||||
{
|
||||
protected $sLocalizedMessage;
|
||||
public function __construct($message, $sLocalizedMessage, $code = 0, $previous = null)
|
||||
{
|
||||
parent::__construct($message, $code, $previous);
|
||||
$this->sLocalizedMessage = $sLocalizedMessage;
|
||||
}
|
||||
|
||||
public function GetLocalizedMessage()
|
||||
{
|
||||
return $this->sLocalizedMessage;
|
||||
}
|
||||
}
|
||||
class BulkExportMissingParameterException extends BulkExportException
|
||||
{
|
||||
public function __construct($sFieldCode)
|
||||
{
|
||||
parent::__construct('Missing parameter: '.$sFieldCode, Dict::Format('Core:BulkExport:MissingParameter_Param', $sFieldCode));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Class BulkExport
|
||||
*
|
||||
* @copyright Copyright (C) 2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
class BulkExportResult extends DBObject
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => 'core/cmdb',
|
||||
"key_type" => 'autoincrement',
|
||||
"name_attcode" => array('created'),
|
||||
"state_attcode" => '',
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => 'priv_bulk_export_result',
|
||||
"db_key_field" => 'id',
|
||||
"db_finalclass_field" => '',
|
||||
"display_template" => '',
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeDateTime("created", array("allowed_values"=>null, "sql"=>"created", "default_value"=>"NOW()", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeInteger("user_id", array("allowed_values"=>null, "sql"=>"user_id", "default_value"=>0, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeInteger("chunk_size", array("allowed_values"=>null, "sql"=>"chunk_size", "default_value"=>0, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("format", array("allowed_values"=>null, "sql"=>"format", "default_value"=>'', "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("temp_file_path", array("allowed_values"=>null, "sql"=>"temp_file_path", "default_value"=>'', "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeLongText("search", array("allowed_values"=>null, "sql"=>"search", "default_value"=>'', "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeLongText("status_info", array("allowed_values"=>null, "sql"=>"status_info", "default_value"=>'', "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeBoolean("localize_output", array("allowed_values"=>null, "sql"=>"localize_output", "default_value"=>true, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws CoreUnexpectedValue
|
||||
* @throws Exception
|
||||
*/
|
||||
public function ComputeValues()
|
||||
{
|
||||
$this->Set('user_id', UserRights::GetUserId());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Garbage collector for cleaning "old" export results from the database and the disk.
|
||||
* This background process runs once per day and deletes the results of all exports which
|
||||
* are older than one day.
|
||||
*/
|
||||
class BulkExportResultGC implements iBackgroundProcess
|
||||
{
|
||||
public function GetPeriodicity()
|
||||
{
|
||||
return 24*3600; // seconds
|
||||
}
|
||||
|
||||
public function Process($iTimeLimit)
|
||||
{
|
||||
$sDateLimit = date(AttributeDateTime::GetSQLFormat(), time() - 24*3600); // Every BulkExportResult older than one day will be deleted
|
||||
|
||||
$sOQL = "SELECT BulkExportResult WHERE created < '$sDateLimit'";
|
||||
$iProcessed = 0;
|
||||
while (time() < $iTimeLimit)
|
||||
{
|
||||
// Next one ?
|
||||
$oSet = new CMDBObjectSet(DBObjectSearch::FromOQL($sOQL), array('created' => true) /* order by*/, array(), null, 1 /* limit count */);
|
||||
$oSet->OptimizeColumnLoad(array('BulkExportResult' => array('temp_file_path')));
|
||||
$oResult = $oSet->Fetch();
|
||||
if (is_null($oResult))
|
||||
{
|
||||
// Nothing to be done
|
||||
break;
|
||||
}
|
||||
$iProcessed++;
|
||||
@unlink($oResult->Get('temp_file_path'));
|
||||
utils::PushArchiveMode(false);
|
||||
$oResult->DBDelete();
|
||||
utils::PopArchiveMode();
|
||||
}
|
||||
return "Cleaned $iProcessed old export results(s).";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class BulkExport
|
||||
*
|
||||
* @copyright Copyright (C) 2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
abstract class BulkExport
|
||||
{
|
||||
protected $oSearch;
|
||||
protected $iChunkSize;
|
||||
protected $sFormatCode;
|
||||
protected $aStatusInfo;
|
||||
protected $oBulkExportResult;
|
||||
protected $sTmpFile;
|
||||
protected $bLocalizeOutput;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->oSearch = null;
|
||||
$this->iChunkSize = 0;
|
||||
$this->sFormatCode = null;
|
||||
$this->aStatusInfo = [
|
||||
'show_obsolete_data' => utils::ShowObsoleteData(),
|
||||
];
|
||||
$this->oBulkExportResult = null;
|
||||
$this->sTmpFile = '';
|
||||
$this->bLocalizeOutput = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the first class capable of exporting the data in the given format
|
||||
*
|
||||
* @param string $sFormatCode The lowercase format (e.g. html, csv, spreadsheet, xlsx, xml, json, pdf...)
|
||||
* @param DBSearch $oSearch The search/filter defining the set of objects to export or null when listing the supported formats
|
||||
*
|
||||
* @return BulkExport|null
|
||||
* @throws ReflectionException
|
||||
*/
|
||||
static public function FindExporter($sFormatCode, $oSearch = null)
|
||||
{
|
||||
foreach(get_declared_classes() as $sPHPClass)
|
||||
{
|
||||
$oRefClass = new ReflectionClass($sPHPClass);
|
||||
if ($oRefClass->isSubclassOf('BulkExport') && !$oRefClass->isAbstract())
|
||||
{
|
||||
/** @var BulkExport $oBulkExporter */
|
||||
$oBulkExporter = new $sPHPClass();
|
||||
if ($oBulkExporter->IsFormatSupported($sFormatCode, $oSearch))
|
||||
{
|
||||
if ($oSearch)
|
||||
{
|
||||
$oBulkExporter->SetObjectList($oSearch);
|
||||
}
|
||||
return $oBulkExporter;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the exporter corresponding to the given persistent token
|
||||
*
|
||||
* @param int $iPersistentToken The identifier of the BulkExportResult object storing the information
|
||||
*
|
||||
* @return BulkExport|null
|
||||
* @throws ArchivedObjectException
|
||||
* @throws CoreException
|
||||
* @throws ReflectionException
|
||||
*/
|
||||
static public function FindExporterFromToken($iPersistentToken = null)
|
||||
{
|
||||
$oBulkExporter = null;
|
||||
$oInfo = MetaModel::GetObject('BulkExportResult', $iPersistentToken, false);
|
||||
if ($oInfo && ($oInfo->Get('user_id') == UserRights::GetUserId()))
|
||||
{
|
||||
$sFormatCode = $oInfo->Get('format');
|
||||
$aStatusInfo = json_decode($oInfo->Get('status_info'),true);
|
||||
|
||||
$oSearch = DBObjectSearch::unserialize($oInfo->Get('search'));
|
||||
$oSearch->SetShowObsoleteData($aStatusInfo['show_obsolete_data']);
|
||||
$oBulkExporter = self::FindExporter($sFormatCode, $oSearch);
|
||||
if ($oBulkExporter)
|
||||
{
|
||||
$oBulkExporter->SetFormat($sFormatCode);
|
||||
$oBulkExporter->SetObjectList($oSearch);
|
||||
$oBulkExporter->SetChunkSize($oInfo->Get('chunk_size'));
|
||||
$oBulkExporter->SetStatusInfo($aStatusInfo);
|
||||
|
||||
$oBulkExporter->SetLocalizeOutput($oInfo->Get('localize_output'));
|
||||
|
||||
|
||||
$oBulkExporter->sTmpFile = $oInfo->Get('temp_file_path');
|
||||
$oBulkExporter->oBulkExportResult = $oInfo;
|
||||
}
|
||||
}
|
||||
return $oBulkExporter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $data
|
||||
* @throws Exception
|
||||
*/
|
||||
public function AppendToTmpFile($data)
|
||||
{
|
||||
if ($this->sTmpFile == '')
|
||||
{
|
||||
$this->sTmpFile = $this->MakeTmpFile($this->GetFileExtension());
|
||||
}
|
||||
$hFile = fopen($this->sTmpFile, 'ab');
|
||||
if ($hFile !== false)
|
||||
{
|
||||
fwrite($hFile, $data);
|
||||
fclose($hFile);
|
||||
}
|
||||
}
|
||||
|
||||
public function GetTmpFilePath()
|
||||
{
|
||||
return $this->sTmpFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists all possible export formats. The output is a hash array in the form: 'format_code' => 'localized format label'
|
||||
* @return array :string
|
||||
*/
|
||||
static public function FindSupportedFormats()
|
||||
{
|
||||
$aSupportedFormats = array();
|
||||
foreach(get_declared_classes() as $sPHPClass)
|
||||
{
|
||||
$oRefClass = new ReflectionClass($sPHPClass);
|
||||
if ($oRefClass->isSubClassOf('BulkExport') && !$oRefClass->isAbstract())
|
||||
{
|
||||
$oBulkExporter = new $sPHPClass;
|
||||
$aFormats = $oBulkExporter->GetSupportedFormats();
|
||||
$aSupportedFormats = array_merge($aSupportedFormats, $aFormats);
|
||||
}
|
||||
}
|
||||
return $aSupportedFormats;
|
||||
}
|
||||
|
||||
/**
|
||||
* (non-PHPdoc)
|
||||
* @see iBulkExport::SetChunkSize()
|
||||
*/
|
||||
public function SetChunkSize($iChunkSize)
|
||||
{
|
||||
$this->iChunkSize = $iChunkSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $bLocalizeOutput
|
||||
*/
|
||||
public function SetLocalizeOutput($bLocalizeOutput)
|
||||
{
|
||||
$this->bLocalizeOutput = $bLocalizeOutput;
|
||||
}
|
||||
|
||||
/**
|
||||
* (non-PHPdoc)
|
||||
* @see iBulkExport::SetObjectList()
|
||||
*/
|
||||
public function SetObjectList(DBSearch $oSearch)
|
||||
{
|
||||
$oSearch->SetShowObsoleteData($this->aStatusInfo['show_obsolete_data']);
|
||||
$this->oSearch = $oSearch;
|
||||
}
|
||||
|
||||
public function SetFormat($sFormatCode)
|
||||
{
|
||||
$this->sFormatCode = $sFormatCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* (non-PHPdoc)
|
||||
* @see iBulkExport::IsFormatSupported()
|
||||
*/
|
||||
public function IsFormatSupported($sFormatCode, $oSearch = null)
|
||||
{
|
||||
return array_key_exists($sFormatCode, $this->GetSupportedFormats());
|
||||
}
|
||||
|
||||
/**
|
||||
* (non-PHPdoc)
|
||||
* @see iBulkExport::GetSupportedFormats()
|
||||
*/
|
||||
public function GetSupportedFormats()
|
||||
{
|
||||
return array(); // return array('csv' => Dict::S('UI:ExportFormatCSV'));
|
||||
}
|
||||
|
||||
|
||||
public function SetHttpHeaders(WebPage $oPage)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function GetHeader()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
abstract public function GetNextChunk(&$aStatus);
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function GetFooter()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function SaveState()
|
||||
{
|
||||
if ($this->oBulkExportResult === null)
|
||||
{
|
||||
$this->oBulkExportResult = new BulkExportResult();
|
||||
$this->oBulkExportResult->Set('format', $this->sFormatCode);
|
||||
$this->oBulkExportResult->Set('search', $this->oSearch->serialize());
|
||||
$this->oBulkExportResult->Set('chunk_size', $this->iChunkSize);
|
||||
$this->oBulkExportResult->Set('localize_output', $this->bLocalizeOutput);
|
||||
}
|
||||
$this->oBulkExportResult->Set('status_info', json_encode($this->GetStatusInfo()));
|
||||
$this->oBulkExportResult->Set('temp_file_path', $this->sTmpFile);
|
||||
utils::PushArchiveMode(false);
|
||||
$ret = $this->oBulkExportResult->DBWrite();
|
||||
utils::PopArchiveMode();
|
||||
return $ret;
|
||||
}
|
||||
|
||||
public function Cleanup()
|
||||
{
|
||||
if (($this->oBulkExportResult && (!$this->oBulkExportResult->IsNew())))
|
||||
{
|
||||
$sFilename = $this->oBulkExportResult->Get('temp_file_path');
|
||||
if ($sFilename != '')
|
||||
{
|
||||
@unlink($sFilename);
|
||||
}
|
||||
utils::PushArchiveMode(false);
|
||||
$this->oBulkExportResult->DBDelete();
|
||||
utils::PopArchiveMode();
|
||||
}
|
||||
}
|
||||
|
||||
public function EnumFormParts()
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated 3.0.0 use GetFormPart instead
|
||||
*/
|
||||
public function DisplayFormPart(WebPage $oP, $sPartId)
|
||||
{
|
||||
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('use GetFormPart instead');
|
||||
$oP->AddSubBlock($this->GetFormPart($oP, $sPartId));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param WebPage $oP
|
||||
* @param $sPartId
|
||||
*
|
||||
* @return UIContentBlock
|
||||
*/
|
||||
public function GetFormPart(WebPage $oP, $sPartId)
|
||||
{
|
||||
}
|
||||
|
||||
public function DisplayUsage(Page $oP)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function ReadParameters()
|
||||
{
|
||||
$this->bLocalizeOutput = !((bool)utils::ReadParam('no_localize', 0, true, 'integer'));
|
||||
}
|
||||
|
||||
public function GetResultAsHtml()
|
||||
{
|
||||
|
||||
}
|
||||
public function GetRawResult()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function GetMimeType()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function GetFileExtension()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
public function GetCharacterSet()
|
||||
{
|
||||
return 'UTF-8';
|
||||
}
|
||||
|
||||
public function GetStatistics()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function SetFields($sFields)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function GetDownloadFileName()
|
||||
{
|
||||
return Dict::Format('Core:BulkExportOf_Class', MetaModel::GetName($this->oSearch->GetClass())).'.'.$this->GetFileExtension();
|
||||
}
|
||||
|
||||
public function SetStatusInfo($aStatusInfo)
|
||||
{
|
||||
$this->aStatusInfo = $aStatusInfo;
|
||||
}
|
||||
|
||||
public function GetStatusInfo()
|
||||
{
|
||||
return $this->aStatusInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $sExtension
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function MakeTmpFile($sExtension)
|
||||
{
|
||||
if(!is_dir(utils::GetDataPath()."bulk_export"))
|
||||
{
|
||||
@mkdir(utils::GetDataPath()."bulk_export", 0777, true /* recursive */);
|
||||
clearstatcache();
|
||||
}
|
||||
if (!is_writable(utils::GetDataPath()."bulk_export"))
|
||||
{
|
||||
throw new Exception('Data directory "'.utils::GetDataPath().'bulk_export" could not be written.');
|
||||
}
|
||||
|
||||
$iNum = rand();
|
||||
do
|
||||
{
|
||||
$iNum++;
|
||||
$sToken = sprintf("%08x", $iNum);
|
||||
$sFileName = utils::GetDataPath()."bulk_export/$sToken.".$sExtension;
|
||||
$hFile = @fopen($sFileName, 'x');
|
||||
}
|
||||
while($hFile === false);
|
||||
|
||||
fclose($hFile);
|
||||
return $sFileName;
|
||||
}
|
||||
}
|
||||
|
||||
// The built-in exports
|
||||
require_once(APPROOT.'core/tabularbulkexport.class.inc.php');
|
||||
require_once(APPROOT.'core/htmlbulkexport.class.inc.php');
|
||||
if (extension_loaded('gd'))
|
||||
{
|
||||
// PDF export - via TCPDF - requires GD
|
||||
require_once(APPROOT.'core/pdfbulkexport.class.inc.php');
|
||||
}
|
||||
require_once(APPROOT.'core/csvbulkexport.class.inc.php');
|
||||
require_once(APPROOT.'core/excelbulkexport.class.inc.php');
|
||||
require_once(APPROOT.'core/spreadsheetbulkexport.class.inc.php');
|
||||
require_once(APPROOT.'core/xmlbulkexport.class.inc.php');
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -40,9 +40,15 @@ require_once('dict.class.inc.php');
|
||||
|
||||
require_once('attributedef.class.inc.php');
|
||||
require_once('stimulus.class.inc.php');
|
||||
require_once('valuesetdef.class.inc.php');
|
||||
require_once('MyHelpers.class.inc.php');
|
||||
|
||||
require_once(APPROOT.'/sources/Core/ValueSetDefinition/ValueSetDefinition.php');
|
||||
require_once(APPROOT.'/sources/Core/ValueSetDefinition/ValueSetObjects.php');
|
||||
require_once(APPROOT.'/sources/Core/ValueSetDefinition/ValueSetEnum.php');
|
||||
require_once(APPROOT.'/sources/Core/ValueSetDefinition/ValueSetEnumPadded.php');
|
||||
require_once(APPROOT.'/sources/Core/ValueSetDefinition/ValueSetRange.php');
|
||||
require_once(APPROOT.'/sources/Core/ValueSetDefinition/ValueSetEnumClasses.php');
|
||||
|
||||
require_once('oql/expression.class.inc.php');
|
||||
require_once('oql/oqlquery.class.inc.php');
|
||||
require_once('oql/oqlexception.class.inc.php');
|
||||
@@ -59,12 +65,41 @@ require_once('dbobject.class.php');
|
||||
require_once('dbobjectset.class.php');
|
||||
|
||||
require_once('backgroundprocess.inc.php');
|
||||
require_once('asynctask.class.inc.php');
|
||||
require_once('dbproperty.class.inc.php');
|
||||
//require_once('asynctask.class.inc.php');
|
||||
require_once(APPROOT.'/sources/Core/DataModel/AsyncTask/ExecAsyncTask.php');
|
||||
require_once(APPROOT.'/sources/Core/DataModel/AsyncTask/AsyncTask.php');
|
||||
require_once(APPROOT.'/sources/Core/DataModel/AsyncTask/AsyncSendEmail.php');
|
||||
require_once(APPROOT.'/sources/Core/DataModel/AsyncTask/ExecAsyncTask.php');
|
||||
require_once(APPROOT.'/sources/Core/DataModel/AsyncTask/AsyncSendNewsroom.php');
|
||||
|
||||
require_once(APPROOT.'/sources/Core/DataModel/DBProperty.php');
|
||||
|
||||
// db change tracking data model
|
||||
require_once('cmdbchange.class.inc.php');
|
||||
require_once('cmdbchangeop.class.inc.php');
|
||||
//require_once('cmdbchangeop.class.inc.php');
|
||||
require_once(APPROOT.'/sources/Core/DataModel/CMDBChange/iCMDBChangeOp.php');
|
||||
require_once(APPROOT.'/sources/Core/DataModel/CMDBChange/CMDBChangeOp.php');
|
||||
require_once(APPROOT.'/sources/Core/DataModel/CMDBChange/CMDBChangeOpCreate.php');
|
||||
require_once(APPROOT.'/sources/Core/DataModel/CMDBChange/CMDBChangeOpDelete.php');
|
||||
require_once(APPROOT.'/sources/Core/DataModel/CMDBChange/CMDBChangeOpPlugin.php');
|
||||
require_once(APPROOT.'/sources/Core/DataModel/CMDBChange/CMDBChangeOpSetAttribute.php');
|
||||
require_once(APPROOT.'/sources/Core/DataModel/CMDBChange/CMDBChangeOpSetAttributeBlob.php');
|
||||
require_once(APPROOT.'/sources/Core/DataModel/CMDBChange/CMDBChangeOpSetAttributeCaseLog.php');
|
||||
require_once(APPROOT.'/sources/Core/DataModel/CMDBChange/CMDBChangeOpSetAttributeCustomFields.php');
|
||||
require_once(APPROOT.'/sources/Core/DataModel/CMDBChange/CMDBChangeOpSetAttributeEncrypted.php');
|
||||
require_once(APPROOT.'/sources/Core/DataModel/CMDBChange/CMDBChangeOpSetAttributeHTML.php');
|
||||
require_once(APPROOT.'/sources/Core/DataModel/CMDBChange/CMDBChangeOpSetAttributeLinks.php');
|
||||
require_once(APPROOT.'/sources/Core/DataModel/CMDBChange/CMDBChangeOpSetAttributeLinksAddRemove.php');
|
||||
require_once(APPROOT.'/sources/Core/DataModel/CMDBChange/CMDBChangeOpSetAttributeLinksTune.php');
|
||||
require_once(APPROOT.'/sources/Core/DataModel/CMDBChange/CMDBChangeOpSetAttributeLongText.php');
|
||||
require_once(APPROOT.'/sources/Core/DataModel/CMDBChange/CMDBChangeOpSetAttributeOneWayPassword.php');
|
||||
require_once(APPROOT.'/sources/Core/DataModel/CMDBChange/CMDBChangeOpSetAttributeScalar.php');
|
||||
require_once(APPROOT.'/sources/Core/DataModel/CMDBChange/CMDBChangeOpSetAttributeTagSet.php');
|
||||
require_once(APPROOT.'/sources/Core/DataModel/CMDBChange/CMDBChangeOpSetAttributeText.php');
|
||||
require_once(APPROOT.'/sources/Core/DataModel/CMDBChange/CMDBChangeOpSetAttributeURL.php');
|
||||
|
||||
|
||||
|
||||
|
||||
// customization data model
|
||||
// Romain: temporary moved into application.inc.php (see explanations there)
|
||||
@@ -77,7 +112,7 @@ require_once('cmdbchangeop.class.inc.php');
|
||||
|
||||
require_once('templatestring.class.inc.php');
|
||||
require_once('csvparser.class.inc.php');
|
||||
require_once('bulkchange.class.inc.php');
|
||||
//require_once('bulkchange.class.inc.php');
|
||||
|
||||
/**
|
||||
* A persistent object, which changes are accurately recorded
|
||||
|
||||
@@ -49,7 +49,13 @@ define('ACCESS_READONLY', 0);
|
||||
*/
|
||||
|
||||
require_once('attributedef.class.inc.php'); // For the defines
|
||||
require_once('simplecrypt.class.inc.php');
|
||||
require_once(APPROOT.'/sources/Application/SimpleCrypt/CryptEngine.php');
|
||||
require_once(APPROOT.'/sources/Application/SimpleCrypt/SimpleCrypt.php');
|
||||
require_once(APPROOT.'/sources/Application/SimpleCrypt/SimpleCryptMcryptEngine.php');
|
||||
require_once(APPROOT.'/sources/Application/SimpleCrypt/SimpleCryptOpenSSLEngine.php');
|
||||
require_once(APPROOT.'/sources/Application/SimpleCrypt/SimpleCryptOpenSSLMcryptCompatibilityEngine.php');
|
||||
require_once(APPROOT.'/sources/Application/SimpleCrypt/SimpleCryptSimpleEngine.php');
|
||||
require_once(APPROOT.'/sources/Application/SimpleCrypt/SimpleCryptSodiumEngine.php');
|
||||
|
||||
// was utf8 but it only supports BMP chars (https://dev.mysql.com/doc/refman/5.5/en/charset-unicode-utf8mb4.html)
|
||||
// so we switched to utf8mb4 in iTop 2.5, adding dependency to MySQL 5.5.3
|
||||
|
||||
@@ -1,251 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2013-2024 Combodo SAS
|
||||
*
|
||||
* 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 ItopCounter
|
||||
*
|
||||
*/
|
||||
final class ItopCounter
|
||||
{
|
||||
|
||||
/**
|
||||
* Key based counter.
|
||||
* The counter is protected against concurrency script.
|
||||
*
|
||||
* @param $sCounterName
|
||||
* @param null|callable $oNewObjectValueProvider optional callable that must return an integer. Used when no key is found
|
||||
*
|
||||
* @return int the counter starting at
|
||||
* * `0` when no $oNewObjectValueProvider is given (or null)
|
||||
* * `$oNewObjectValueProvider() + 1` otherwise
|
||||
*
|
||||
* @throws \CoreException
|
||||
* @throws \MySQLException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function Inc($sCounterName, $oNewObjectValueProvider = null)
|
||||
{
|
||||
$sSelfClassName = self::class;
|
||||
$sMutexKeyName = "{$sSelfClassName}-{$sCounterName}";
|
||||
$oiTopMutex = new iTopMutex($sMutexKeyName);
|
||||
$oiTopMutex->Lock();
|
||||
|
||||
$bIsInsideTransaction = CMDBSource::IsInsideTransaction();
|
||||
if ($bIsInsideTransaction)
|
||||
{
|
||||
// # Transaction isolation hack:
|
||||
// When inside a transaction, we need to open a new connection for the counter.
|
||||
// So it is visible immediately to the connections outside of the transaction.
|
||||
// Either way, the lock is not long enought, and there would be duplicate ref.
|
||||
//
|
||||
// SELECT ... FOR UPDATE would have also worked but with the cost of extra long lock (until the commit),
|
||||
// we did not wanted this! As opening a short connection is less prone to starving than a long running one.
|
||||
// Plus it would trigger way more deadlocks!
|
||||
$hDBLink = self::InitMySQLSession();
|
||||
}
|
||||
else
|
||||
{
|
||||
$hDBLink = CMDBSource::GetMysqli();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$oFilter = DBObjectSearch::FromOQL('SELECT KeyValueStore WHERE key_name=:key_name AND namespace=:namespace', array(
|
||||
'key_name' => $sCounterName,
|
||||
'namespace' => $sSelfClassName,
|
||||
));
|
||||
$oAttDef = MetaModel::GetAttributeDef(KeyValueStore::class, 'value');
|
||||
$aAttToLoad = array(KeyValueStore::class => array('value' => $oAttDef));
|
||||
$sSql = $oFilter->MakeSelectQuery(array(), array(), $aAttToLoad);
|
||||
$hResult = mysqli_query($hDBLink, $sSql);
|
||||
$aCounter = mysqli_fetch_array($hResult, MYSQLI_NUM);
|
||||
mysqli_free_result($hResult);
|
||||
|
||||
//Rebuild the filter, as the MakeSelectQuery polluted the orignal and it cannot be reused
|
||||
$oFilter = DBObjectSearch::FromOQL('SELECT KeyValueStore WHERE key_name=:key_name AND namespace=:namespace', array(
|
||||
'key_name' => $sCounterName,
|
||||
'namespace' => $sSelfClassName,
|
||||
));
|
||||
|
||||
if (is_null($aCounter))
|
||||
{
|
||||
if (null != $oNewObjectValueProvider)
|
||||
{
|
||||
$iComputedValue = $oNewObjectValueProvider();
|
||||
}
|
||||
else
|
||||
{
|
||||
$iComputedValue = 0;
|
||||
}
|
||||
|
||||
$iCurrentValue = $iComputedValue + 1;
|
||||
|
||||
$aQueryParams = array(
|
||||
'key_name' => $sCounterName,
|
||||
'value' => "$iCurrentValue",
|
||||
'namespace' => $sSelfClassName,
|
||||
);
|
||||
|
||||
$sSql = $oFilter->MakeInsertQuery($aQueryParams);
|
||||
}
|
||||
else
|
||||
{
|
||||
$iCurrentValue = (int) $aCounter[1];
|
||||
$iCurrentValue++;
|
||||
$aQueryParams = array(
|
||||
'value' => "$iCurrentValue",
|
||||
);
|
||||
|
||||
$sSql = $oFilter->MakeUpdateQuery($aQueryParams);
|
||||
}
|
||||
|
||||
$hResult = mysqli_query($hDBLink, $sSql);
|
||||
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
IssueLog::Error($e->getMessage());
|
||||
throw $e;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if ($bIsInsideTransaction)
|
||||
{
|
||||
mysqli_close($hDBLink);
|
||||
}
|
||||
$oiTopMutex->Unlock();
|
||||
}
|
||||
|
||||
return $iCurrentValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* handle a counter for the root class of given $sLeafClass.
|
||||
* If no counter exist initialize it with the `max(id) + 1`
|
||||
*
|
||||
*
|
||||
*
|
||||
* @param $sLeafClass
|
||||
*
|
||||
* @return int
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreCannotSaveObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreOqlMultipleResultsForbiddenException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \MySQLException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public static function IncClass($sLeafClass)
|
||||
{
|
||||
$sRootClass = MetaModel::GetRootClass($sLeafClass);
|
||||
|
||||
$oNewObjectCallback = function() use ($sRootClass)
|
||||
{
|
||||
$sRootTable = MetaModel::DBGetTable($sRootClass);
|
||||
$sIdField = MetaModel::DBGetKey($sRootClass);
|
||||
|
||||
return CMDBSource::QueryToScalar("SELECT max(`$sIdField`) FROM `$sRootTable`");
|
||||
};
|
||||
|
||||
return self::Inc($sRootClass, $oNewObjectCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \mysqli
|
||||
* @throws \ConfigException
|
||||
* @throws \CoreException
|
||||
* @throws \MySQLException
|
||||
*/
|
||||
private static function InitMySQLSession()
|
||||
{
|
||||
$oConfig = utils::GetConfig();
|
||||
$sDBHost = $oConfig->Get('db_host');
|
||||
$sDBUser = $oConfig->Get('db_user');
|
||||
$sDBPwd = $oConfig->Get('db_pwd');
|
||||
$sDBName = $oConfig->Get('db_name');
|
||||
$bDBTlsEnabled = $oConfig->Get('db_tls.enabled');
|
||||
$sDBTlsCA = $oConfig->Get('db_tls.ca');
|
||||
|
||||
$hDBLink = CMDBSource::GetMysqliInstance($sDBHost, $sDBUser, $sDBPwd, $sDBName, $bDBTlsEnabled, $sDBTlsCA, false);
|
||||
|
||||
if (!$hDBLink)
|
||||
{
|
||||
throw new MySQLException('Could not connect to the DB server '.mysqli_connect_error().' (mysql errno: '.mysqli_connect_errno(), array('host' => $sDBHost, 'user' => $sDBUser));
|
||||
}
|
||||
|
||||
return $hDBLink;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Persistent classes for a CMDB
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
class KeyValueStore extends DBObject
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array(
|
||||
'category' => '',
|
||||
'key_type' => 'autoincrement',
|
||||
'name_attcode' => array('key_name'),
|
||||
'state_attcode' => '',
|
||||
'reconc_keys' => array(''),
|
||||
'db_table' => 'key_value_store',
|
||||
'db_key_field' => 'id',
|
||||
'db_finalclass_field' => '',
|
||||
'indexes' => array (
|
||||
array (
|
||||
0 => 'key_name',
|
||||
1 => 'namespace',
|
||||
),
|
||||
),);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeString("namespace", array("allowed_values"=>null, "sql"=>'namespace', "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array(), "always_load_in_tables"=>false)));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("key_name", array("allowed_values"=>null, "sql"=>'key_name', "default_value"=>'', "is_null_allowed"=>false, "depends_on"=>array(), "always_load_in_tables"=>false)));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("value", array("allowed_values"=>null, "sql"=>'value', "default_value"=>'0', "is_null_allowed"=>false, "depends_on"=>array(), "always_load_in_tables"=>false)));
|
||||
|
||||
MetaModel::Init_SetZListItems('details', array (
|
||||
0 => 'key_name',
|
||||
1 => 'value',
|
||||
2 => 'namespace',
|
||||
));
|
||||
MetaModel::Init_SetZListItems('standard_search', array (
|
||||
0 => 'key_name',
|
||||
1 => 'value',
|
||||
2 => 'namespace',
|
||||
));
|
||||
MetaModel::Init_SetZListItems('list', array (
|
||||
0 => 'key_name',
|
||||
1 => 'value',
|
||||
2 => 'namespace',
|
||||
));
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,426 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
|
||||
/**
|
||||
* Copyright (C) 2013-2024 Combodo SAS
|
||||
*
|
||||
* 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 Event extends DBObject implements iDisplay
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "core/cmdb,view_in_gui",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_event",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "realclass",
|
||||
"order_by_default" => array('date' => false)
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeText("message", array("allowed_values"=>null, "sql"=>"message", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeDateTime("date", array("allowed_values"=>null, "sql"=>"date", "default_value"=>"NOW()", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("userinfo", array("allowed_values"=>null, "sql"=>"userinfo", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
// MetaModel::Init_AddAttribute(new AttributeString("userinfo", array("allowed_values"=>null, "sql"=>"userinfo", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('date', 'message', 'userinfo')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('date', 'finalclass', 'message')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
|
||||
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps the given context parameter name to the appropriate filter/search code for this class
|
||||
* @param string $sContextParam Name of the context parameter, i.e. 'org_id'
|
||||
* @return string Filter code, i.e. 'customer_id'
|
||||
*/
|
||||
public static function MapContextParam($sContextParam)
|
||||
{
|
||||
if ($sContextParam == 'menu')
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
return $sContextParam;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns a 'hilight' CSS class, used to hilight a given row in a table
|
||||
* There are currently (i.e defined in the CSS) 4 possible values HILIGHT_CLASS_CRITICAL,
|
||||
* HILIGHT_CLASS_WARNING, HILIGHT_CLASS_OK, HILIGHT_CLASS_NONE
|
||||
* To Be overridden by derived classes
|
||||
* @param void
|
||||
* @return String The desired higlight class for the object/row
|
||||
*/
|
||||
public function GetHilightClass()
|
||||
{
|
||||
// Possible return values are:
|
||||
// HILIGHT_CLASS_CRITICAL, HILIGHT_CLASS_WARNING, HILIGHT_CLASS_OK, HILIGHT_CLASS_NONE
|
||||
return HILIGHT_CLASS_NONE; // Not hilighted by default
|
||||
}
|
||||
|
||||
public static function GetUIPage()
|
||||
{
|
||||
return 'UI.php';
|
||||
}
|
||||
|
||||
function DisplayDetails(WebPage $oPage, $bEditMode = false)
|
||||
{
|
||||
// Object's details
|
||||
//$this->DisplayBareHeader($oPage, $bEditMode);
|
||||
$oPage->AddTabContainer(OBJECT_PROPERTIES_TAB);
|
||||
$oPage->SetCurrentTabContainer(OBJECT_PROPERTIES_TAB);
|
||||
$oPage->SetCurrentTab('UI:PropertiesTab');
|
||||
$this->DisplayBareProperties($oPage, $bEditMode);
|
||||
}
|
||||
|
||||
function DisplayBareProperties(WebPage $oPage, $bEditMode = false, $sPrefix = '', $aExtraParams = array())
|
||||
{
|
||||
if ($bEditMode) return array(); // Not editable
|
||||
|
||||
$aDetails = array();
|
||||
$sClass = get_class($this);
|
||||
$aZList = MetaModel::FlattenZlist(MetaModel::GetZListItems($sClass, 'details'));
|
||||
foreach ($aZList as $sAttCode) {
|
||||
$sDisplayValue = $this->GetAsHTML($sAttCode);
|
||||
$aDetails[] = array('label' => '<span title="'.MetaModel::GetDescription($sClass, $sAttCode).'">'.MetaModel::GetLabel($sClass, $sAttCode).'</span>', 'value' => $sDisplayValue);
|
||||
}
|
||||
$oPage->Details($aDetails);
|
||||
|
||||
return array();
|
||||
}
|
||||
}
|
||||
|
||||
class EventNotification extends Event
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "core/cmdb,view_in_gui",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_event_notification",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"order_by_default" => array('date' => false),
|
||||
'indexes' => array(
|
||||
array( 'object_class', 'object_id'),
|
||||
)
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("trigger_id", array("targetclass"=>"Trigger", "jointype"=> "", "allowed_values"=>null, "sql"=>"trigger_id", "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("action_id", array("targetclass" => "Action", "jointype" => "", "allowed_values" => null, "sql" => "action_id", "is_null_allowed" => false, "on_target_delete" => DEL_AUTO, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeInteger("object_id", array("allowed_values" => null, "sql" => "object_id", "default_value" => 0, "is_null_allowed" => false, "depends_on" => array())));
|
||||
//@since 3.2.0
|
||||
MetaModel::Init_AddAttribute(new AttributeClass("object_class", array("class_category"=>"", "more_values"=>"", "sql"=>"object_class", "default_value"=>null, "is_null_allowed"=>true /*to avoid setting AbstractResource as default in database*/, "depends_on"=>array())));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('date', 'message', 'userinfo', 'trigger_id', 'action_id', 'object_class', 'object_id')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('date', 'message')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
|
||||
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
|
||||
}
|
||||
}
|
||||
|
||||
class EventNotificationEmail extends EventNotification
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "core/cmdb,view_in_gui",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_event_email",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"order_by_default" => array('date' => false)
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeText("to", array("allowed_values"=>null, "sql"=>"to", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("cc", array("allowed_values"=>null, "sql"=>"cc", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("bcc", array("allowed_values"=>null, "sql"=>"bcc", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("from", array("allowed_values"=>null, "sql"=>"from", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("subject", array("allowed_values"=>null, "sql"=>"subject", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeHTML("body", array("allowed_values"=>null, "sql"=>"body", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeTable("attachments", array("allowed_values"=>null, "sql"=>"attachments", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('date', 'userinfo', 'message', 'trigger_id', 'action_id', 'object_class', 'object_id', 'to', 'cc', 'bcc', 'from', 'subject', 'body', 'attachments')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('date', 'message', 'to', 'subject', 'attachments')); // Attributes to be displayed for a list
|
||||
|
||||
// Search criteria
|
||||
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
|
||||
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
|
||||
}
|
||||
}
|
||||
|
||||
class EventIssue extends Event
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "core/cmdb,view_in_gui",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_event_issue",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"order_by_default" => array('date' => false)
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeString("issue", array("allowed_values"=>null, "sql"=>"issue", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("impact", array("allowed_values"=>null, "sql"=>"impact", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("page", array("allowed_values"=>null, "sql"=>"page", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributePropertySet("arguments_post", array("allowed_values"=>null, "sql"=>"arguments_post", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributePropertySet("arguments_get", array("allowed_values"=>null, "sql"=>"arguments_get", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeTable("callstack", array("allowed_values"=>null, "sql"=>"callstack", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributePropertySet("data", array("allowed_values"=>null, "sql"=>"data", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('date', 'message', 'userinfo', 'issue', 'impact', 'page', 'arguments_post', 'arguments_get', 'callstack', 'data')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('date', 'userinfo', 'issue', 'impact')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
|
||||
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
|
||||
}
|
||||
|
||||
protected function OnInsert()
|
||||
{
|
||||
// Init page information: name, arguments
|
||||
//
|
||||
$this->Set('page', @$GLOBALS['_SERVER']['SCRIPT_NAME']);
|
||||
|
||||
if (strlen($this->Get('userinfo')) == 0) {
|
||||
$this->Set('userinfo', UserRights::GetUserId());
|
||||
}
|
||||
|
||||
if (array_key_exists('_GET', $GLOBALS) && is_array($GLOBALS['_GET']))
|
||||
{
|
||||
$this->Set('arguments_get', $this->SanitizeRequestParams($GLOBALS['_GET']));
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->Set('arguments_get', array());
|
||||
}
|
||||
|
||||
if (array_key_exists('_POST', $GLOBALS) && is_array($GLOBALS['_POST']))
|
||||
{
|
||||
$this->Set('arguments_post', $this->SanitizeRequestParams($GLOBALS['_POST']));
|
||||
} else {
|
||||
$this->Set('arguments_post', array());
|
||||
}
|
||||
$sLength = mb_strlen($this->Get('issue'));
|
||||
if ($sLength > 255) {
|
||||
$this->Set('issue', mb_substr($this->Get('issue'), 0, 210)." -truncated ($sLength chars)");
|
||||
}
|
||||
|
||||
$sLength = mb_strlen($this->Get('impact'));
|
||||
if ($sLength > 255) {
|
||||
$this->Set('impact', mb_substr($this->Get('impact'), 0, 210)." -truncated ($sLength chars)");
|
||||
}
|
||||
|
||||
$sLength = mb_strlen($this->Get('page'));
|
||||
if ($sLength > 255) {
|
||||
$this->Set('page', mb_substr($this->Get('page'), 0, 210)." -truncated ($sLength chars)");
|
||||
}
|
||||
}
|
||||
|
||||
protected function SanitizeRequestParams(array $aParams): array
|
||||
{
|
||||
$aSanitizedParams = [];
|
||||
|
||||
foreach ($aParams as $sKey => $sValue) {
|
||||
if (is_string($sValue)) {
|
||||
if (stristr($sKey, 'pwd') !== false || stristr($sKey, 'passwd') !== false || stristr($sKey, 'password') !== false) {
|
||||
$aSanitizedParams[$sKey] = '****';
|
||||
} elseif (mb_strlen($sValue) < 256) {
|
||||
$aSanitizedParams[$sKey] = $sValue;
|
||||
} else {
|
||||
$aSanitizedParams[$sKey] = '!long string: '.mb_strlen($sValue).' chars';
|
||||
}
|
||||
} else {
|
||||
// Not a string (avoid warnings in case the value cannot be easily cast into a string)
|
||||
$aSanitizedParams[$sKey] = @(string)$sValue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return $aSanitizedParams;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class EventWebService extends Event
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "core/cmdb,view_in_gui",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_event_webservice",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"order_by_default" => array('date' => false)
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeString("verb", array("allowed_values"=>null, "sql"=>"verb", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
//MetaModel::Init_AddAttribute(new AttributeStructure("arguments", array("allowed_values"=>null, "sql"=>"data", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeBoolean("result", array("allowed_values"=>null, "sql"=>"result", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("log_info", array("allowed_values"=>null, "sql"=>"log_info", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("log_warning", array("allowed_values"=>null, "sql"=>"log_warning", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("log_error", array("allowed_values"=>null, "sql"=>"log_error", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("data", array("allowed_values"=>null, "sql"=>"data", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('date', 'userinfo', 'verb', 'result', 'log_info', 'log_warning', 'log_error', 'data')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('date', 'userinfo', 'verb', 'result')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
|
||||
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
|
||||
}
|
||||
}
|
||||
|
||||
class EventRestService extends Event
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "core/cmdb,view_in_gui",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_event_restservice",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"order_by_default" => array('date' => false)
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeString("operation", array("allowed_values"=>null, "sql"=>"operation", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("version", array("allowed_values"=>null, "sql"=>"version", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("json_input", array("allowed_values"=>null, "sql"=>"json_input", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeInteger("code", array("allowed_values"=>null, "sql"=>"code", "default_value"=>0, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("json_output", array("allowed_values"=>null, "sql"=>"json_output", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("provider", array("allowed_values"=>null, "sql"=>"provider", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('date', 'userinfo', 'operation', 'version', 'json_input', 'message', 'code', 'json_output', 'provider')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('date', 'userinfo', 'operation', 'message')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
|
||||
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
|
||||
}
|
||||
}
|
||||
|
||||
class EventLoginUsage extends Event
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "core/cmdb,view_in_gui",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_event_loginusage",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"order_by_default" => array('date' => false)
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("user_id", array("targetclass"=>"User", "jointype"=> "", "allowed_values"=>null, "sql"=>"user_id", "is_null_allowed"=>false, "on_target_delete"=>DEL_SILENT, "depends_on"=>array())));
|
||||
$aZList = array('date', 'user_id');
|
||||
if (MetaModel::IsValidAttCode('Contact', 'name'))
|
||||
{
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalField("contact_name", array("allowed_values"=>null, "extkey_attcode"=>"user_id", "target_attcode"=>"contactid", "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
$aZList[] = 'contact_name';
|
||||
}
|
||||
if (MetaModel::IsValidAttCode('Contact', 'email'))
|
||||
{
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalField("contact_email", array("allowed_values"=>null, "extkey_attcode"=>"user_id", "target_attcode"=>"email", "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
$aZList[] = 'contact_email';
|
||||
}
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array_merge($aZList, array('userinfo', 'message'))); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array_merge($aZList, array('userinfo'))); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', $aZList); // Criteria of the std search form
|
||||
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
|
||||
}
|
||||
}
|
||||
|
||||
class EventOnObject extends Event
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "core/cmdb,view_in_gui",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_event_onobject",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
"order_by_default" => array('date' => false)
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeString("obj_class", array("allowed_values"=>null, "sql"=>"obj_class", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeInteger("obj_key", array("allowed_values"=>null, "sql"=>"obj_key", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('date', 'userinfo', 'obj_class', 'obj_key', 'message')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('date', 'userinfo', 'obj_class', 'obj_key', 'message')); // Attributes to be displayed for a list
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,14 @@ require_once APPROOT.'core/modulehandler.class.inc.php';
|
||||
require_once APPROOT.'core/querymodifier.class.inc.php';
|
||||
require_once APPROOT.'core/metamodelmodifier.inc.php';
|
||||
require_once APPROOT.'core/computing.inc.php';
|
||||
require_once APPROOT.'core/relationgraph.class.inc.php';
|
||||
//require_once APPROOT.'core/relationgraph.class.inc.php';
|
||||
require_once(APPROOT.'/sources/Core/RelationGraph/RelationEdge.php');
|
||||
require_once(APPROOT.'/sources/Core/RelationGraph/RelationGraph.php');
|
||||
require_once(APPROOT.'/sources/Core/RelationGraph/RelationObjectNode.php');
|
||||
require_once(APPROOT.'/sources/Core/RelationGraph/RelationRedundancyNode.php');
|
||||
|
||||
|
||||
|
||||
require_once APPROOT.'core/apc-compat.php';
|
||||
require_once APPROOT.'core/expressioncache.class.inc.php';
|
||||
|
||||
|
||||
@@ -1,425 +0,0 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2024 Combodo SAS
|
||||
//
|
||||
// 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/>
|
||||
|
||||
/**
|
||||
* SimpleCrypt Class - crypto helpers
|
||||
* Simple encryption of strings, uses mcrypt or degrades to a pure PHP
|
||||
* implementation when mcrypt is not present.
|
||||
* Based on Miguel Ros' work found at:
|
||||
* http://rossoft.wordpress.com/2006/05/22/simple-encryption-class/
|
||||
*
|
||||
* Usage:
|
||||
* $oSimpleCrypt = new SimpleCrypt();
|
||||
* $encrypted = $oSimpleCrypt->encrypt('a_key','the_text');
|
||||
* $sClearText = $oSimpleCrypt->decrypt('a_key',$encrypted);
|
||||
*
|
||||
* The result is $plain equals to 'the_text'
|
||||
*
|
||||
* You can use a different engine if you don't have Mcrypt:
|
||||
* $oSimpleCrypt = new SimpleCrypt('Simple');
|
||||
*
|
||||
* A string encrypted with one engine can't be decrypted with
|
||||
* a different one even if the key is the same.
|
||||
*
|
||||
* @author Miguel Ros <rossoft@gmail.com>
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
class SimpleCrypt
|
||||
{
|
||||
/**
|
||||
* @var \SimpleCrypt
|
||||
* @since 3.1.0 N°5388
|
||||
*/
|
||||
protected $oEngine;
|
||||
|
||||
public static function GetNewDefaultParams()
|
||||
{
|
||||
if(function_exists('sodium_crypto_secretbox_open') && function_exists('random_bytes')){
|
||||
$sEngineName = 'Sodium';
|
||||
}
|
||||
else if (function_exists('openssl_decrypt'))
|
||||
{
|
||||
$sEngineName = 'OpenSSL';
|
||||
}
|
||||
else if(function_exists('mcrypt_module_open')){
|
||||
$sEngineName = 'Mcrypt';
|
||||
}
|
||||
else
|
||||
{
|
||||
$sEngineName = 'Simple';
|
||||
}
|
||||
$sEngineName = 'SimpleCrypt' . $sEngineName . 'Engine';
|
||||
return $sEngineName::GetNewDefaultParams();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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){
|
||||
case 'Sodium':
|
||||
if(!function_exists('sodium_crypto_secretbox_open')){
|
||||
$sEngineName = 'Simple';
|
||||
}
|
||||
break;
|
||||
case 'Mcrypt':
|
||||
if(!function_exists('mcrypt_module_open')){
|
||||
if (function_exists('openssl_decrypt'))
|
||||
{
|
||||
$sEngineName = 'OpenSSLMcryptCompatibility';
|
||||
}
|
||||
else
|
||||
{
|
||||
$sEngineName = 'Simple';
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'OpenSSL':
|
||||
case 'OpenSSLMcryptCompatibility':
|
||||
if(!function_exists('openssl_decrypt')){
|
||||
$sEngineName = 'Simple';
|
||||
}
|
||||
break;
|
||||
case 'Simple':
|
||||
break;
|
||||
default:
|
||||
throw new Exception(Dict::Format("Core:AttributeEncryptUnknownLibrary", $sEngineName));
|
||||
}
|
||||
|
||||
$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);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Decrypts the string by the given key
|
||||
* @param string $key
|
||||
* @param string $string Ciphered 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"
|
||||
* Tryes to use the best available random number generator
|
||||
* @return string The generated random "salt"
|
||||
*/
|
||||
static function GetNewSalt()
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
//echo "Random bits pulled from /dev/urandom<br/>\n";
|
||||
$sRandomBits .= @fread($fp,16);
|
||||
@fclose($fp);
|
||||
}
|
||||
else
|
||||
{
|
||||
// MS-Windows platform?
|
||||
if (@class_exists('COM'))
|
||||
{
|
||||
// http://msdn.microsoft.com/en-us/library/aa388176(VS.85).aspx
|
||||
try
|
||||
{
|
||||
$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);
|
||||
}
|
||||
}
|
||||
catch (Exception $ex)
|
||||
{
|
||||
// echo 'Exception: ' . $ex->getMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($sRandomBits == null)
|
||||
{
|
||||
// No "strong" random generator available, use PHP's built-in mechanism
|
||||
//echo "Random bits generated from mt_rand<br/>\n";
|
||||
mt_srand(crc32(microtime()));
|
||||
$sRandomBits = '';
|
||||
for($i = 0; $i < 4; $i++)
|
||||
{
|
||||
$sRandomBits .= sprintf('%04x', mt_rand(0, 65535));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
return $sRandomBits;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface for encryption engines
|
||||
*/
|
||||
interface CryptEngine
|
||||
{
|
||||
public static function GetNewDefaultParams();
|
||||
function Encrypt($key, $sString);
|
||||
function Decrypt($key, $encrypted_data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple Engine doesn't need any PHP extension.
|
||||
* Every encryption of the same string with the same key
|
||||
* will return the same encrypted string
|
||||
*/
|
||||
class SimpleCryptSimpleEngine implements CryptEngine
|
||||
{
|
||||
public static function GetNewDefaultParams()
|
||||
{
|
||||
return array( 'lib' => 'Simple', 'key' => null);
|
||||
}
|
||||
|
||||
public function Encrypt($key, $sString)
|
||||
{
|
||||
$result = '';
|
||||
for($i=1; $i<=strlen($sString); $i++)
|
||||
{
|
||||
$char = substr($sString, $i-1, 1);
|
||||
$keychar = substr($key, ($i % strlen($key))-1, 1);
|
||||
$char = chr(ord($char)+ord($keychar));
|
||||
$result.=$char;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function Decrypt($key, $encrypted_data)
|
||||
{
|
||||
$result = '';
|
||||
for($i=1; $i<=strlen($encrypted_data); $i++)
|
||||
{
|
||||
$char = substr($encrypted_data, $i-1, 1);
|
||||
$keychar = substr($key, ($i % strlen($key))-1, 1);
|
||||
$char = chr(ord($char)-ord($keychar));
|
||||
$result.=$char;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* McryptEngine requires Mcrypt extension
|
||||
* Every encryption of the same string with the same key
|
||||
* will return a different encrypted string.
|
||||
*/
|
||||
class SimpleCryptMcryptEngine implements CryptEngine
|
||||
{
|
||||
var $alg = MCRYPT_BLOWFISH;
|
||||
var $td = null;
|
||||
|
||||
public static function GetNewDefaultParams()
|
||||
{
|
||||
return array('lib' => 'Mcrypt', 'key' => null);
|
||||
}
|
||||
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$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_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))
|
||||
{
|
||||
$sString = str_repeat("\0", 8);
|
||||
}
|
||||
$encrypted_data = mcrypt_generic($this->td, $sString);
|
||||
mcrypt_generic_deinit($this->td);
|
||||
return $iv.$encrypted_data;
|
||||
}
|
||||
|
||||
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));
|
||||
$r = mcrypt_generic_init($this->td, $key, $iv);
|
||||
if (($r < 0) || ($r === false))
|
||||
{
|
||||
$decrypted_data = Dict::S("Core:AttributeEncryptFailedToDecrypt");
|
||||
}
|
||||
else
|
||||
{
|
||||
$decrypted_data = rtrim(mdecrypt_generic($this->td, $string), "\0");
|
||||
mcrypt_generic_deinit($this->td);
|
||||
}
|
||||
return $decrypted_data;
|
||||
}
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
mcrypt_module_close($this->td);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* SodiumEngine requires Sodium extension
|
||||
* Every encryption of the same string with the same key
|
||||
* will return a different encrypted string.
|
||||
* The key has to be SODIUM_CRYPTO_SECRETBOX_KEYBYTES bytes long.
|
||||
*/
|
||||
class SimpleCryptSodiumEngine implements CryptEngine
|
||||
{
|
||||
public static function GetNewDefaultParams()
|
||||
{
|
||||
return array('lib' => 'Sodium', 'key' => bin2hex(sodium_crypto_secretbox_keygen()));
|
||||
}
|
||||
|
||||
public function Encrypt($key, $sString)
|
||||
{
|
||||
$key = hex2bin($key);
|
||||
$nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
|
||||
$encrypted_string = sodium_crypto_secretbox($sString, $nonce, $key);
|
||||
sodium_memzero($sString);
|
||||
sodium_memzero($key);
|
||||
return base64_encode($nonce.$encrypted_string);
|
||||
}
|
||||
|
||||
public function Decrypt($key, $encrypted_data)
|
||||
{
|
||||
$key = hex2bin($key);
|
||||
$encrypted_data = base64_decode($encrypted_data);
|
||||
$nonce = mb_substr($encrypted_data, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, '8bit');
|
||||
$encrypted_data = mb_substr($encrypted_data, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, null, '8bit');
|
||||
$plaintext = sodium_crypto_secretbox_open($encrypted_data, $nonce, $key);
|
||||
if ($plaintext === false)
|
||||
{
|
||||
$plaintext = Dict::S("Core:AttributeEncryptFailedToDecrypt");
|
||||
}
|
||||
sodium_memzero($encrypted_data);
|
||||
sodium_memzero($key);
|
||||
return $plaintext;
|
||||
}
|
||||
|
||||
}
|
||||
class SimpleCryptOpenSSLEngine implements CryptEngine
|
||||
{
|
||||
public static function GetNewDefaultParams()
|
||||
{
|
||||
return array('lib' => 'OpenSSL', 'key' => bin2hex(openssl_random_pseudo_bytes(32)));
|
||||
}
|
||||
|
||||
public function Encrypt($key, $sString)
|
||||
{
|
||||
$key = hex2bin($key);
|
||||
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length("AES-256-CBC"));
|
||||
$encrypted_string = openssl_encrypt($sString, "AES-256-CBC", $key, 0 , $iv);
|
||||
return $iv.$encrypted_string;
|
||||
}
|
||||
|
||||
public function Decrypt($key, $encrypted_data)
|
||||
{
|
||||
$key = hex2bin($key);
|
||||
$iv = mb_substr($encrypted_data, 0, openssl_cipher_iv_length("AES-256-CBC"), '8bit');
|
||||
$encrypted_data = mb_substr($encrypted_data, openssl_cipher_iv_length("AES-256-CBC"), null, '8bit');
|
||||
$plaintext = openssl_decrypt($encrypted_data,"AES-256-CBC", $key, 0 , $iv);
|
||||
if ($plaintext === false)
|
||||
{
|
||||
$plaintext = Dict::S("Core:AttributeEncryptFailedToDecrypt");
|
||||
}
|
||||
return trim($plaintext);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class SimpleCryptOpenSSLMcryptCompatibilityEngine implements CryptEngine
|
||||
{
|
||||
public static function GetNewDefaultParams()
|
||||
{
|
||||
return array('lib' => 'OpenSSLMcryptCompatibility', 'key' => null);
|
||||
}
|
||||
//fix for php < 7.1.8 (keys are Zero padded instead of cycle padded)
|
||||
static private function MakeOpenSSLBlowfishKey($key)
|
||||
{
|
||||
if("$key" === '')
|
||||
{
|
||||
return $key;
|
||||
}
|
||||
$len = (16+2)*4;
|
||||
while(strlen($key) < $len)
|
||||
{
|
||||
$key .= $key;
|
||||
}
|
||||
$key = substr($key, 0, $len);
|
||||
return $key;
|
||||
}
|
||||
public function Encrypt($key, $sString)
|
||||
{
|
||||
$key = SimpleCryptOpenSSLMcryptCompatibilityEngine::MakeOpenSSLBlowfishKey($key);
|
||||
$blockSize = 8;
|
||||
$len = strlen($sString);
|
||||
$paddingLen = intval (($len + $blockSize -1) / $blockSize) * $blockSize - $len;
|
||||
$padding = str_repeat("\0", $paddingLen);
|
||||
$sData = $sString . $padding;
|
||||
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length("BF-CBC"));
|
||||
$encrypted_string = openssl_encrypt($sData, "BF-CBC", $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);
|
||||
return $iv.$encrypted_string;
|
||||
}
|
||||
|
||||
public function Decrypt($key, $encrypted_data)
|
||||
{
|
||||
$key = SimpleCryptOpenSSLMcryptCompatibilityEngine::MakeOpenSSLBlowfishKey($key);
|
||||
$iv = mb_substr($encrypted_data, 0, openssl_cipher_iv_length("BF-CBC"), '8bit');
|
||||
$encrypted_data = mb_substr($encrypted_data, openssl_cipher_iv_length("BF-CBC"), null, '8bit');
|
||||
$plaintext = openssl_decrypt($encrypted_data,"BF-CBC", $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);
|
||||
if ($plaintext === false)
|
||||
{
|
||||
$plaintext = Dict::S("Core:AttributeEncryptFailedToDecrypt");
|
||||
}
|
||||
return trim($plaintext);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,894 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2013-2024 Combodo SAS
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
use Combodo\iTop\Application\UI\Base\Component\Alert\AlertUIBlockFactory;
|
||||
|
||||
/**
|
||||
* A user defined trigger, to customize the application
|
||||
* A trigger will activate an action
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
abstract class Trigger extends cmdbAbstractObject
|
||||
{
|
||||
/**
|
||||
* @throws \CoreException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "grant_by_profile,core/cmdb",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "description",
|
||||
"complementary_name_attcode" => ['finalclass', 'complement'],
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => ['description'],
|
||||
"db_table" => "priv_trigger",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "realclass",
|
||||
'style' => new ormStyle(null, null, null, null, null, '../images/icons/icons8-conflict.svg'),
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values" => null, "sql" => "description", "default_value" => null, "is_null_allowed" => false, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect("action_list",
|
||||
array("linked_class" => "lnkTriggerAction", "ext_key_to_me" => "trigger_id", "ext_key_to_remote" => "action_id", "allowed_values" => null, "count_min" => 1, "count_max" => 0, "depends_on" => array())));
|
||||
$aTags = ContextTag::GetTags();
|
||||
MetaModel::Init_AddAttribute(new AttributeEnumSet("context", array("allowed_values" => null, "possible_values" => new ValueSetEnumPadded($aTags, true), "sql" => "context", "depends_on" => array(), "is_null_allowed" => true, "max_items" => 12)));
|
||||
// "complement" is a computed field, fed by Trigger sub-classes, in general in ComputeValues method, for eg. the TriggerOnObject fed it with target_class info
|
||||
MetaModel::Init_AddAttribute(new AttributeString("complement", array("allowed_values" => null, "sql" => "complement", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("subscription_policy", array("allowed_values" => new ValueSetEnum(Combodo\iTop\Core\Trigger\Enum\SubscriptionPolicy::cases()), "sql" => "subscription_policy", "default_value" => \Combodo\iTop\Core\Trigger\Enum\SubscriptionPolicy::AllowNoChannel->value, "is_null_allowed" => false, "depends_on" => array())));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('finalclass', 'description', 'context', 'subscription_policy', 'action_list', 'complement')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('finalclass', 'complement')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
|
||||
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the trigger can be used in the current context
|
||||
*
|
||||
* @return bool true if context OK
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public function IsContextValid()
|
||||
{
|
||||
// Check the context
|
||||
$oContext = $this->Get('context');
|
||||
$bChecked = false;
|
||||
$bValid = false;
|
||||
foreach ($oContext->GetValues() as $sValue)
|
||||
{
|
||||
$bChecked = true;
|
||||
if (ContextTag::Check($sValue))
|
||||
{
|
||||
$bValid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($bChecked && !$bValid)
|
||||
{
|
||||
// Trigger does not match the current context
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $aContextArgs
|
||||
*
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public function DoActivate($aContextArgs)
|
||||
{
|
||||
// Check the context
|
||||
if (!$this->IsContextValid())
|
||||
{
|
||||
// Trigger does not match the current context
|
||||
$sClass = get_class($this);
|
||||
$sName = $this->Get('friendlyname');
|
||||
IssueLog::Debug("Context NOT valid for : {$sClass} '$sName'");
|
||||
return;
|
||||
}
|
||||
|
||||
$aContextArgs['trigger->object()'] = $this;
|
||||
|
||||
// Find the related actions
|
||||
$oLinkedActions = $this->Get('action_list');
|
||||
|
||||
// Order actions as expected
|
||||
$aActionListOrdered = [];
|
||||
while ($oLink = $oLinkedActions->Fetch()) {
|
||||
$aActionListOrdered[(int) $oLink->Get('order')][] = $oLink;
|
||||
}
|
||||
ksort($aActionListOrdered);
|
||||
|
||||
// Execute actions
|
||||
foreach ($aActionListOrdered as $aActionSubList) {
|
||||
foreach ($aActionSubList as $oLink) /** @var \DBObject $oLink */ {
|
||||
/** @var \DBObject $oLink */
|
||||
$iActionId = $oLink->Get('action_id');
|
||||
/** @var \Action $oAction */
|
||||
$oAction = MetaModel::GetObject('Action', $iActionId);
|
||||
if ($oAction->IsActive()) {
|
||||
$oKPI = new ExecutionKPI();
|
||||
$aContextArgs['action->object()'] = $oAction;
|
||||
$oAction->DoExecute($this, $aContextArgs);
|
||||
$oKPI->ComputeStatsForExtension($oAction, 'DoExecute');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the given object is in the scope of this trigger
|
||||
* and can potentially be the subject of notifications
|
||||
*
|
||||
* @param DBObject $oObject The object to check
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function IsInScope(DBObject $oObject)
|
||||
{
|
||||
// By default the answer is no
|
||||
// Overload this function in your own derived class for a different behavior
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class TriggerOnObject
|
||||
*/
|
||||
abstract class TriggerOnObject extends Trigger
|
||||
{
|
||||
/**
|
||||
* @throws \CoreException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "grant_by_profile,core/cmdb",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "description",
|
||||
"complementary_name_attcode" => ['finalclass', 'complement'],
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => ['description'],
|
||||
"db_table" => "priv_trigger_onobject",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeClass("target_class",
|
||||
array("class_category" => "bizmodel", "more_values" => "User,UserExternal,UserInternal,UserLDAP,UserLocal", "sql" => "target_class", "default_value" => null, "is_null_allowed" => false, "depends_on" => array(), "class_exclusion_list" => "Attachment")));
|
||||
MetaModel::Init_AddAttribute(new AttributeOQL("filter", array("allowed_values" => null, "sql" => "filter", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'subscription_policy', 'action_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('finalclass', 'target_class', 'description')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('default_search', array('description', 'target_class')); // Default criteria of the search banner
|
||||
// MetaModel::Init_SetZListItems('standard_search', array('name', 'target_class', 'description')); // Criteria of the search form
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public function DoCheckToWrite()
|
||||
{
|
||||
parent::DoCheckToWrite();
|
||||
|
||||
$sFilter = trim($this->Get('filter') ?? '');
|
||||
if (strlen($sFilter) > 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
$oSearch = DBObjectSearch::FromOQL($sFilter);
|
||||
|
||||
if (!MetaModel::IsParentClass($this->Get('target_class'), $oSearch->GetClass()))
|
||||
{
|
||||
$this->m_aCheckIssues[] = Dict::Format('TriggerOnObject:WrongFilterClass', $this->Get('target_class'));
|
||||
}
|
||||
} catch (OqlException $e)
|
||||
{
|
||||
$this->m_aCheckIssues[] = Dict::Format('TriggerOnObject:WrongFilterQuery', $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public function ComputeValues()
|
||||
{
|
||||
parent::ComputeValues();
|
||||
|
||||
// Complementary name of a Trigger is manually built
|
||||
// - the Trigger finalclass code not translated
|
||||
// - an hardcoded text in english
|
||||
// - the target class code not translated for TriggerOnObject subclasses
|
||||
$this->Set('complement', 'class restriction: '.$this->Get('target_class'));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check whether the given object is in the scope of this trigger
|
||||
* and can potentially be the subject of notifications
|
||||
*
|
||||
* @param DBObject $oObject The object to check
|
||||
*
|
||||
* @return bool
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public function IsInScope(DBObject $oObject)
|
||||
{
|
||||
$sRootClass = $this->Get('target_class');
|
||||
|
||||
return ($oObject instanceof $sRootClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $aContextArgs
|
||||
*
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public function DoActivate($aContextArgs)
|
||||
{
|
||||
$bGo = true;
|
||||
if (isset($aContextArgs['this->object()']))
|
||||
{
|
||||
/** @var \DBObject $oObject */
|
||||
$oObject = $aContextArgs['this->object()'];
|
||||
$bGo = $this->IsTargetObject($oObject->GetKey(), $oObject->ListPreviousValuesForUpdatedAttributes());
|
||||
}
|
||||
if ($bGo)
|
||||
{
|
||||
parent::DoActivate($aContextArgs);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* if the target class is Attachment, then the trigger is read-only
|
||||
* @param $sAttCode
|
||||
* @param $aReasons
|
||||
* @param $sTargetState
|
||||
* @return int
|
||||
* @throws ArchivedObjectException
|
||||
* @throws CoreException
|
||||
*/
|
||||
public function GetAttributeFlags($sAttCode, &$aReasons = array(), $sTargetState='')
|
||||
{
|
||||
// Force the computed field to be read-only, preventing it to be written
|
||||
if ($this->Get('target_class') == 'Attachment' ) {
|
||||
return OPT_ATT_READONLY;
|
||||
}
|
||||
return parent::GetAttributeFlags($sAttCode, $aReasons, $sTargetState);
|
||||
}
|
||||
|
||||
|
||||
public function DisplayBareHeader(WebPage $oPage, $bEditMode = false)
|
||||
{
|
||||
$aHeaderBlocks = parent::DisplayBareHeader($oPage, $bEditMode);
|
||||
if ($this->Get('target_class') == 'Attachment' ) {
|
||||
$oPage->AddUiBlock(AlertUIBlockFactory::MakeForWarning('', Dict::S('Class:TriggerOnObject:TriggerClassAttachment/ReadOnlyMessage')));
|
||||
$oPage->add_ready_script("$('#UIMenuModify').hide();");
|
||||
}
|
||||
|
||||
return $aHeaderBlocks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Activate trigger based on attribute list given instead of changed attributes
|
||||
*
|
||||
* @param array $aContextArgs
|
||||
* @param array|null $aAttributes if null default to changed attributes
|
||||
*
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
* @throws \OQLException
|
||||
* @since 3.1.1 3.2.0 N°6228
|
||||
*/
|
||||
public function DoActivateForSpecificAttributes(array $aContextArgs, ?array $aAttributes)
|
||||
{
|
||||
if (isset($aContextArgs['this->object()']))
|
||||
{
|
||||
/** @var \DBObject $oObject */
|
||||
$oObject = $aContextArgs['this->object()'];
|
||||
if (is_null($aAttributes)) {
|
||||
$aChanges = $oObject->ListPreviousValuesForUpdatedAttributes();
|
||||
} else {
|
||||
$aChanges = array_fill_keys($aAttributes, true);
|
||||
}
|
||||
if (false === $this->IsTargetObject($oObject->GetKey(), $aChanges)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
parent::DoActivate($aContextArgs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $iObjectId
|
||||
* @param array $aChanges
|
||||
*
|
||||
* @return bool True if the object of ID $iObjectId is within the scope of the OQL defined by the "filter" attribute
|
||||
*
|
||||
* @throws \CoreException
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public function IsTargetObject($iObjectId, $aChanges = array())
|
||||
{
|
||||
$sFilter = trim($this->Get('filter') ?? '');
|
||||
if (strlen($sFilter) > 0) {
|
||||
$oSearch = DBObjectSearch::FromOQL($sFilter);
|
||||
$oSearch->AddCondition('id', $iObjectId, '=');
|
||||
$oSearch->AllowAllData();
|
||||
$oSet = new DBObjectSet($oSearch);
|
||||
$bRet = ($oSet->Count() > 0);
|
||||
} else {
|
||||
$bRet = true;
|
||||
}
|
||||
|
||||
return $bRet;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Exception $oException
|
||||
* @param \DBObject $oObject
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @uses \IssueLog::Error()
|
||||
*
|
||||
* @since 2.7.9 3.0.3 3.1.0 N°5893
|
||||
*/
|
||||
public function LogException($oException, $oObject)
|
||||
{
|
||||
$sObjectKey = $oObject->GetKey(); // if object wasn't persisted yet, then we'll have a negative value
|
||||
|
||||
$aContext = [
|
||||
'exception.class' => get_class($oException),
|
||||
'exception.message' => $oException->getMessage(),
|
||||
'trigger.class' => get_class($this),
|
||||
'trigger.id' => $this->GetKey(),
|
||||
'trigger.friendlyname' => $this->GetRawName(),
|
||||
'object.class' => get_class($oObject),
|
||||
'object.id' => $sObjectKey,
|
||||
'object.friendlyname' => $oObject->GetRawName(),
|
||||
'current_user' => UserRights::GetUser(),
|
||||
'exception.stack' => $oException->getTraceAsString(),
|
||||
];
|
||||
|
||||
IssueLog::Error('A trigger did throw an exception', null, $aContext);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* To trigger notifications when a ticket is updated from the portal
|
||||
*/
|
||||
class TriggerOnPortalUpdate extends TriggerOnObject
|
||||
{
|
||||
/**
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "grant_by_profile,core/cmdb,application",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "description",
|
||||
"complementary_name_attcode" => ['finalclass', 'complement'],
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => ['description'],
|
||||
"db_table" => "priv_trigger_onportalupdate",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'subscription_policy', 'action_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('finalclass', 'target_class', 'description')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class TriggerOnStateChange
|
||||
*/
|
||||
abstract class TriggerOnStateChange extends TriggerOnObject
|
||||
{
|
||||
/**
|
||||
* @throws \CoreException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "grant_by_profile,core/cmdb",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "description",
|
||||
"complementary_name_attcode" => ['finalclass', 'complement'],
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => ['description'],
|
||||
"db_table" => "priv_trigger_onstatechange",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeClassState("state", array("class_field" => 'target_class', "allowed_values" => null, "sql" => "state", "default_value" => null, "is_null_allowed" => false, "depends_on" => array('target_class'))));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'state', 'subscription_policy', 'action_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('finalclass', 'target_class', 'state')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class', 'state')); // Criteria of the std search form
|
||||
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class TriggerOnStateEnter
|
||||
*/
|
||||
class TriggerOnStateEnter extends TriggerOnStateChange
|
||||
{
|
||||
/**
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "grant_by_profile,core/cmdb,application",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "description",
|
||||
"complementary_name_attcode" => ['finalclass', 'complement'],
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => ['description'],
|
||||
"db_table" => "priv_trigger_onstateenter",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'state', 'subscription_policy', 'action_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('target_class', 'state')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class', 'state')); // Criteria of the std search form
|
||||
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class TriggerOnStateLeave
|
||||
*/
|
||||
class TriggerOnStateLeave extends TriggerOnStateChange
|
||||
{
|
||||
/**
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "grant_by_profile,core/cmdb,application",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "description",
|
||||
"complementary_name_attcode" => ['finalclass', 'complement'],
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => ['description'],
|
||||
"db_table" => "priv_trigger_onstateleave",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'state', 'subscription_policy', 'action_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('target_class', 'state')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class', 'state')); // Criteria of the std search form
|
||||
// MetaModel::Init_SetZListItems('advanced_search', array('')); // Criteria of the advanced search form
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class TriggerOnObjectCreate
|
||||
*/
|
||||
class TriggerOnObjectCreate extends TriggerOnObject
|
||||
{
|
||||
/**
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "grant_by_profile,core/cmdb,application",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "description",
|
||||
"complementary_name_attcode" => ['finalclass', 'complement'],
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => ['description'],
|
||||
"db_table" => "priv_trigger_onobjcreate",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'subscription_policy', 'action_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('finalclass', 'target_class')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class')); // Criteria of the std search form
|
||||
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Class TriggerOnObjectCreate
|
||||
*/
|
||||
class TriggerOnObjectDelete extends TriggerOnObject
|
||||
{
|
||||
/**
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "grant_by_profile,core/cmdb,application",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "description",
|
||||
"complementary_name_attcode" => ['finalclass', 'complement'],
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => ['description'],
|
||||
"db_table" => "priv_trigger_onobjdelete",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'subscription_policy', 'action_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('finalclass', 'target_class')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class')); // Criteria of the std search form
|
||||
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class TriggerOnObjectCreate
|
||||
*/
|
||||
class TriggerOnObjectUpdate extends TriggerOnObject
|
||||
{
|
||||
/**
|
||||
* @throws \CoreException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "grant_by_profile,core/cmdb,application",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "description",
|
||||
"complementary_name_attcode" => ['finalclass', 'complement'],
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => ['description'],
|
||||
"db_table" => "priv_trigger_onobjupdate",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeClassAttCodeSet('target_attcodes', array("allowed_values" => null, "class_field" => "target_class", "sql" => "target_attcodes", "default_value" => null, "is_null_allowed" => true, "max_items" => 20, "min_items" => 0, "attribute_definition_exclusion_list" => "AttributeDashboard,AttributeExternalField,AttributeFinalClass,AttributeFriendlyName,AttributeObsolescenceDate,AttributeObsolescenceFlag,AttributeSubItem", "attribute_definition_list" => null, "depends_on" => array('target_class'))));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'target_attcodes', 'subscription_policy', 'action_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('finalclass', 'target_class')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class')); // Criteria of the std search form
|
||||
}
|
||||
|
||||
public function IsTargetObject($iObjectId, $aChanges = array())
|
||||
{
|
||||
if (!parent::IsTargetObject($iObjectId, $aChanges))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check the attribute
|
||||
$oAttCodeSet = $this->Get('target_attcodes');
|
||||
$aAttCodes = $oAttCodeSet->GetValues();
|
||||
if (empty($aAttCodes))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
foreach($aAttCodes as $sAttCode)
|
||||
{
|
||||
if (array_key_exists($sAttCode, $aChanges))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function ComputeValues()
|
||||
{
|
||||
parent::ComputeValues();
|
||||
|
||||
// Remove unwanted attribute codes
|
||||
$aChanges = $this->ListChanges();
|
||||
if (isset($aChanges['target_attcodes']))
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef(get_class($this), 'target_attcodes');
|
||||
$aArgs = array('this' => $this);
|
||||
$aAllowedValues = $oAttDef->GetAllowedValues($aArgs);
|
||||
|
||||
/** @var \ormSet $oValue */
|
||||
$oValue = $this->Get('target_attcodes');
|
||||
$aValues = $oValue->GetValues();
|
||||
$bChanged = false;
|
||||
foreach($aValues as $key => $sValue)
|
||||
{
|
||||
if (!isset($aAllowedValues[$sValue]))
|
||||
{
|
||||
unset($aValues[$key]);
|
||||
$bChanged = true;
|
||||
}
|
||||
}
|
||||
if ($bChanged)
|
||||
{
|
||||
$oValue->SetValues($aValues);
|
||||
$this->Set('target_attcodes', $oValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Class TriggerOnObjectMention
|
||||
*
|
||||
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
|
||||
* @since 3.0.0
|
||||
*/
|
||||
class TriggerOnObjectMention extends TriggerOnObject
|
||||
{
|
||||
/**
|
||||
* @throws \CoreException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "grant_by_profile,core/cmdb,application",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "description",
|
||||
"complementary_name_attcode" => ['finalclass', 'complement'],
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => ['description'],
|
||||
"db_table" => "priv_trigger_onobjmention",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeOQL("mentioned_filter", array("allowed_values" => null, "sql" => "mentioned_filter", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'mentioned_filter', 'subscription_policy', 'action_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('finalclass', 'target_class')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class')); // Criteria of the std search form
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \DBObject $oObject
|
||||
*
|
||||
* @return bool True if $oObject is within the scope of the OQL defined by the "mentioned_filter" attribute OR if no mentioned_filter defined. Otherwise, returns false.
|
||||
*
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public function IsMentionedObjectInScope(DBObject $oObject)
|
||||
{
|
||||
$sFilter = trim($this->Get('mentioned_filter'));
|
||||
if (strlen($sFilter) > 0)
|
||||
{
|
||||
$oSearch = DBObjectSearch::FromOQL($sFilter);
|
||||
$sSearchClass = $oSearch->GetClass();
|
||||
|
||||
// If filter not on current object class (or descendants), consider it as not in scope
|
||||
if (is_a($oObject, $sSearchClass, true) === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$oSearch->AddCondition('id', $oObject->GetKey(), '=');
|
||||
if (MetaModel::IsAbstract($oSearch->GetClass())) {
|
||||
$oSearch->AddCondition('finalclass', get_class($oObject), '=');
|
||||
}
|
||||
|
||||
$aParams = $oObject->ToArgs('this');
|
||||
$oSet = new DBObjectSet($oSearch, [], $aParams);
|
||||
$bRet = $oSet->CountExceeds(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
$bRet = true;
|
||||
}
|
||||
|
||||
return $bRet;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class TriggerOnAttributeBlobDownload
|
||||
*
|
||||
* @since 3.1.0
|
||||
*/
|
||||
class TriggerOnAttributeBlobDownload extends TriggerOnObject
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @throws \CoreException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "grant_by_profile,core/cmdb,application",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "description",
|
||||
"complementary_name_attcode" => ['finalclass', 'complement'],
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => ['description'],
|
||||
"db_table" => "priv_trigger_onattblobdownload",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class lnkTriggerAction
|
||||
*/
|
||||
class lnkTriggerAction extends cmdbAbstractObject
|
||||
{
|
||||
/**
|
||||
* @throws \CoreException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "grant_by_profile,core/cmdb,application",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array('action_id', 'trigger_id'),
|
||||
"db_table" => "priv_link_action_trigger",
|
||||
"db_key_field" => "link_id",
|
||||
"db_finalclass_field" => "",
|
||||
"is_link" => true,
|
||||
'uniqueness_rules' => array(
|
||||
'no_duplicate' => array(
|
||||
'attributes' => array(
|
||||
0 => 'action_id',
|
||||
1 => 'trigger_id',
|
||||
),
|
||||
'filter' => '',
|
||||
'disabled' => false,
|
||||
'is_blocking' => true,
|
||||
),
|
||||
),
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("action_id", array("targetclass" => "Action", "jointype" => '', "allowed_values" => null, "sql" => "action_id", "is_null_allowed" => false, "on_target_delete" => DEL_AUTO, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalField("action_name", array("allowed_values" => null, "extkey_attcode" => 'action_id', "target_attcode" => "name")));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("trigger_id", array("targetclass" => "Trigger", "jointype" => '', "allowed_values" => null, "sql" => "trigger_id", "is_null_allowed" => false, "on_target_delete" => DEL_AUTO, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalField("trigger_name", array("allowed_values" => null, "extkey_attcode" => 'trigger_id', "target_attcode" => "description")));
|
||||
MetaModel::Init_AddAttribute(new AttributeInteger("order", array("allowed_values" => null, "sql" => "order", "default_value" => 0, "is_null_allowed" => true, "depends_on" => array())));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('action_id', 'trigger_id', 'order')); // Attributes to be displayed for a list
|
||||
MetaModel::Init_SetZListItems('list', array('action_id', 'trigger_id', 'order')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', array('action_id', 'trigger_id', 'order')); // Criteria of the std search form
|
||||
MetaModel::Init_SetZListItems('advanced_search', array('action_id', 'trigger_id', 'order')); // Criteria of the advanced search form
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class TriggerOnThresholdReached
|
||||
*/
|
||||
class TriggerOnThresholdReached extends TriggerOnObject
|
||||
{
|
||||
/**
|
||||
* @throws \CoreException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "grant_by_profile,core/cmdb,application",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "description",
|
||||
"complementary_name_attcode" => ['finalclass', 'complement'],
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => ['description'],
|
||||
"db_table" => "priv_trigger_threshold",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeClassAttCodeSet('stop_watch_code', array("allowed_values" => null, "class_field" => "target_class", "sql" => "stop_watch_code", "default_value" => null, "is_null_allowed" => false, "max_items" => 1, "min_items" => 1, "attribute_definition_exclusion_list" => null, "attribute_definition_list" => "AttributeStopWatch", "include_child_classes_attributes" => true, "depends_on" => array('target_class'))));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("threshold_index", array("allowed_values" => null, "sql" => "threshold_index", "default_value" => null, "is_null_allowed" => false, "depends_on" => array())));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'stop_watch_code', 'threshold_index', 'filter', 'subscription_policy', 'action_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('target_class', 'threshold_index', 'threshold_index')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class')); // Criteria of the std search form
|
||||
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
|
||||
}
|
||||
}
|
||||
@@ -1,663 +0,0 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2024 Combodo SAS
|
||||
//
|
||||
// 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/>
|
||||
|
||||
|
||||
/**
|
||||
* Value set definitions (from a fixed list or from a query, etc.)
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
use Combodo\iTop\Core\MetaModel\FriendlyNameType;
|
||||
|
||||
require_once('MyHelpers.class.inc.php');
|
||||
|
||||
/**
|
||||
* ValueSetDefinition
|
||||
* value sets API and implementations
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
abstract class ValueSetDefinition
|
||||
{
|
||||
protected $m_bIsLoaded = false;
|
||||
protected $m_aValues = array();
|
||||
|
||||
|
||||
// Displayable description that could be computed out of the std usage context
|
||||
public function GetValuesDescription()
|
||||
{
|
||||
$aValues = $this->GetValues(array(), '');
|
||||
$aDisplayedValues = array();
|
||||
foreach($aValues as $key => $value)
|
||||
{
|
||||
$aDisplayedValues[] = "$key => $value";
|
||||
}
|
||||
$sAllowedValues = implode(', ', $aDisplayedValues);
|
||||
return $sAllowedValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $aArgs
|
||||
* @param string $sContains
|
||||
* @param string $sOperation for the values {@see static::LoadValues()}
|
||||
*
|
||||
* @return array hash array of keys => values
|
||||
*/
|
||||
public function GetValues($aArgs, $sContains = '', $sOperation = 'contains')
|
||||
{
|
||||
if (!$this->m_bIsLoaded)
|
||||
{
|
||||
$this->LoadValues($aArgs);
|
||||
$this->m_bIsLoaded = true;
|
||||
}
|
||||
if (strlen($sContains) == 0)
|
||||
{
|
||||
// No filtering
|
||||
$aRet = $this->m_aValues;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Filter on results containing the needle <sContain>
|
||||
$aRet = array();
|
||||
foreach ($this->m_aValues as $sKey=>$sValue)
|
||||
{
|
||||
if (stripos($sValue, $sContains) !== false)
|
||||
{
|
||||
$aRet[$sKey] = $sValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->SortValues($aRet);
|
||||
return $aRet;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $aValues Values to sort in the form keys => values
|
||||
*
|
||||
* @return void
|
||||
* @since 3.1.0 N°1646 Create method
|
||||
*/
|
||||
public function SortValues(array &$aValues): void
|
||||
{
|
||||
// Sort alphabetically on values
|
||||
natcasesort($aValues);
|
||||
}
|
||||
|
||||
abstract protected function LoadValues($aArgs);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set of existing values for an attribute, given a search filter
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
class ValueSetObjects extends ValueSetDefinition
|
||||
{
|
||||
protected $m_sContains;
|
||||
protected $m_sOperation;
|
||||
protected $m_sFilterExpr; // in OQL
|
||||
protected $m_sValueAttCode;
|
||||
protected $m_aOrderBy;
|
||||
protected $m_oExtraCondition;
|
||||
private $m_bAllowAllData;
|
||||
private $m_aModifierProperties;
|
||||
private $m_bSort;
|
||||
private $m_iLimit;
|
||||
|
||||
|
||||
/**
|
||||
* @param hash $aOrderBy Array of '[<classalias>.]attcode' => bAscending
|
||||
*/
|
||||
public function __construct($sFilterExp, $sValueAttCode = '', $aOrderBy = array(), $bAllowAllData = false, $aModifierProperties = array())
|
||||
{
|
||||
$this->m_sContains = '';
|
||||
$this->m_sOperation = '';
|
||||
$this->m_sFilterExpr = $sFilterExp;
|
||||
$this->m_sValueAttCode = $sValueAttCode;
|
||||
$this->m_aOrderBy = $aOrderBy;
|
||||
$this->m_bAllowAllData = $bAllowAllData;
|
||||
$this->m_aModifierProperties = $aModifierProperties;
|
||||
$this->m_oExtraCondition = null;
|
||||
$this->m_bSort = true;
|
||||
$this->m_iLimit = 0;
|
||||
}
|
||||
|
||||
public function SetModifierProperty($sPluginClass, $sProperty, $value)
|
||||
{
|
||||
$this->m_aModifierProperties[$sPluginClass][$sProperty] = $value;
|
||||
$this->m_bIsLoaded = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use SetCondition instead
|
||||
*
|
||||
* @param \DBSearch $oFilter
|
||||
*/
|
||||
public function AddCondition(DBSearch $oFilter)
|
||||
{
|
||||
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('use SetCondition instead');
|
||||
$this->SetCondition($oFilter);
|
||||
}
|
||||
|
||||
public function SetCondition(DBSearch $oFilter)
|
||||
{
|
||||
$this->m_oExtraCondition = $oFilter;
|
||||
$this->m_bIsLoaded = false;
|
||||
}
|
||||
public function SetOrderBy(array $aOrderBy)
|
||||
{
|
||||
$this->m_aOrderBy = $aOrderBy;
|
||||
}
|
||||
public function ToObjectSet($aArgs = array(), $sContains = '', $iAdditionalValue = null)
|
||||
{
|
||||
if ($this->m_bAllowAllData)
|
||||
{
|
||||
$oFilter = DBObjectSearch::FromOQL_AllData($this->m_sFilterExpr);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oFilter = DBObjectSearch::FromOQL($this->m_sFilterExpr);
|
||||
}
|
||||
if (!is_null($this->m_oExtraCondition))
|
||||
{
|
||||
$oFilter = $oFilter->Intersect($this->m_oExtraCondition);
|
||||
}
|
||||
foreach($this->m_aModifierProperties as $sPluginClass => $aProperties)
|
||||
{
|
||||
foreach ($aProperties as $sProperty => $value)
|
||||
{
|
||||
$oFilter->SetModifierProperty($sPluginClass, $sProperty, $value);
|
||||
}
|
||||
}
|
||||
if ($iAdditionalValue > 0)
|
||||
{
|
||||
$oSearchAdditionalValue = new DBObjectSearch($oFilter->GetClass());
|
||||
$oSearchAdditionalValue->AddConditionExpression( new BinaryExpression(
|
||||
new FieldExpression('id', $oSearchAdditionalValue->GetClassAlias()),
|
||||
'=',
|
||||
new VariableExpression('current_extkey_id'))
|
||||
);
|
||||
$oSearchAdditionalValue->AllowAllData();
|
||||
$oSearchAdditionalValue->SetArchiveMode(true);
|
||||
$oSearchAdditionalValue->SetInternalParams( array('current_extkey_id' => $iAdditionalValue) );
|
||||
|
||||
$oFilter = new DBUnionSearch(array($oFilter, $oSearchAdditionalValue));
|
||||
}
|
||||
|
||||
return new DBObjectSet($oFilter, $this->m_aOrderBy, $aArgs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @throws CoreException
|
||||
* @throws OQLException
|
||||
*/
|
||||
public function GetValues($aArgs, $sContains = '', $sOperation = 'contains')
|
||||
{
|
||||
if (!$this->m_bIsLoaded || ($sContains != $this->m_sContains) || ($sOperation != $this->m_sOperation))
|
||||
{
|
||||
$this->LoadValues($aArgs, $sContains, $sOperation);
|
||||
$this->m_bIsLoaded = true;
|
||||
}
|
||||
// The results are already filtered and sorted (on friendly name)
|
||||
$aRet = $this->m_aValues;
|
||||
return $aRet;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $aArgs
|
||||
* @param string $sContains
|
||||
* @param string $sOperation 'contains' or 'equals_start_with'
|
||||
*
|
||||
* @return bool
|
||||
* @throws \CoreException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
protected function LoadValues($aArgs, $sContains = '', $sOperation = 'contains')
|
||||
{
|
||||
$this->m_sContains = $sContains;
|
||||
$this->m_sOperation = $sOperation;
|
||||
|
||||
$this->m_aValues = array();
|
||||
|
||||
$oFilter = $this->GetFilter($sOperation, $sContains);
|
||||
|
||||
$oObjects = new DBObjectSet($oFilter, $this->m_aOrderBy, $aArgs, null, $this->m_iLimit, 0, $this->m_bSort);
|
||||
if (empty($this->m_sValueAttCode)) {
|
||||
$aAttToLoad = array($oFilter->GetClassAlias() => array('friendlyname'));
|
||||
} else {
|
||||
$aAttToLoad = array($oFilter->GetClassAlias() => array($this->m_sValueAttCode));
|
||||
}
|
||||
$oObjects->OptimizeColumnLoad($aAttToLoad);
|
||||
while ($oObject = $oObjects->Fetch()) {
|
||||
if (empty($this->m_sValueAttCode)) {
|
||||
$this->m_aValues[$oObject->GetKey()] = $oObject->GetName();
|
||||
} else {
|
||||
$this->m_aValues[$oObject->GetKey()] = $oObject->Get($this->m_sValueAttCode);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get filter for functions LoadValues and LoadValuesForAutocomplete
|
||||
*
|
||||
* @param $sOperation
|
||||
* @param $sContains
|
||||
*
|
||||
* @return \DBObjectSearch|\DBSearch|\DBUnionSearch|false|mixed
|
||||
* @throws \CoreException
|
||||
* @throws \OQLException
|
||||
* @since 3.0.3 3.1.0
|
||||
*/
|
||||
protected function GetFilter($sOperation, $sContains)
|
||||
{
|
||||
$this->m_sContains = $sContains;
|
||||
$this->m_sOperation = $sOperation;
|
||||
|
||||
if ($this->m_bAllowAllData) {
|
||||
$oFilter = DBObjectSearch::FromOQL_AllData($this->m_sFilterExpr);
|
||||
} else {
|
||||
$oFilter = DBObjectSearch::FromOQL($this->m_sFilterExpr);
|
||||
$oFilter->SetShowObsoleteData(utils::ShowObsoleteData());
|
||||
}
|
||||
if (!$oFilter) {
|
||||
return false;
|
||||
}
|
||||
if (!is_null($this->m_oExtraCondition)) {
|
||||
$oFilter = $oFilter->Intersect($this->m_oExtraCondition);
|
||||
}
|
||||
foreach ($this->m_aModifierProperties as $sPluginClass => $aProperties) {
|
||||
foreach ($aProperties as $sProperty => $value) {
|
||||
$oFilter->SetModifierProperty($sPluginClass, $sProperty, $value);
|
||||
}
|
||||
}
|
||||
|
||||
$sClass = $oFilter->GetClass();
|
||||
|
||||
switch ($this->m_sOperation) {
|
||||
case 'equals':
|
||||
case 'start_with':
|
||||
if ($this->m_sOperation === 'start_with') {
|
||||
$this->m_sContains .= '%';
|
||||
$sOperator = 'LIKE';
|
||||
} else {
|
||||
$sOperator = '=';
|
||||
}
|
||||
|
||||
$aAttributes = MetaModel::GetFriendlyNameAttributeCodeList($sClass);
|
||||
if (count($aAttributes) > 0) {
|
||||
$sClassAlias = $oFilter->GetClassAlias();
|
||||
$aFilters = array();
|
||||
$oValueExpr = new ScalarExpression($this->m_sContains);
|
||||
foreach ($aAttributes as $sAttribute) {
|
||||
$oNewFilter = $oFilter->DeepClone();
|
||||
$oNameExpr = new FieldExpression($sAttribute, $sClassAlias);
|
||||
$oCondition = new BinaryExpression($oNameExpr, $sOperator, $oValueExpr);
|
||||
$oNewFilter->AddConditionExpression($oCondition);
|
||||
$aFilters[] = $oNewFilter;
|
||||
}
|
||||
// Unions are much faster than OR conditions
|
||||
$oFilter = new DBUnionSearch($aFilters);
|
||||
} else {
|
||||
$oValueExpr = new ScalarExpression($this->m_sContains);
|
||||
$oNameExpr = new FieldExpression('friendlyname', $oFilter->GetClassAlias());
|
||||
$oNewCondition = new BinaryExpression($oNameExpr, $sOperator, $oValueExpr);
|
||||
$oFilter->AddConditionExpression($oNewCondition);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
$oValueExpr = new ScalarExpression('%'.$this->m_sContains.'%');
|
||||
$oNameExpr = new FieldExpression('friendlyname', $oFilter->GetClassAlias());
|
||||
$oNewCondition = new BinaryExpression($oNameExpr, 'LIKE', $oValueExpr);
|
||||
$oFilter->AddConditionExpression($oNewCondition);
|
||||
break;
|
||||
}
|
||||
|
||||
return $oFilter;
|
||||
}
|
||||
|
||||
public function GetValuesDescription()
|
||||
{
|
||||
return 'Filter: '.$this->m_sFilterExpr;
|
||||
}
|
||||
|
||||
public function GetFilterExpression()
|
||||
{
|
||||
return $this->m_sFilterExpr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $iLimit
|
||||
*/
|
||||
public function SetLimit($iLimit)
|
||||
{
|
||||
$this->m_iLimit = $iLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $bSort
|
||||
*/
|
||||
public function SetSort($bSort)
|
||||
{
|
||||
$this->m_bSort = $bSort;
|
||||
}
|
||||
|
||||
public function GetValuesForAutocomplete($aArgs, $sContains = '', $sOperation = 'contains')
|
||||
{
|
||||
if (!$this->m_bIsLoaded || ($sContains != $this->m_sContains) || ($sOperation != $this->m_sOperation))
|
||||
{
|
||||
$this->LoadValuesForAutocomplete($aArgs, $sContains, $sOperation);
|
||||
$this->m_bIsLoaded = true;
|
||||
}
|
||||
// The results are already filtered and sorted (on friendly name)
|
||||
$aRet = $this->m_aValues;
|
||||
return $aRet;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $aArgs
|
||||
* @param string $sContains
|
||||
* @param string $sOperation 'contains' or 'equals_start_with'
|
||||
*
|
||||
* @return bool
|
||||
* @throws \CoreException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
protected function LoadValuesForAutocomplete($aArgs, $sContains = '', $sOperation = 'contains')
|
||||
{
|
||||
$this->m_aValues = array();
|
||||
|
||||
$oFilter = $this->GetFilter($sOperation, $sContains);
|
||||
$sClass = $oFilter->GetClass();
|
||||
$sClassAlias = $oFilter->GetClassAlias();
|
||||
|
||||
$oObjects = new DBObjectSet($oFilter, $this->m_aOrderBy, $aArgs, null, $this->m_iLimit, 0, $this->m_bSort);
|
||||
if (empty($this->m_sValueAttCode)) {
|
||||
$aAttToLoad = ['friendlyname'];
|
||||
} else {
|
||||
$aAttToLoad = [$this->m_sValueAttCode];
|
||||
}
|
||||
|
||||
$sImageAttr = MetaModel::GetImageAttributeCode($sClass);
|
||||
if (!empty($sImageAttr)) {
|
||||
$aAttToLoad [] = $sImageAttr;
|
||||
}
|
||||
|
||||
$aComplementAttributeSpec = MetaModel::GetNameSpec($sClass, FriendlyNameType::COMPLEMENTARY);
|
||||
$sFormatAdditionalField = $aComplementAttributeSpec[0];
|
||||
$aAdditionalField = $aComplementAttributeSpec[1];
|
||||
|
||||
if (count($aAdditionalField) > 0) {
|
||||
if (is_array($aAdditionalField)) {
|
||||
$aAttToLoad = array_merge($aAttToLoad, $aAdditionalField);
|
||||
} else {
|
||||
$aAttToLoad [] = $aAdditionalField;
|
||||
}
|
||||
}
|
||||
|
||||
$oObjects->OptimizeColumnLoad([$sClassAlias => $aAttToLoad]);
|
||||
while ($oObject = $oObjects->Fetch()) {
|
||||
$aData = [];
|
||||
if (empty($this->m_sValueAttCode)) {
|
||||
$aData['label'] = $oObject->GetName();
|
||||
} else {
|
||||
$aData['label'] = $oObject->Get($this->m_sValueAttCode);
|
||||
}
|
||||
if ($oObject->IsObsolete()) {
|
||||
$aData['obsolescence_flag'] = '1';
|
||||
} else {
|
||||
$aData['obsolescence_flag'] = '0';
|
||||
}
|
||||
if (count($aAdditionalField) > 0) {
|
||||
$aArguments = [];
|
||||
foreach ($aAdditionalField as $sAdditionalField) {
|
||||
array_push($aArguments, $oObject->Get($sAdditionalField));
|
||||
}
|
||||
$aData['additional_field'] = utils::VSprintf($sFormatAdditionalField, $aArguments);
|
||||
} else {
|
||||
$aData['additional_field'] = '';
|
||||
}
|
||||
if (!empty($sImageAttr)) {
|
||||
/** @var \ormDocument $oImage */
|
||||
$oImage = $oObject->Get($sImageAttr);
|
||||
if (!$oImage->IsEmpty()) {
|
||||
$aData['picture_url'] = $oImage->GetDisplayURL($sClass, $oObject->GetKey(), $sImageAttr);
|
||||
$aData['initials'] = '';
|
||||
} else {
|
||||
$aData['initials'] = utils::ToAcronym($aData['label']);
|
||||
}
|
||||
}
|
||||
$this->m_aValues[$oObject->GetKey()] = $aData;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Fixed set values (could be hardcoded in the business model)
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
class ValueSetEnum extends ValueSetDefinition
|
||||
{
|
||||
protected $m_values;
|
||||
/**
|
||||
* @var bool $bSortByValues If true, values will be sorted at runtime (on their values, not their keys), otherwise it is sorted at compile time in a predefined order.
|
||||
* {@see \MFCompiler::CompileAttributeEnumValues()} for complete reasons.
|
||||
* @since 3.1.0 N°1646
|
||||
*/
|
||||
protected bool $bSortByValues;
|
||||
|
||||
/**
|
||||
* @param array|string $Values
|
||||
* @param bool $bLocalizedSort
|
||||
*
|
||||
* @since 3.1.0 N°1646 Add $bLocalizedSort parameter
|
||||
* @since 3.2.0 N°7157 $Values can be an array of backed-enum cases
|
||||
*/
|
||||
public function __construct($Values, bool $bSortByValues = false)
|
||||
{
|
||||
$this->m_values = $Values;
|
||||
$this->bSortByValues = $bSortByValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \ValueSetEnum::$bSortByValues
|
||||
* @return bool
|
||||
* @since 3.1.0 N°1646
|
||||
*/
|
||||
public function IsSortedByValues(): bool
|
||||
{
|
||||
return $this->bSortByValues;
|
||||
}
|
||||
|
||||
// Helper to export the data model
|
||||
public function GetValueList()
|
||||
{
|
||||
$this->LoadValues(null);
|
||||
return $this->m_aValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @since 3.1.0 N°1646 Overload method
|
||||
*/
|
||||
public function SortValues(array &$aValues): void
|
||||
{
|
||||
// Force sort by values only if necessary
|
||||
if ($this->bSortByValues) {
|
||||
natcasesort($aValues);
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't sort values as we rely on the order defined during compilation
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array|string $aArgs
|
||||
*
|
||||
* @return true
|
||||
*/
|
||||
protected function LoadValues($aArgs)
|
||||
{
|
||||
$aValues = [];
|
||||
if (is_array($this->m_values))
|
||||
{
|
||||
foreach ($this->m_values as $key => $value) {
|
||||
// Handle backed-enum case
|
||||
if (is_object($value) && enum_exists(get_class($value))) {
|
||||
$aValues[$value->value] = $value->value;
|
||||
continue;
|
||||
}
|
||||
|
||||
$aValues[$key] = $value;
|
||||
}
|
||||
}
|
||||
elseif (is_string($this->m_values) && strlen($this->m_values) > 0)
|
||||
{
|
||||
foreach (explode(",", $this->m_values) as $sVal)
|
||||
{
|
||||
$sVal = trim($sVal);
|
||||
$sKey = $sVal;
|
||||
$aValues[$sKey] = $sVal;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$aValues = [];
|
||||
}
|
||||
$this->m_aValues = $aValues;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
class ValueSetEnumPadded extends ValueSetEnum
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @since 3.1.0 N°6448 Add $bSortByValues parameter
|
||||
*/
|
||||
public function __construct($Values, bool $bSortByValues = false)
|
||||
{
|
||||
parent::__construct($Values, $bSortByValues);
|
||||
if (is_string($Values))
|
||||
{
|
||||
$this->LoadValues(null);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->m_aValues = $Values;
|
||||
}
|
||||
$aPaddedValues = array();
|
||||
foreach ($this->m_aValues as $sKey => $sVal)
|
||||
{
|
||||
// Pad keys to the min. length required by the \AttributeSet
|
||||
$sKey = str_pad($sKey, 3, '_', STR_PAD_LEFT);
|
||||
$aPaddedValues[$sKey] = $sVal;
|
||||
}
|
||||
$this->m_values = $aPaddedValues;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fixed set values, defined as a range: 0..59 (with an optional increment)
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
class ValueSetRange extends ValueSetDefinition
|
||||
{
|
||||
protected $m_iStart;
|
||||
protected $m_iEnd;
|
||||
|
||||
public function __construct($iStart, $iEnd, $iStep = 1)
|
||||
{
|
||||
$this->m_iStart = $iStart;
|
||||
$this->m_iEnd = $iEnd;
|
||||
$this->m_iStep = $iStep;
|
||||
}
|
||||
|
||||
protected function LoadValues($aArgs)
|
||||
{
|
||||
$iValue = $this->m_iStart;
|
||||
for($iValue = $this->m_iStart; $iValue <= $this->m_iEnd; $iValue += $this->m_iStep)
|
||||
{
|
||||
$this->m_aValues[$iValue] = $iValue;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Data model classes
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
class ValueSetEnumClasses extends ValueSetEnum
|
||||
{
|
||||
protected $m_sCategories;
|
||||
|
||||
public function __construct($sCategories = '', $sAdditionalValues = '')
|
||||
{
|
||||
$this->m_sCategories = $sCategories;
|
||||
parent::__construct($sAdditionalValues, true /* Classes are always sorted alphabetically */);
|
||||
}
|
||||
|
||||
protected function LoadValues($aArgs)
|
||||
{
|
||||
// Call the parent to parse the additional values...
|
||||
parent::LoadValues($aArgs);
|
||||
|
||||
// Translate the labels of the additional values
|
||||
foreach($this->m_aValues as $sClass => $void)
|
||||
{
|
||||
if (MetaModel::IsValidClass($sClass))
|
||||
{
|
||||
$this->m_aValues[$sClass] = MetaModel::GetName($sClass);
|
||||
}
|
||||
else
|
||||
{
|
||||
unset($this->m_aValues[$sClass]);
|
||||
}
|
||||
}
|
||||
|
||||
// Then, add the classes from the category definition
|
||||
foreach (MetaModel::GetClasses($this->m_sCategories) as $sClass)
|
||||
{
|
||||
if (MetaModel::IsValidClass($sClass))
|
||||
{
|
||||
$this->m_aValues[$sClass] = MetaModel::GetName($sClass);
|
||||
}
|
||||
else
|
||||
{
|
||||
unset($this->m_aValues[$sClass]);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -6,99 +6,99 @@ $vendorDir = dirname(__DIR__);
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
'AbstractApplicationObjectExtension' => $baseDir . '/application/applicationextension.inc.php',
|
||||
'AbstractApplicationUIExtension' => $baseDir . '/application/applicationextension.inc.php',
|
||||
'AbstractLoginFSMExtension' => $baseDir . '/application/applicationextension.inc.php',
|
||||
'AbstractPageUIBlockExtension' => $baseDir . '/application/applicationextension.inc.php',
|
||||
'AbstractPortalUIExtension' => $baseDir . '/application/applicationextension.inc.php',
|
||||
'AbstractPreferencesExtension' => $baseDir . '/application/applicationextension.inc.php',
|
||||
'AbstractApplicationObjectExtension' => $baseDir . '/application/applicationextension/backoffice/AbstractApplicationObjectExtension.php',
|
||||
'AbstractApplicationUIExtension' => $baseDir . '/application/applicationextension/backoffice/AbstractApplicationUIExtension.php',
|
||||
'AbstractLoginFSMExtension' => $baseDir . '/application/applicationextension/login/AbstractLoginFSMExtension.php',
|
||||
'AbstractPageUIBlockExtension' => $baseDir . '/application/applicationextension/backoffice/AbstractPageUIBlockExtension.php',
|
||||
'AbstractPortalUIExtension' => $baseDir . '/application/applicationextension/portal/AbstractPortalUIExtension.php',
|
||||
'AbstractPreferencesExtension' => $baseDir . '/application/applicationextension/backoffice/AbstractPreferencesExtension.php',
|
||||
'AbstractWeeklyScheduledProcess' => $baseDir . '/core/backgroundprocess.inc.php',
|
||||
'AbstractWelcomePopupExtension' => $baseDir . '/application/applicationextension.inc.php',
|
||||
'Action' => $baseDir . '/core/action.class.inc.php',
|
||||
'AbstractWelcomePopupExtension' => $baseDir . '/application/applicationextension/backoffice/AbstractWelcomePopupExtension.php',
|
||||
'Action' => $baseDir . '/sources/Application/DataModel/TriggerAndAction/Action.php',
|
||||
'ActionChecker' => $baseDir . '/core/userrights.class.inc.php',
|
||||
'ActionEmail' => $baseDir . '/core/action.class.inc.php',
|
||||
'ActionNotification' => $baseDir . '/core/action.class.inc.php',
|
||||
'ActionEmail' => $baseDir . '/sources/Application/DataModel/TriggerAndAction/ActionEmail.php',
|
||||
'ActionNotification' => $baseDir . '/sources/Application/DataModel/TriggerAndAction/ActionNotification.php',
|
||||
'ApcService' => $baseDir . '/core/apc-service.class.inc.php',
|
||||
'ApplicationContext' => $baseDir . '/application/applicationcontext.class.inc.php',
|
||||
'ApplicationException' => $baseDir . '/application/exceptions/ApplicationException.php',
|
||||
'ApplicationMenu' => $baseDir . '/application/menunode.class.inc.php',
|
||||
'ApplicationPopupMenuItem' => $baseDir . '/application/applicationextension.inc.php',
|
||||
'ApplicationPopupMenuItem' => $baseDir . '/application/applicationextension/backoffice/ApplicationPopupMenuItem.php',
|
||||
'Archive_Tar' => $vendorDir . '/pear/archive_tar/Archive/Tar.php',
|
||||
'ArchivedObjectException' => $baseDir . '/application/exceptions/ArchivedObjectException.php',
|
||||
'AsyncSendEmail' => $baseDir . '/core/asynctask.class.inc.php',
|
||||
'AsyncSendNewsroom' => $baseDir . '/core/asynctask.class.inc.php',
|
||||
'AsyncTask' => $baseDir . '/core/asynctask.class.inc.php',
|
||||
'AttributeApplicationLanguage' => $baseDir . '/core/attributedef.class.inc.php',
|
||||
'AttributeArchiveDate' => $baseDir . '/core/attributedef.class.inc.php',
|
||||
'AttributeArchiveFlag' => $baseDir . '/core/attributedef.class.inc.php',
|
||||
'AttributeBlob' => $baseDir . '/core/attributedef.class.inc.php',
|
||||
'AttributeBoolean' => $baseDir . '/core/attributedef.class.inc.php',
|
||||
'AttributeCaseLog' => $baseDir . '/core/attributedef.class.inc.php',
|
||||
'AttributeClass' => $baseDir . '/core/attributedef.class.inc.php',
|
||||
'AttributeClassAttCodeSet' => $baseDir . '/core/attributedef.class.inc.php',
|
||||
'AttributeClassState' => $baseDir . '/core/attributedef.class.inc.php',
|
||||
'AttributeCustomFields' => $baseDir . '/core/attributedef.class.inc.php',
|
||||
'AttributeDBField' => $baseDir . '/core/attributedef.class.inc.php',
|
||||
'AttributeDBFieldVoid' => $baseDir . '/core/attributedef.class.inc.php',
|
||||
'AttributeDashboard' => $baseDir . '/core/attributedef.class.inc.php',
|
||||
'AttributeDate' => $baseDir . '/core/attributedef.class.inc.php',
|
||||
'AttributeDateTime' => $baseDir . '/core/attributedef.class.inc.php',
|
||||
'AttributeDeadline' => $baseDir . '/core/attributedef.class.inc.php',
|
||||
'AttributeDecimal' => $baseDir . '/core/attributedef.class.inc.php',
|
||||
'AttributeDefinition' => $baseDir . '/core/attributedef.class.inc.php',
|
||||
'AttributeDuration' => $baseDir . '/core/attributedef.class.inc.php',
|
||||
'AttributeEmailAddress' => $baseDir . '/core/attributedef.class.inc.php',
|
||||
'AttributeEncryptedString' => $baseDir . '/core/attributedef.class.inc.php',
|
||||
'AttributeEnum' => $baseDir . '/core/attributedef.class.inc.php',
|
||||
'AttributeEnumSet' => $baseDir . '/core/attributedef.class.inc.php',
|
||||
'AttributeExternalField' => $baseDir . '/core/attributedef.class.inc.php',
|
||||
'AttributeExternalKey' => $baseDir . '/core/attributedef.class.inc.php',
|
||||
'AttributeFinalClass' => $baseDir . '/core/attributedef.class.inc.php',
|
||||
'AttributeFriendlyName' => $baseDir . '/core/attributedef.class.inc.php',
|
||||
'AttributeHTML' => $baseDir . '/core/attributedef.class.inc.php',
|
||||
'AttributeHierarchicalKey' => $baseDir . '/core/attributedef.class.inc.php',
|
||||
'AttributeIPAddress' => $baseDir . '/core/attributedef.class.inc.php',
|
||||
'AttributeImage' => $baseDir . '/core/attributedef.class.inc.php',
|
||||
'AttributeInteger' => $baseDir . '/core/attributedef.class.inc.php',
|
||||
'AttributeLinkedSet' => $baseDir . '/core/attributedef.class.inc.php',
|
||||
'AttributeLinkedSetIndirect' => $baseDir . '/core/attributedef.class.inc.php',
|
||||
'AttributeLongText' => $baseDir . '/core/attributedef.class.inc.php',
|
||||
'AttributeMetaEnum' => $baseDir . '/core/attributedef.class.inc.php',
|
||||
'AttributeOQL' => $baseDir . '/core/attributedef.class.inc.php',
|
||||
'AttributeObjectKey' => $baseDir . '/core/attributedef.class.inc.php',
|
||||
'AttributeObsolescenceDate' => $baseDir . '/core/attributedef.class.inc.php',
|
||||
'AttributeObsolescenceFlag' => $baseDir . '/core/attributedef.class.inc.php',
|
||||
'AttributeOneWayPassword' => $baseDir . '/core/attributedef.class.inc.php',
|
||||
'AttributePassword' => $baseDir . '/core/attributedef.class.inc.php',
|
||||
'AttributePercentage' => $baseDir . '/core/attributedef.class.inc.php',
|
||||
'AttributePhoneNumber' => $baseDir . '/core/attributedef.class.inc.php',
|
||||
'AttributePropertySet' => $baseDir . '/core/attributedef.class.inc.php',
|
||||
'AttributeQueryAttCodeSet' => $baseDir . '/core/attributedef.class.inc.php',
|
||||
'AttributeRedundancySettings' => $baseDir . '/core/attributedef.class.inc.php',
|
||||
'AttributeSet' => $baseDir . '/core/attributedef.class.inc.php',
|
||||
'AttributeStopWatch' => $baseDir . '/core/attributedef.class.inc.php',
|
||||
'AttributeString' => $baseDir . '/core/attributedef.class.inc.php',
|
||||
'AttributeSubItem' => $baseDir . '/core/attributedef.class.inc.php',
|
||||
'AttributeTable' => $baseDir . '/core/attributedef.class.inc.php',
|
||||
'AttributeTagSet' => $baseDir . '/core/attributedef.class.inc.php',
|
||||
'AttributeTemplateHTML' => $baseDir . '/core/attributedef.class.inc.php',
|
||||
'AttributeTemplateString' => $baseDir . '/core/attributedef.class.inc.php',
|
||||
'AttributeTemplateText' => $baseDir . '/core/attributedef.class.inc.php',
|
||||
'AttributeText' => $baseDir . '/core/attributedef.class.inc.php',
|
||||
'AttributeURL' => $baseDir . '/core/attributedef.class.inc.php',
|
||||
'AsyncSendEmail' => $baseDir . '/sources/Core/DataModel/AsyncTask/AsyncSendEmail.php',
|
||||
'AsyncSendNewsroom' => $baseDir . '/sources/Core/DataModel/AsyncTask/AsyncSendNewsroom.php',
|
||||
'AsyncTask' => $baseDir . '/sources/Core/DataModel/AsyncTask/AsyncTask.php',
|
||||
'AttributeApplicationLanguage' => $baseDir . '/sources/Core/AttributeDefinition/AttributeApplicationLanguage.php',
|
||||
'AttributeArchiveDate' => $baseDir . '/sources/Core/AttributeDefinition/AttributeArchiveDate.php',
|
||||
'AttributeArchiveFlag' => $baseDir . '/sources/Core/AttributeDefinition/AttributeArchiveFlag.php',
|
||||
'AttributeBlob' => $baseDir . '/sources/Core/AttributeDefinition/AttributeBlob.php',
|
||||
'AttributeBoolean' => $baseDir . '/sources/Core/AttributeDefinition/AttributeBoolean.php',
|
||||
'AttributeCaseLog' => $baseDir . '/sources/Core/AttributeDefinition/AttributeCaseLog.php',
|
||||
'AttributeClass' => $baseDir . '/sources/Core/AttributeDefinition/AttributeClass.php',
|
||||
'AttributeClassAttCodeSet' => $baseDir . '/sources/Core/AttributeDefinition/AttributeClassAttCodeSet.php',
|
||||
'AttributeClassState' => $baseDir . '/sources/Core/AttributeDefinition/AttributeClassState.php',
|
||||
'AttributeCustomFields' => $baseDir . '/sources/Core/AttributeDefinition/AttributeCustomFields.php',
|
||||
'AttributeDBField' => $baseDir . '/sources/Core/AttributeDefinition/AttributeDBField.php',
|
||||
'AttributeDBFieldVoid' => $baseDir . '/sources/Core/AttributeDefinition/AttributeDBFieldVoid.php',
|
||||
'AttributeDashboard' => $baseDir . '/sources/Core/AttributeDefinition/AttributeDashboard.php',
|
||||
'AttributeDate' => $baseDir . '/sources/Core/AttributeDefinition/AttributeDate.php',
|
||||
'AttributeDateTime' => $baseDir . '/sources/Core/AttributeDefinition/AttributeDateTime.php',
|
||||
'AttributeDeadline' => $baseDir . '/sources/Core/AttributeDefinition/AttributeDeadline.php',
|
||||
'AttributeDecimal' => $baseDir . '/sources/Core/AttributeDefinition/AttributeDecimal.php',
|
||||
'AttributeDefinition' => $baseDir . '/sources/Core/AttributeDefinition/AttributeDefinition.php',
|
||||
'AttributeDuration' => $baseDir . '/sources/Core/AttributeDefinition/AttributeDuration.php',
|
||||
'AttributeEmailAddress' => $baseDir . '/sources/Core/AttributeDefinition/AttributeEmailAddress.php',
|
||||
'AttributeEncryptedString' => $baseDir . '/sources/Core/AttributeDefinition/AttributeEncryptedString.php',
|
||||
'AttributeEnum' => $baseDir . '/sources/Core/AttributeDefinition/AttributeEnum.php',
|
||||
'AttributeEnumSet' => $baseDir . '/sources/Core/AttributeDefinition/AttributeEnumSet.php',
|
||||
'AttributeExternalField' => $baseDir . '/sources/Core/AttributeDefinition/AttributeExternalField.php',
|
||||
'AttributeExternalKey' => $baseDir . '/sources/Core/AttributeDefinition/AttributeExternalKey.php',
|
||||
'AttributeFinalClass' => $baseDir . '/sources/Core/AttributeDefinition/AttributeFinalClass.php',
|
||||
'AttributeFriendlyName' => $baseDir . '/sources/Core/AttributeDefinition/AttributeFriendlyName.php',
|
||||
'AttributeHTML' => $baseDir . '/sources/Core/AttributeDefinition/AttributeHTML.php',
|
||||
'AttributeHierarchicalKey' => $baseDir . '/sources/Core/AttributeDefinition/AttributeHierarchicalKey.php',
|
||||
'AttributeIPAddress' => $baseDir . '/sources/Core/AttributeDefinition/AttributeIPAddress.php',
|
||||
'AttributeImage' => $baseDir . '/sources/Core/AttributeDefinition/AttributeImage.php',
|
||||
'AttributeInteger' => $baseDir . '/sources/Core/AttributeDefinition/AttributeInteger.php',
|
||||
'AttributeLinkedSet' => $baseDir . '/sources/Core/AttributeDefinition/AttributeLinkedSet.php',
|
||||
'AttributeLinkedSetIndirect' => $baseDir . '/sources/Core/AttributeDefinition/AttributeLinkedSetIndirect.php',
|
||||
'AttributeLongText' => $baseDir . '/sources/Core/AttributeDefinition/AttributeLongText.php',
|
||||
'AttributeMetaEnum' => $baseDir . '/sources/Core/AttributeDefinition/AttributeMetaEnum.php',
|
||||
'AttributeOQL' => $baseDir . '/sources/Core/AttributeDefinition/AttributeOQL.php',
|
||||
'AttributeObjectKey' => $baseDir . '/sources/Core/AttributeDefinition/AttributeObjectKey.php',
|
||||
'AttributeObsolescenceDate' => $baseDir . '/sources/Core/AttributeDefinition/AttributeObsolescenceDate.php',
|
||||
'AttributeObsolescenceFlag' => $baseDir . '/sources/Core/AttributeDefinition/AttributeObsolescenceFlag.php',
|
||||
'AttributeOneWayPassword' => $baseDir . '/sources/Core/AttributeDefinition/AttributeOneWayPassword.php',
|
||||
'AttributePassword' => $baseDir . '/sources/Core/AttributeDefinition/AttributePassword.php',
|
||||
'AttributePercentage' => $baseDir . '/sources/Core/AttributeDefinition/AttributePercentage.php',
|
||||
'AttributePhoneNumber' => $baseDir . '/sources/Core/AttributeDefinition/AttributePhoneNumber.php',
|
||||
'AttributePropertySet' => $baseDir . '/sources/Core/AttributeDefinition/AttributePropertySet.php',
|
||||
'AttributeQueryAttCodeSet' => $baseDir . '/sources/Core/AttributeDefinition/AttributeQueryAttCodeSet.php',
|
||||
'AttributeRedundancySettings' => $baseDir . '/sources/Core/AttributeDefinition/AttributeRedundancySettings.php',
|
||||
'AttributeSet' => $baseDir . '/sources/Core/AttributeDefinition/AttributeSet.php',
|
||||
'AttributeStopWatch' => $baseDir . '/sources/Core/AttributeDefinition/AttributeStopWatch.php',
|
||||
'AttributeString' => $baseDir . '/sources/Core/AttributeDefinition/AttributeString.php',
|
||||
'AttributeSubItem' => $baseDir . '/sources/Core/AttributeDefinition/AttributeSubItem.php',
|
||||
'AttributeTable' => $baseDir . '/sources/Core/AttributeDefinition/AttributeTable.php',
|
||||
'AttributeTagSet' => $baseDir . '/sources/Core/AttributeDefinition/AttributeTagSet.php',
|
||||
'AttributeTemplateHTML' => $baseDir . '/sources/Core/AttributeDefinition/AttributeTemplateHTML.php',
|
||||
'AttributeTemplateString' => $baseDir . '/sources/Core/AttributeDefinition/AttributeTemplateString.php',
|
||||
'AttributeTemplateText' => $baseDir . '/sources/Core/AttributeDefinition/AttributeTemplateText.php',
|
||||
'AttributeText' => $baseDir . '/sources/Core/AttributeDefinition/AttributeText.php',
|
||||
'AttributeURL' => $baseDir . '/sources/Core/AttributeDefinition/AttributeURL.php',
|
||||
'AuditCategory' => $baseDir . '/application/audit.category.class.inc.php',
|
||||
'AuditDomain' => $baseDir . '/application/audit.domain.class.inc.php',
|
||||
'AuditRule' => $baseDir . '/application/audit.rule.class.inc.php',
|
||||
'BackgroundTask' => $baseDir . '/core/backgroundtask.class.inc.php',
|
||||
'BackgroundTask' => $baseDir . '/sources/Core/DataModel/BackgroundTask.php',
|
||||
'BinaryExpression' => $baseDir . '/core/oql/expression.class.inc.php',
|
||||
'BinaryOqlExpression' => $baseDir . '/core/oql/oqlquery.class.inc.php',
|
||||
'BulkChange' => $baseDir . '/core/bulkchange.class.inc.php',
|
||||
'BulkChange' => $baseDir . '/sources/Core/BulkChange/BulkChange.php',
|
||||
'BulkChangeException' => $baseDir . '/application/exceptions/BulkChangeException.php',
|
||||
'BulkExport' => $baseDir . '/core/bulkexport.class.inc.php',
|
||||
'BulkExportException' => $baseDir . '/core/bulkexport.class.inc.php',
|
||||
'BulkExportMissingParameterException' => $baseDir . '/core/bulkexport.class.inc.php',
|
||||
'BulkExportResult' => $baseDir . '/core/bulkexport.class.inc.php',
|
||||
'BulkExportResultGC' => $baseDir . '/core/bulkexport.class.inc.php',
|
||||
'BulkExport' => $baseDir . '/sources/Application/BulkExport/BulkExport.php',
|
||||
'BulkExportException' => $baseDir . '/sources/Application/BulkExport/BulkExportException.php',
|
||||
'BulkExportMissingParameterException' => $baseDir . '/sources/Application/BulkExport/BulkExportMissingParameterException.php',
|
||||
'BulkExportResult' => $baseDir . '/sources/Core/DataModel/BulkExportResult.php',
|
||||
'BulkExportResultGC' => $baseDir . '/sources/Application/BulkExport/BulkExportResultGC.php',
|
||||
'CAS_AuthenticationException' => $vendorDir . '/apereo/phpcas/source/CAS/AuthenticationException.php',
|
||||
'CAS_Client' => $vendorDir . '/apereo/phpcas/source/CAS/Client.php',
|
||||
'CAS_CookieJar' => $vendorDir . '/apereo/phpcas/source/CAS/CookieJar.php',
|
||||
@@ -151,25 +151,25 @@ return array(
|
||||
'CAS_Session_PhpSession' => $vendorDir . '/apereo/phpcas/source/CAS/Session/PhpSession.php',
|
||||
'CAS_TypeMismatchException' => $vendorDir . '/apereo/phpcas/source/CAS/TypeMismatchException.php',
|
||||
'CMDBChange' => $baseDir . '/core/cmdbchange.class.inc.php',
|
||||
'CMDBChangeOp' => $baseDir . '/core/cmdbchangeop.class.inc.php',
|
||||
'CMDBChangeOpCreate' => $baseDir . '/core/cmdbchangeop.class.inc.php',
|
||||
'CMDBChangeOpDelete' => $baseDir . '/core/cmdbchangeop.class.inc.php',
|
||||
'CMDBChangeOpPlugin' => $baseDir . '/core/cmdbchangeop.class.inc.php',
|
||||
'CMDBChangeOpSetAttribute' => $baseDir . '/core/cmdbchangeop.class.inc.php',
|
||||
'CMDBChangeOpSetAttributeBlob' => $baseDir . '/core/cmdbchangeop.class.inc.php',
|
||||
'CMDBChangeOpSetAttributeCaseLog' => $baseDir . '/core/cmdbchangeop.class.inc.php',
|
||||
'CMDBChangeOpSetAttributeCustomFields' => $baseDir . '/core/cmdbchangeop.class.inc.php',
|
||||
'CMDBChangeOpSetAttributeEncrypted' => $baseDir . '/core/cmdbchangeop.class.inc.php',
|
||||
'CMDBChangeOpSetAttributeHTML' => $baseDir . '/core/cmdbchangeop.class.inc.php',
|
||||
'CMDBChangeOpSetAttributeLinks' => $baseDir . '/core/cmdbchangeop.class.inc.php',
|
||||
'CMDBChangeOpSetAttributeLinksAddRemove' => $baseDir . '/core/cmdbchangeop.class.inc.php',
|
||||
'CMDBChangeOpSetAttributeLinksTune' => $baseDir . '/core/cmdbchangeop.class.inc.php',
|
||||
'CMDBChangeOpSetAttributeLongText' => $baseDir . '/core/cmdbchangeop.class.inc.php',
|
||||
'CMDBChangeOpSetAttributeOneWayPassword' => $baseDir . '/core/cmdbchangeop.class.inc.php',
|
||||
'CMDBChangeOpSetAttributeScalar' => $baseDir . '/core/cmdbchangeop.class.inc.php',
|
||||
'CMDBChangeOpSetAttributeTagSet' => $baseDir . '/core/cmdbchangeop.class.inc.php',
|
||||
'CMDBChangeOpSetAttributeText' => $baseDir . '/core/cmdbchangeop.class.inc.php',
|
||||
'CMDBChangeOpSetAttributeURL' => $baseDir . '/core/cmdbchangeop.class.inc.php',
|
||||
'CMDBChangeOp' => $baseDir . '/sources/Core/DataModel/CMDBChange/CMDBChangeOp.php',
|
||||
'CMDBChangeOpCreate' => $baseDir . '/sources/Core/DataModel/CMDBChange/CMDBChangeOpCreate.php',
|
||||
'CMDBChangeOpDelete' => $baseDir . '/sources/Core/DataModel/CMDBChange/CMDBChangeOpDelete.php',
|
||||
'CMDBChangeOpPlugin' => $baseDir . '/sources/Core/DataModel/CMDBChange/CMDBChangeOpPlugin.php',
|
||||
'CMDBChangeOpSetAttribute' => $baseDir . '/sources/Core/DataModel/CMDBChange/CMDBChangeOpSetAttribute.php',
|
||||
'CMDBChangeOpSetAttributeBlob' => $baseDir . '/sources/Core/DataModel/CMDBChange/CMDBChangeOpSetAttributeBlob.php',
|
||||
'CMDBChangeOpSetAttributeCaseLog' => $baseDir . '/sources/Core/DataModel/CMDBChange/CMDBChangeOpSetAttributeCaseLog.php',
|
||||
'CMDBChangeOpSetAttributeCustomFields' => $baseDir . '/sources/Core/DataModel/CMDBChange/CMDBChangeOpSetAttributeCustomFields.php',
|
||||
'CMDBChangeOpSetAttributeEncrypted' => $baseDir . '/sources/Core/DataModel/CMDBChange/CMDBChangeOpSetAttributeEncrypted.php',
|
||||
'CMDBChangeOpSetAttributeHTML' => $baseDir . '/sources/Core/DataModel/CMDBChange/CMDBChangeOpSetAttributeHTML.php',
|
||||
'CMDBChangeOpSetAttributeLinks' => $baseDir . '/sources/Core/DataModel/CMDBChange/CMDBChangeOpSetAttributeLinks.php',
|
||||
'CMDBChangeOpSetAttributeLinksAddRemove' => $baseDir . '/sources/Core/DataModel/CMDBChange/CMDBChangeOpSetAttributeLinksAddRemove.php',
|
||||
'CMDBChangeOpSetAttributeLinksTune' => $baseDir . '/sources/Core/DataModel/CMDBChange/CMDBChangeOpSetAttributeLinksTune.php',
|
||||
'CMDBChangeOpSetAttributeLongText' => $baseDir . '/sources/Core/DataModel/CMDBChange/CMDBChangeOpSetAttributeLongText.php',
|
||||
'CMDBChangeOpSetAttributeOneWayPassword' => $baseDir . '/sources/Core/DataModel/CMDBChange/CMDBChangeOpSetAttributeOneWayPassword.php',
|
||||
'CMDBChangeOpSetAttributeScalar' => $baseDir . '/sources/Core/DataModel/CMDBChange/CMDBChangeOpSetAttributeScalar.php',
|
||||
'CMDBChangeOpSetAttributeTagSet' => $baseDir . '/sources/Core/DataModel/CMDBChange/CMDBChangeOpSetAttributeTagSet.php',
|
||||
'CMDBChangeOpSetAttributeText' => $baseDir . '/sources/Core/DataModel/CMDBChange/CMDBChangeOpSetAttributeText.php',
|
||||
'CMDBChangeOpSetAttributeURL' => $baseDir . '/sources/Core/DataModel/CMDBChange/CMDBChangeOpSetAttributeURL.php',
|
||||
'CMDBObject' => $baseDir . '/core/cmdbobject.class.inc.php',
|
||||
'CMDBObjectSet' => $baseDir . '/core/cmdbobject.class.inc.php',
|
||||
'CMDBSource' => $baseDir . '/core/cmdbsource.class.inc.php',
|
||||
@@ -177,16 +177,16 @@ return array(
|
||||
'CSVParser' => $baseDir . '/core/csvparser.class.inc.php',
|
||||
'CSVParserException' => $baseDir . '/application/exceptions/CSVParserException.php',
|
||||
'CURLStringFile' => $vendorDir . '/symfony/polyfill-php81/Resources/stubs/CURLStringFile.php',
|
||||
'CellChangeSpec' => $baseDir . '/core/bulkchange.class.inc.php',
|
||||
'CellStatus_Ambiguous' => $baseDir . '/core/bulkchange.class.inc.php',
|
||||
'CellStatus_Issue' => $baseDir . '/core/bulkchange.class.inc.php',
|
||||
'CellStatus_Modify' => $baseDir . '/core/bulkchange.class.inc.php',
|
||||
'CellStatus_NullIssue' => $baseDir . '/core/bulkchange.class.inc.php',
|
||||
'CellStatus_SearchIssue' => $baseDir . '/core/bulkchange.class.inc.php',
|
||||
'CellStatus_Void' => $baseDir . '/core/bulkchange.class.inc.php',
|
||||
'CellChangeSpec' => $baseDir . '/sources/Core/BulkChange/CellChangeSpec.php',
|
||||
'CellStatus_Ambiguous' => $baseDir . '/sources/Core/BulkChange/CellStatus_Ambiguous.php',
|
||||
'CellStatus_Issue' => $baseDir . '/sources/Core/BulkChange/CellStatus_Issue.php',
|
||||
'CellStatus_Modify' => $baseDir . '/sources/Core/BulkChange/CellStatus_Modify.php',
|
||||
'CellStatus_NullIssue' => $baseDir . '/sources/Core/BulkChange/CellStatus_NullIssue.php',
|
||||
'CellStatus_SearchIssue' => $baseDir . '/sources/Core/BulkChange/CellStatus_SearchIssue.php',
|
||||
'CellStatus_Void' => $baseDir . '/sources/Core/BulkChange/CellStatus_Void.php',
|
||||
'CharConcatExpression' => $baseDir . '/core/oql/expression.class.inc.php',
|
||||
'CharConcatWSExpression' => $baseDir . '/core/oql/expression.class.inc.php',
|
||||
'CheckStopWatchThresholds' => $baseDir . '/core/ormstopwatch.class.inc.php',
|
||||
'CheckStopWatchThresholds' => $baseDir . '/sources/Core/Orm/ormStopWatch.php',
|
||||
'CheckableExpression' => $baseDir . '/core/oql/oqlquery.class.inc.php',
|
||||
'Combodo\\iTop\\Application\\Branding' => $baseDir . '/sources/Application/Branding.php',
|
||||
'Combodo\\iTop\\Application\\EventRegister\\ApplicationEvents' => $baseDir . '/sources/Application/EventRegister/ApplicationEvents.php',
|
||||
@@ -539,13 +539,13 @@ return array(
|
||||
'CoreTemplateException' => $baseDir . '/application/exceptions/CoreTemplateException.php',
|
||||
'CoreUnexpectedValue' => $baseDir . '/application/exceptions/CoreUnexpectedValue.php',
|
||||
'CoreWarning' => $baseDir . '/application/exceptions/CoreWarning.php',
|
||||
'CryptEngine' => $baseDir . '/core/simplecrypt.class.inc.php',
|
||||
'CryptEngine' => $baseDir . '/sources/Application/SimpleCrypt/CryptEngine.php',
|
||||
'CustomFieldsHandler' => $baseDir . '/core/customfieldshandler.class.inc.php',
|
||||
'DBObject' => $baseDir . '/core/dbobject.class.php',
|
||||
'DBObjectSearch' => $baseDir . '/core/dbobjectsearch.class.php',
|
||||
'DBObjectSet' => $baseDir . '/core/dbobjectset.class.php',
|
||||
'DBObjectSetComparator' => $baseDir . '/core/dbobjectset.class.php',
|
||||
'DBProperty' => $baseDir . '/core/dbproperty.class.inc.php',
|
||||
'DBProperty' => $baseDir . '/sources/Core/DataModel/DBProperty.php',
|
||||
'DBSearch' => $baseDir . '/core/dbsearch.class.php',
|
||||
'DBSearchHelper' => $baseDir . '/application/DBSearchHelper.php',
|
||||
'DBUnionSearch' => $baseDir . '/core/dbunionsearch.class.php',
|
||||
@@ -616,18 +616,18 @@ return array(
|
||||
'DisplayableNode' => $baseDir . '/core/displayablegraph.class.inc.php',
|
||||
'DisplayableRedundancyNode' => $baseDir . '/core/displayablegraph.class.inc.php',
|
||||
'EMail' => $baseDir . '/core/email.class.inc.php',
|
||||
'Event' => $baseDir . '/core/event.class.inc.php',
|
||||
'EventIssue' => $baseDir . '/core/event.class.inc.php',
|
||||
'EventLoginUsage' => $baseDir . '/core/event.class.inc.php',
|
||||
'EventNotification' => $baseDir . '/core/event.class.inc.php',
|
||||
'EventNotificationEmail' => $baseDir . '/core/event.class.inc.php',
|
||||
'EventOnObject' => $baseDir . '/core/event.class.inc.php',
|
||||
'EventRestService' => $baseDir . '/core/event.class.inc.php',
|
||||
'EventWebService' => $baseDir . '/core/event.class.inc.php',
|
||||
'ExcelBulkExport' => $baseDir . '/core/excelbulkexport.class.inc.php',
|
||||
'Event' => $baseDir . '/sources/Application/DataModel/Event/Event.php',
|
||||
'EventIssue' => $baseDir . '/sources/Application/DataModel/Event/EventIssue.php',
|
||||
'EventLoginUsage' => $baseDir . '/sources/Application/DataModel/Event/EventLoginUsage.php',
|
||||
'EventNotification' => $baseDir . '/sources/Application/DataModel/Event/EventNotification.php',
|
||||
'EventNotificationEmail' => $baseDir . '/sources/Application/DataModel/Event/EventNotificationEmail.php',
|
||||
'EventOnObject' => $baseDir . '/sources/Application/DataModel/Event/EventOnObject.php',
|
||||
'EventRestService' => $baseDir . '/sources/Application/DataModel/Event/EventRestService.php',
|
||||
'EventWebService' => $baseDir . '/sources/Application/DataModel/Event/EventWebService.php',
|
||||
'ExcelBulkExport' => $baseDir . '/sources/Application/BulkExport/ExcelBulkExport.php',
|
||||
'ExcelExporter' => $baseDir . '/application/excelexporter.class.inc.php',
|
||||
'ExceptionLog' => $baseDir . '/core/log.class.inc.php',
|
||||
'ExecAsyncTask' => $baseDir . '/core/asynctask.class.inc.php',
|
||||
'ExecAsyncTask' => $baseDir . '/sources/Core/DataModel/AsyncTask/ExecAsyncTask.php',
|
||||
'ExecutionKPI' => $baseDir . '/core/kpi.class.inc.php',
|
||||
'Expression' => $baseDir . '/core/oql/expression.class.inc.php',
|
||||
'ExpressionCache' => $baseDir . '/core/expressioncache.class.inc.php',
|
||||
@@ -738,7 +738,7 @@ return array(
|
||||
'GuzzleHttp\\RetryMiddleware' => $vendorDir . '/guzzlehttp/guzzle/src/RetryMiddleware.php',
|
||||
'GuzzleHttp\\TransferStats' => $vendorDir . '/guzzlehttp/guzzle/src/TransferStats.php',
|
||||
'GuzzleHttp\\Utils' => $vendorDir . '/guzzlehttp/guzzle/src/Utils.php',
|
||||
'HTMLBulkExport' => $baseDir . '/core/htmlbulkexport.class.inc.php',
|
||||
'HTMLBulkExport' => $baseDir . '/sources/Application/BulkExport/HTMLBulkExport.php',
|
||||
'HTMLDOMSanitizer' => $baseDir . '/core/htmlsanitizer.class.inc.php',
|
||||
'HTMLNullSanitizer' => $baseDir . '/core/htmlsanitizer.class.inc.php',
|
||||
'HTMLSanitizer' => $baseDir . '/core/htmlsanitizer.class.inc.php',
|
||||
@@ -753,10 +753,10 @@ return array(
|
||||
'InvalidExternalKeyValueException' => $baseDir . '/application/exceptions/InvalidExternalKeyValueException.php',
|
||||
'InvalidPasswordAttributeOneWayPassword' => $baseDir . '/application/exceptions/InvalidPasswordAttributeOneWayPassword.php',
|
||||
'IssueLog' => $baseDir . '/core/log.class.inc.php',
|
||||
'ItopCounter' => $baseDir . '/core/counter.class.inc.php',
|
||||
'JSButtonItem' => $baseDir . '/application/applicationextension.inc.php',
|
||||
'JSPopupMenuItem' => $baseDir . '/application/applicationextension.inc.php',
|
||||
'KeyValueStore' => $baseDir . '/core/counter.class.inc.php',
|
||||
'ItopCounter' => $baseDir . '/sources/Core/ItopCounter.php',
|
||||
'JSButtonItem' => $baseDir . '/application/applicationextension/backoffice/JSButtonItem.php',
|
||||
'JSPopupMenuItem' => $baseDir . '/application/applicationextension/backoffice/JSPopupMenuItem.php',
|
||||
'KeyValueStore' => $baseDir . '/sources/Core/DataModel/KeyValueStore.php',
|
||||
'Laminas\\Loader\\AutoloaderFactory' => $vendorDir . '/laminas/laminas-loader/src/AutoloaderFactory.php',
|
||||
'Laminas\\Loader\\ClassMapAutoloader' => $vendorDir . '/laminas/laminas-loader/src/ClassMapAutoloader.php',
|
||||
'Laminas\\Loader\\Exception\\BadMethodCallException' => $vendorDir . '/laminas/laminas-loader/src/Exception/BadMethodCallException.php',
|
||||
@@ -1117,7 +1117,7 @@ return array(
|
||||
'MenuGroup' => $baseDir . '/application/menunode.class.inc.php',
|
||||
'MenuNode' => $baseDir . '/application/menunode.class.inc.php',
|
||||
'MetaModel' => $baseDir . '/core/metamodel.class.php',
|
||||
'MissingColumnException' => $baseDir . '/core/attributedef.class.inc.php',
|
||||
'MissingColumnException' => $baseDir . '/sources/Core/AttributeDefinition/MissingColumnException.php',
|
||||
'MissingQueryArgument' => $baseDir . '/core/oql/expression.class.inc.php',
|
||||
'ModelReflection' => $baseDir . '/core/modelreflection.class.inc.php',
|
||||
'ModelReflectionRuntime' => $baseDir . '/core/modelreflection.class.inc.php',
|
||||
@@ -1170,7 +1170,7 @@ return array(
|
||||
'OqlUnionQuery' => $baseDir . '/core/oql/oqlquery.class.inc.php',
|
||||
'Override' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/Override.php',
|
||||
'PDF417' => $vendorDir . '/tecnickcom/tcpdf/include/barcodes/pdf417.php',
|
||||
'PDFBulkExport' => $baseDir . '/core/pdfbulkexport.class.inc.php',
|
||||
'PDFBulkExport' => $baseDir . '/sources/Application/BulkExport/PDFBulkExport.php',
|
||||
'PEAR' => $vendorDir . '/pear/pear-core-minimal/src/PEAR.php',
|
||||
'PEAR_ErrorStack' => $vendorDir . '/pear/pear-core-minimal/src/PEAR/ErrorStack.php',
|
||||
'PEAR_Exception' => $vendorDir . '/pear/pear_exception/PEAR/Exception.php',
|
||||
@@ -1501,26 +1501,26 @@ return array(
|
||||
'QueryOQL' => $baseDir . '/application/query.class.inc.php',
|
||||
'QueryReflection' => $baseDir . '/core/modelreflection.class.inc.php',
|
||||
'QueryReflectionRuntime' => $baseDir . '/core/modelreflection.class.inc.php',
|
||||
'RelationEdge' => $baseDir . '/core/relationgraph.class.inc.php',
|
||||
'RelationGraph' => $baseDir . '/core/relationgraph.class.inc.php',
|
||||
'RelationObjectNode' => $baseDir . '/core/relationgraph.class.inc.php',
|
||||
'RelationRedundancyNode' => $baseDir . '/core/relationgraph.class.inc.php',
|
||||
'RelationEdge' => $baseDir . '/sources/Core/RelationGraph/RelationEdge.php',
|
||||
'RelationGraph' => $baseDir . '/sources/Core/RelationGraph/RelationGraph.php',
|
||||
'RelationObjectNode' => $baseDir . '/sources/Core/RelationGraph/RelationObjectNode.php',
|
||||
'RelationRedundancyNode' => $baseDir . '/sources/Core/RelationGraph/RelationRedundancyNode.php',
|
||||
'RelationTypeIterator' => $baseDir . '/core/simplegraph.class.inc.php',
|
||||
'ReportValue' => $baseDir . '/core/bulkchange.class.inc.php',
|
||||
'ReportValue' => $baseDir . '/sources/Core/BulkChange/ReportValue.php',
|
||||
'RestDelete' => $baseDir . '/core/restservices.class.inc.php',
|
||||
'RestResult' => $baseDir . '/application/applicationextension.inc.php',
|
||||
'RestResult' => $baseDir . '/application/applicationextension/rest/RestResult.php',
|
||||
'RestResultWithObjects' => $baseDir . '/core/restservices.class.inc.php',
|
||||
'RestResultWithRelations' => $baseDir . '/core/restservices.class.inc.php',
|
||||
'RestUtils' => $baseDir . '/application/applicationextension.inc.php',
|
||||
'RestUtils' => $baseDir . '/application/applicationextension/rest/RestUtils.php',
|
||||
'ReturnTypeWillChange' => $vendorDir . '/symfony/polyfill-php81/Resources/stubs/ReturnTypeWillChange.php',
|
||||
'RotatingLogFileNameBuilder' => $baseDir . '/core/log.class.inc.php',
|
||||
'RowStatus' => $baseDir . '/core/bulkchange.class.inc.php',
|
||||
'RowStatus_Disappeared' => $baseDir . '/core/bulkchange.class.inc.php',
|
||||
'RowStatus_Error' => $baseDir . '/core/bulkchange.class.inc.php',
|
||||
'RowStatus_Issue' => $baseDir . '/core/bulkchange.class.inc.php',
|
||||
'RowStatus_Modify' => $baseDir . '/core/bulkchange.class.inc.php',
|
||||
'RowStatus_NewObj' => $baseDir . '/core/bulkchange.class.inc.php',
|
||||
'RowStatus_NoChange' => $baseDir . '/core/bulkchange.class.inc.php',
|
||||
'RowStatus' => $baseDir . '/sources/Core/BulkChange/RowStatus.php',
|
||||
'RowStatus_Disappeared' => $baseDir . '/sources/Core/BulkChange/RowStatus_Disappeared.php',
|
||||
'RowStatus_Error' => $baseDir . '/sources/Core/BulkChange/RowStatus_Error.php',
|
||||
'RowStatus_Issue' => $baseDir . '/sources/Core/BulkChange/RowStatus_Issue.php',
|
||||
'RowStatus_Modify' => $baseDir . '/sources/Core/BulkChange/RowStatus_Modify.php',
|
||||
'RowStatus_NewObj' => $baseDir . '/sources/Core/BulkChange/RowStatus_NewObj.php',
|
||||
'RowStatus_NoChange' => $baseDir . '/sources/Core/BulkChange/RowStatus_NoChange.php',
|
||||
'RunTimeIconSelectionField' => $baseDir . '/application/forms.class.inc.php',
|
||||
'RuntimeDashboard' => $baseDir . '/application/dashboard.class.inc.php',
|
||||
'SQLExpression' => $baseDir . '/core/oql/expression.class.inc.php',
|
||||
@@ -1624,23 +1624,23 @@ return array(
|
||||
'ScssPhp\\ScssPhp\\Warn' => $vendorDir . '/scssphp/scssphp/src/Warn.php',
|
||||
'SearchMenuNode' => $baseDir . '/application/menunode.class.inc.php',
|
||||
'SecurityException' => $baseDir . '/application/exceptions/SecurityException.php',
|
||||
'SeparatorPopupMenuItem' => $baseDir . '/application/applicationextension.inc.php',
|
||||
'SeparatorPopupMenuItem' => $baseDir . '/application/applicationextension/backoffice/SeparatorPopupMenuItem.php',
|
||||
'SetupLog' => $baseDir . '/core/log.class.inc.php',
|
||||
'Shortcut' => $baseDir . '/application/shortcut.class.inc.php',
|
||||
'ShortcutContainerMenuNode' => $baseDir . '/application/menunode.class.inc.php',
|
||||
'ShortcutMenuNode' => $baseDir . '/application/menunode.class.inc.php',
|
||||
'ShortcutOQL' => $baseDir . '/application/shortcut.class.inc.php',
|
||||
'SimpleCrypt' => $baseDir . '/core/simplecrypt.class.inc.php',
|
||||
'SimpleCryptMcryptEngine' => $baseDir . '/core/simplecrypt.class.inc.php',
|
||||
'SimpleCryptOpenSSLEngine' => $baseDir . '/core/simplecrypt.class.inc.php',
|
||||
'SimpleCryptOpenSSLMcryptCompatibilityEngine' => $baseDir . '/core/simplecrypt.class.inc.php',
|
||||
'SimpleCryptSimpleEngine' => $baseDir . '/core/simplecrypt.class.inc.php',
|
||||
'SimpleCryptSodiumEngine' => $baseDir . '/core/simplecrypt.class.inc.php',
|
||||
'SimpleCrypt' => $baseDir . '/sources/Application/SimpleCrypt/SimpleCrypt.php',
|
||||
'SimpleCryptMcryptEngine' => $baseDir . '/sources/Application/SimpleCrypt/SimpleCryptMcryptEngine.php',
|
||||
'SimpleCryptOpenSSLEngine' => $baseDir . '/sources/Application/SimpleCrypt/SimpleCryptOpenSSLEngine.php',
|
||||
'SimpleCryptOpenSSLMcryptCompatibilityEngine' => $baseDir . '/sources/Application/SimpleCrypt/SimpleCryptOpenSSLMcryptCompatibilityEngine.php',
|
||||
'SimpleCryptSimpleEngine' => $baseDir . '/sources/Application/SimpleCrypt/SimpleCryptSimpleEngine.php',
|
||||
'SimpleCryptSodiumEngine' => $baseDir . '/sources/Application/SimpleCrypt/SimpleCryptSodiumEngine.php',
|
||||
'SimpleGraph' => $baseDir . '/core/simplegraph.class.inc.php',
|
||||
'SimpleGraphException' => $baseDir . '/core/simplegraph.class.inc.php',
|
||||
'Soundasleep\\Html2Text' => $vendorDir . '/soundasleep/html2text/src/Html2Text.php',
|
||||
'Soundasleep\\Html2TextException' => $vendorDir . '/soundasleep/html2text/src/Html2TextException.php',
|
||||
'SpreadsheetBulkExport' => $baseDir . '/core/spreadsheetbulkexport.class.inc.php',
|
||||
'SpreadsheetBulkExport' => $baseDir . '/sources/Application/BulkExport/SpreadsheetBulkExport.php',
|
||||
'StimulusChecker' => $baseDir . '/core/userrights.class.inc.php',
|
||||
'StimulusInternal' => $baseDir . '/core/stimulus.class.inc.php',
|
||||
'StimulusUserAction' => $baseDir . '/core/stimulus.class.inc.php',
|
||||
@@ -2916,12 +2916,12 @@ return array(
|
||||
'TCPDF_IMPORT' => $vendorDir . '/tecnickcom/tcpdf/tcpdf_import.php',
|
||||
'TCPDF_PARSER' => $vendorDir . '/tecnickcom/tcpdf/tcpdf_parser.php',
|
||||
'TCPDF_STATIC' => $vendorDir . '/tecnickcom/tcpdf/include/tcpdf_static.php',
|
||||
'TabularBulkExport' => $baseDir . '/core/tabularbulkexport.class.inc.php',
|
||||
'TagSetFieldData' => $baseDir . '/core/tagsetfield.class.inc.php',
|
||||
'TabularBulkExport' => $baseDir . '/sources/Application/BulkExport/TabularBulkExport.php',
|
||||
'TagSetFieldData' => $baseDir . '/sources/Core/DataModel/TagSetFieldData.php',
|
||||
'TemplateMenuNode' => $baseDir . '/application/menunode.class.inc.php',
|
||||
'TemplateString' => $baseDir . '/core/templatestring.class.inc.php',
|
||||
'TemplateStringPlaceholder' => $baseDir . '/core/templatestring.class.inc.php',
|
||||
'TemporaryObjectDescriptor' => $baseDir . '/core/TemporaryObjectDescriptor.php',
|
||||
'TemporaryObjectDescriptor' => $baseDir . '/sources/Core/DataModel/TemporaryObjectDescriptor.php',
|
||||
'TheNetworg\\OAuth2\\Client\\Grant\\JwtBearer' => $vendorDir . '/thenetworg/oauth2-azure/src/Grant/JwtBearer.php',
|
||||
'TheNetworg\\OAuth2\\Client\\Provider\\Azure' => $vendorDir . '/thenetworg/oauth2-azure/src/Provider/Azure.php',
|
||||
'TheNetworg\\OAuth2\\Client\\Provider\\AzureResourceOwner' => $vendorDir . '/thenetworg/oauth2-azure/src/Provider/AzureResourceOwner.php',
|
||||
@@ -2929,18 +2929,18 @@ return array(
|
||||
'ThemeHandler' => $baseDir . '/application/themehandler.class.inc.php',
|
||||
'ThemeHandlerService' => $baseDir . '/application/themehandlerservice.class.inc.php',
|
||||
'ToolsLog' => $baseDir . '/core/log.class.inc.php',
|
||||
'Trigger' => $baseDir . '/core/trigger.class.inc.php',
|
||||
'TriggerOnAttributeBlobDownload' => $baseDir . '/core/trigger.class.inc.php',
|
||||
'TriggerOnObject' => $baseDir . '/core/trigger.class.inc.php',
|
||||
'TriggerOnObjectCreate' => $baseDir . '/core/trigger.class.inc.php',
|
||||
'TriggerOnObjectDelete' => $baseDir . '/core/trigger.class.inc.php',
|
||||
'TriggerOnObjectMention' => $baseDir . '/core/trigger.class.inc.php',
|
||||
'TriggerOnObjectUpdate' => $baseDir . '/core/trigger.class.inc.php',
|
||||
'TriggerOnPortalUpdate' => $baseDir . '/core/trigger.class.inc.php',
|
||||
'TriggerOnStateChange' => $baseDir . '/core/trigger.class.inc.php',
|
||||
'TriggerOnStateEnter' => $baseDir . '/core/trigger.class.inc.php',
|
||||
'TriggerOnStateLeave' => $baseDir . '/core/trigger.class.inc.php',
|
||||
'TriggerOnThresholdReached' => $baseDir . '/core/trigger.class.inc.php',
|
||||
'Trigger' => $baseDir . '/sources/Application/DataModel/TriggerAndAction/Trigger.php',
|
||||
'TriggerOnAttributeBlobDownload' => $baseDir . '/sources/Application/DataModel/TriggerAndAction/TriggerOnAttributeBlobDownload.php',
|
||||
'TriggerOnObject' => $baseDir . '/sources/Application/DataModel/TriggerAndAction/TriggerOnObject.php',
|
||||
'TriggerOnObjectCreate' => $baseDir . '/sources/Application/DataModel/TriggerAndAction/TriggerOnObjectCreate.php',
|
||||
'TriggerOnObjectDelete' => $baseDir . '/sources/Application/DataModel/TriggerAndAction/TriggerOnObjectDelete.php',
|
||||
'TriggerOnObjectMention' => $baseDir . '/sources/Application/DataModel/TriggerAndAction/TriggerOnObjectMention.php',
|
||||
'TriggerOnObjectUpdate' => $baseDir . '/sources/Application/DataModel/TriggerAndAction/TriggerOnObjectUpdate.php',
|
||||
'TriggerOnPortalUpdate' => $baseDir . '/sources/Application/DataModel/TriggerAndAction/TriggerOnPortalUpdate.php',
|
||||
'TriggerOnStateChange' => $baseDir . '/sources/Application/DataModel/TriggerAndAction/TriggerOnStateChange.php',
|
||||
'TriggerOnStateEnter' => $baseDir . '/sources/Application/DataModel/TriggerAndAction/TriggerOnStateEnter.php',
|
||||
'TriggerOnStateLeave' => $baseDir . '/sources/Application/DataModel/TriggerAndAction/TriggerOnStateLeave.php',
|
||||
'TriggerOnThresholdReached' => $baseDir . '/sources/Application/DataModel/TriggerAndAction/TriggerOnThresholdReached.php',
|
||||
'TrueExpression' => $baseDir . '/core/oql/expression.class.inc.php',
|
||||
'Twig\\AbstractTwigCallable' => $vendorDir . '/twig/twig/src/AbstractTwigCallable.php',
|
||||
'Twig\\Attribute\\FirstClassTwigCallableReady' => $vendorDir . '/twig/twig/src/Attribute/FirstClassTwigCallableReady.php',
|
||||
@@ -3156,8 +3156,8 @@ return array(
|
||||
'UIPasswordWidget' => $baseDir . '/application/ui.passwordwidget.class.inc.php',
|
||||
'UISearchFormForeignKeys' => $baseDir . '/application/ui.searchformforeignkeys.class.inc.php',
|
||||
'UIWizard' => $baseDir . '/application/uiwizard.class.inc.php',
|
||||
'URLButtonItem' => $baseDir . '/application/applicationextension.inc.php',
|
||||
'URLPopupMenuItem' => $baseDir . '/application/applicationextension.inc.php',
|
||||
'URLButtonItem' => $baseDir . '/application/applicationextension/backoffice/URLButtonItem.php',
|
||||
'URLPopupMenuItem' => $baseDir . '/application/applicationextension/backoffice/URLPopupMenuItem.php',
|
||||
'UnaryExpression' => $baseDir . '/core/oql/expression.class.inc.php',
|
||||
'UnknownClassOqlException' => $baseDir . '/core/oql/oqlinterpreter.class.inc.php',
|
||||
'User' => $baseDir . '/core/userrights.class.inc.php',
|
||||
@@ -3166,12 +3166,12 @@ return array(
|
||||
'UserRightException' => $baseDir . '/application/exceptions/UserRightException.php',
|
||||
'UserRights' => $baseDir . '/core/userrights.class.inc.php',
|
||||
'UserRightsAddOnAPI' => $baseDir . '/core/userrights.class.inc.php',
|
||||
'ValueSetDefinition' => $baseDir . '/core/valuesetdef.class.inc.php',
|
||||
'ValueSetEnum' => $baseDir . '/core/valuesetdef.class.inc.php',
|
||||
'ValueSetEnumClasses' => $baseDir . '/core/valuesetdef.class.inc.php',
|
||||
'ValueSetEnumPadded' => $baseDir . '/core/valuesetdef.class.inc.php',
|
||||
'ValueSetObjects' => $baseDir . '/core/valuesetdef.class.inc.php',
|
||||
'ValueSetRange' => $baseDir . '/core/valuesetdef.class.inc.php',
|
||||
'ValueSetDefinition' => $baseDir . '/sources/Core/ValueSetDefinition/ValueSetDefinition.php',
|
||||
'ValueSetEnum' => $baseDir . '/sources/Core/ValueSetDefinition/ValueSetEnum.php',
|
||||
'ValueSetEnumClasses' => $baseDir . '/sources/Core/ValueSetDefinition/ValueSetEnumClasses.php',
|
||||
'ValueSetEnumPadded' => $baseDir . '/sources/Core/ValueSetDefinition/ValueSetEnumPadded.php',
|
||||
'ValueSetObjects' => $baseDir . '/sources/Core/ValueSetDefinition/ValueSetObjects.php',
|
||||
'ValueSetRange' => $baseDir . '/sources/Core/ValueSetDefinition/ValueSetRange.php',
|
||||
'VariableExpression' => $baseDir . '/core/oql/expression.class.inc.php',
|
||||
'VariableOqlExpression' => $baseDir . '/core/oql/oqlquery.class.inc.php',
|
||||
'WebPageMenuNode' => $baseDir . '/application/menunode.class.inc.php',
|
||||
@@ -3181,48 +3181,48 @@ return array(
|
||||
'WeeklyRotatingLogFileNameBuilder' => $baseDir . '/core/log.class.inc.php',
|
||||
'WizardHelper' => $baseDir . '/application/wizardhelper.class.inc.php',
|
||||
'XLSXWriter' => $baseDir . '/application/xlsxwriter.class.php',
|
||||
'XMLBulkExport' => $baseDir . '/core/xmlbulkexport.class.inc.php',
|
||||
'XMLBulkExport' => $baseDir . '/sources/Application/BulkExport/XMLBulkExport.php',
|
||||
'appUserPreferences' => $baseDir . '/application/user.preferences.class.inc.php',
|
||||
'cmdbAbstractObject' => $baseDir . '/application/cmdbabstract.class.inc.php',
|
||||
'cmdbDataGenerator' => $baseDir . '/core/data.generator.class.inc.php',
|
||||
'iApplicationObjectExtension' => $baseDir . '/application/applicationextension.inc.php',
|
||||
'iApplicationUIExtension' => $baseDir . '/application/applicationextension.inc.php',
|
||||
'iAttributeNoGroupBy' => $baseDir . '/core/attributedef.class.inc.php',
|
||||
'iApplicationObjectExtension' => $baseDir . '/application/applicationextension/backoffice/iApplicationObjectExtension.php',
|
||||
'iApplicationUIExtension' => $baseDir . '/application/applicationextension/backoffice/iApplicationUIExtension.php',
|
||||
'iAttributeNoGroupBy' => $baseDir . '/sources/Core/AttributeDefinition/iAttributeNoGroupBy.php',
|
||||
'iBackgroundProcess' => $baseDir . '/core/backgroundprocess.inc.php',
|
||||
'iBackofficeDictEntriesExtension' => $baseDir . '/application/applicationextension.inc.php',
|
||||
'iBackofficeDictEntriesPrefixesExtension' => $baseDir . '/application/applicationextension.inc.php',
|
||||
'iBackofficeEarlyScriptExtension' => $baseDir . '/application/applicationextension.inc.php',
|
||||
'iBackofficeInitScriptExtension' => $baseDir . '/application/applicationextension.inc.php',
|
||||
'iBackofficeLinkedScriptsExtension' => $baseDir . '/application/applicationextension.inc.php',
|
||||
'iBackofficeLinkedStylesheetsExtension' => $baseDir . '/application/applicationextension.inc.php',
|
||||
'iBackofficeReadyScriptExtension' => $baseDir . '/application/applicationextension.inc.php',
|
||||
'iBackofficeSassExtension' => $baseDir . '/application/applicationextension.inc.php',
|
||||
'iBackofficeScriptExtension' => $baseDir . '/application/applicationextension.inc.php',
|
||||
'iBackofficeStyleExtension' => $baseDir . '/application/applicationextension.inc.php',
|
||||
'iBackupExtraFilesExtension' => $baseDir . '/application/applicationextension.inc.php',
|
||||
'iCMDBChangeOp' => $baseDir . '/core/cmdbchangeop.class.inc.php',
|
||||
'iBackofficeDictEntriesExtension' => $baseDir . '/application/applicationextension/backoffice/iBackofficeDictEntriesExtension.php',
|
||||
'iBackofficeDictEntriesPrefixesExtension' => $baseDir . '/application/applicationextension/backoffice/iBackofficeDictEntriesPrefixesExtension.php',
|
||||
'iBackofficeEarlyScriptExtension' => $baseDir . '/application/applicationextension/backoffice/iBackofficeEarlyScriptExtension.php',
|
||||
'iBackofficeInitScriptExtension' => $baseDir . '/application/applicationextension/backoffice/iBackofficeInitScriptExtension.php',
|
||||
'iBackofficeLinkedScriptsExtension' => $baseDir . '/application/applicationextension/backoffice/iBackofficeLinkedScriptsExtension.php',
|
||||
'iBackofficeLinkedStylesheetsExtension' => $baseDir . '/application/applicationextension/backoffice/iBackofficeLinkedStylesheetsExtension.php',
|
||||
'iBackofficeReadyScriptExtension' => $baseDir . '/application/applicationextension/backoffice/iBackofficeReadyScriptExtension.php',
|
||||
'iBackofficeSassExtension' => $baseDir . '/application/applicationextension/backoffice/iBackofficeSassExtension.php',
|
||||
'iBackofficeScriptExtension' => $baseDir . '/application/applicationextension/backoffice/iBackofficeScriptExtension.php',
|
||||
'iBackofficeStyleExtension' => $baseDir . '/application/applicationextension/backoffice/iBackofficeStyleExtension.php',
|
||||
'iBackupExtraFilesExtension' => $baseDir . '/application/applicationextension/iBackupExtraFilesExtension.php',
|
||||
'iCMDBChangeOp' => $baseDir . '/sources/Core/DataModel/CMDBChange/iCMDBChangeOp.php',
|
||||
'iDBObjectSetIterator' => $baseDir . '/core/dbobjectiterator.php',
|
||||
'iDBObjectURLMaker' => $baseDir . '/application/applicationcontext.class.inc.php',
|
||||
'iDisplay' => $baseDir . '/core/dbobject.class.php',
|
||||
'iFieldRendererMappingsExtension' => $baseDir . '/application/applicationextension.inc.php',
|
||||
'iKPILoggerExtension' => $baseDir . '/application/applicationextension.inc.php',
|
||||
'iFieldRendererMappingsExtension' => $baseDir . '/application/applicationextension/backoffice/iFieldRendererMappingsExtension.php',
|
||||
'iKPILoggerExtension' => $baseDir . '/application/applicationextension/iKPILoggerExtension.php',
|
||||
'iLogFileNameBuilder' => $baseDir . '/core/log.class.inc.php',
|
||||
'iLoginExtension' => $baseDir . '/application/applicationextension.inc.php',
|
||||
'iLoginFSMExtension' => $baseDir . '/application/applicationextension.inc.php',
|
||||
'iLoginUIExtension' => $baseDir . '/application/applicationextension.inc.php',
|
||||
'iLogoutExtension' => $baseDir . '/application/applicationextension.inc.php',
|
||||
'iLoginExtension' => $baseDir . '/application/applicationextension/login/iLoginExtension.php',
|
||||
'iLoginFSMExtension' => $baseDir . '/application/applicationextension/login/iLoginFSMExtension.php',
|
||||
'iLoginUIExtension' => $baseDir . '/application/applicationextension/login/iLoginUIExtension.php',
|
||||
'iLogoutExtension' => $baseDir . '/application/applicationextension/login/iLogoutExtension.php',
|
||||
'iMetricComputer' => $baseDir . '/core/computing.inc.php',
|
||||
'iModuleExtension' => $baseDir . '/application/applicationextension.inc.php',
|
||||
'iModuleExtension' => $baseDir . '/application/applicationextension/iModuleExtension.php',
|
||||
'iNewsroomProvider' => $baseDir . '/application/newsroomprovider.class.inc.php',
|
||||
'iOnClassInitialization' => $baseDir . '/core/metamodelmodifier.inc.php',
|
||||
'iPageUIBlockExtension' => $baseDir . '/application/applicationextension.inc.php',
|
||||
'iPopupMenuExtension' => $baseDir . '/application/applicationextension.inc.php',
|
||||
'iPortalUIExtension' => $baseDir . '/application/applicationextension.inc.php',
|
||||
'iPreferencesExtension' => $baseDir . '/application/applicationextension.inc.php',
|
||||
'iPageUIBlockExtension' => $baseDir . '/application/applicationextension/backoffice/iPageUIBlockExtension.php',
|
||||
'iPopupMenuExtension' => $baseDir . '/application/applicationextension/backoffice/iPopupMenuExtension.php',
|
||||
'iPortalUIExtension' => $baseDir . '/application/applicationextension/portal/iPortalUIExtension.php',
|
||||
'iPreferencesExtension' => $baseDir . '/application/applicationextension/backoffice/iPreferencesExtension.php',
|
||||
'iProcess' => $baseDir . '/core/backgroundprocess.inc.php',
|
||||
'iQueryModifier' => $baseDir . '/core/querymodifier.class.inc.php',
|
||||
'iRestInputSanitizer' => $baseDir . '/application/applicationextension.inc.php',
|
||||
'iRestServiceProvider' => $baseDir . '/application/applicationextension.inc.php',
|
||||
'iRestInputSanitizer' => $baseDir . '/application/applicationextension/rest/iRestInputSanitizer.php',
|
||||
'iRestServiceProvider' => $baseDir . '/application/applicationextension/rest/iRestServiceProvider.php',
|
||||
'iScheduledProcess' => $baseDir . '/core/backgroundprocess.inc.php',
|
||||
'iSelfRegister' => $baseDir . '/core/userrights.class.inc.php',
|
||||
'iTopConfigParser' => $baseDir . '/core/iTopConfigParser.php',
|
||||
@@ -3231,19 +3231,19 @@ return array(
|
||||
'iTopOwnershipToken' => $baseDir . '/core/ownershiplock.class.inc.php',
|
||||
'iTopStandardURLMaker' => $baseDir . '/application/applicationcontext.class.inc.php',
|
||||
'iTopXmlException' => $baseDir . '/application/exceptions/iTopXmlException.php',
|
||||
'iWelcomePopupExtension' => $baseDir . '/application/applicationextension.inc.php',
|
||||
'iWelcomePopupExtension' => $baseDir . '/application/applicationextension/backoffice/iWelcomePopupExtension.php',
|
||||
'iWorkingTimeComputer' => $baseDir . '/core/computing.inc.php',
|
||||
'lnkAuditCategoryToAuditDomain' => $baseDir . '/application/audit.domain.class.inc.php',
|
||||
'lnkTriggerAction' => $baseDir . '/core/trigger.class.inc.php',
|
||||
'ormCaseLog' => $baseDir . '/core/ormcaselog.class.inc.php',
|
||||
'ormCustomFieldsValue' => $baseDir . '/core/ormcustomfieldsvalue.class.inc.php',
|
||||
'ormDocument' => $baseDir . '/core/ormdocument.class.inc.php',
|
||||
'ormLinkSet' => $baseDir . '/core/ormlinkset.class.inc.php',
|
||||
'ormPassword' => $baseDir . '/core/ormpassword.class.inc.php',
|
||||
'ormSet' => $baseDir . '/core/ormset.class.inc.php',
|
||||
'ormStopWatch' => $baseDir . '/core/ormstopwatch.class.inc.php',
|
||||
'ormStyle' => $baseDir . '/core/ormStyle.class.inc.php',
|
||||
'ormTagSet' => $baseDir . '/core/ormtagset.class.inc.php',
|
||||
'lnkTriggerAction' => $baseDir . '/sources/Application/DataModel/TriggerAndAction/lnkTriggerAction.php',
|
||||
'ormCaseLog' => $baseDir . '/sources/Core/Orm/ormCaseLog.php',
|
||||
'ormCustomFieldsValue' => $baseDir . '/sources/Core/Orm/ormCustomFieldsValue.php',
|
||||
'ormDocument' => $baseDir . '/sources/Core/Orm/ormDocument.php',
|
||||
'ormLinkSet' => $baseDir . '/sources/Core/Orm/ormLinkSet.php',
|
||||
'ormPassword' => $baseDir . '/sources/Core/Orm/ormPassword.php',
|
||||
'ormSet' => $baseDir . '/sources/Core/Orm/ormSet.php',
|
||||
'ormStopWatch' => $baseDir . '/sources/Core/Orm/ormStopWatch.php',
|
||||
'ormStyle' => $baseDir . '/sources/Core/Orm/ormStyle.php',
|
||||
'ormTagSet' => $baseDir . '/sources/Core/Orm/ormTagSet.php',
|
||||
'phpCAS' => $vendorDir . '/apereo/phpcas/source/CAS.php',
|
||||
'privUITransaction' => $baseDir . '/application/transaction.class.inc.php',
|
||||
'privUITransactionFile' => $baseDir . '/application/transaction.class.inc.php',
|
||||
|
||||
@@ -384,99 +384,99 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
|
||||
);
|
||||
|
||||
public static $classMap = array (
|
||||
'AbstractApplicationObjectExtension' => __DIR__ . '/../..' . '/application/applicationextension.inc.php',
|
||||
'AbstractApplicationUIExtension' => __DIR__ . '/../..' . '/application/applicationextension.inc.php',
|
||||
'AbstractLoginFSMExtension' => __DIR__ . '/../..' . '/application/applicationextension.inc.php',
|
||||
'AbstractPageUIBlockExtension' => __DIR__ . '/../..' . '/application/applicationextension.inc.php',
|
||||
'AbstractPortalUIExtension' => __DIR__ . '/../..' . '/application/applicationextension.inc.php',
|
||||
'AbstractPreferencesExtension' => __DIR__ . '/../..' . '/application/applicationextension.inc.php',
|
||||
'AbstractApplicationObjectExtension' => __DIR__ . '/../..' . '/application/applicationextension/backoffice/AbstractApplicationObjectExtension.php',
|
||||
'AbstractApplicationUIExtension' => __DIR__ . '/../..' . '/application/applicationextension/backoffice/AbstractApplicationUIExtension.php',
|
||||
'AbstractLoginFSMExtension' => __DIR__ . '/../..' . '/application/applicationextension/login/AbstractLoginFSMExtension.php',
|
||||
'AbstractPageUIBlockExtension' => __DIR__ . '/../..' . '/application/applicationextension/backoffice/AbstractPageUIBlockExtension.php',
|
||||
'AbstractPortalUIExtension' => __DIR__ . '/../..' . '/application/applicationextension/portal/AbstractPortalUIExtension.php',
|
||||
'AbstractPreferencesExtension' => __DIR__ . '/../..' . '/application/applicationextension/backoffice/AbstractPreferencesExtension.php',
|
||||
'AbstractWeeklyScheduledProcess' => __DIR__ . '/../..' . '/core/backgroundprocess.inc.php',
|
||||
'AbstractWelcomePopupExtension' => __DIR__ . '/../..' . '/application/applicationextension.inc.php',
|
||||
'Action' => __DIR__ . '/../..' . '/core/action.class.inc.php',
|
||||
'AbstractWelcomePopupExtension' => __DIR__ . '/../..' . '/application/applicationextension/backoffice/AbstractWelcomePopupExtension.php',
|
||||
'Action' => __DIR__ . '/../..' . '/sources/Application/DataModel/TriggerAndAction/Action.php',
|
||||
'ActionChecker' => __DIR__ . '/../..' . '/core/userrights.class.inc.php',
|
||||
'ActionEmail' => __DIR__ . '/../..' . '/core/action.class.inc.php',
|
||||
'ActionNotification' => __DIR__ . '/../..' . '/core/action.class.inc.php',
|
||||
'ActionEmail' => __DIR__ . '/../..' . '/sources/Application/DataModel/TriggerAndAction/ActionEmail.php',
|
||||
'ActionNotification' => __DIR__ . '/../..' . '/sources/Application/DataModel/TriggerAndAction/ActionNotification.php',
|
||||
'ApcService' => __DIR__ . '/../..' . '/core/apc-service.class.inc.php',
|
||||
'ApplicationContext' => __DIR__ . '/../..' . '/application/applicationcontext.class.inc.php',
|
||||
'ApplicationException' => __DIR__ . '/../..' . '/application/exceptions/ApplicationException.php',
|
||||
'ApplicationMenu' => __DIR__ . '/../..' . '/application/menunode.class.inc.php',
|
||||
'ApplicationPopupMenuItem' => __DIR__ . '/../..' . '/application/applicationextension.inc.php',
|
||||
'ApplicationPopupMenuItem' => __DIR__ . '/../..' . '/application/applicationextension/backoffice/ApplicationPopupMenuItem.php',
|
||||
'Archive_Tar' => __DIR__ . '/..' . '/pear/archive_tar/Archive/Tar.php',
|
||||
'ArchivedObjectException' => __DIR__ . '/../..' . '/application/exceptions/ArchivedObjectException.php',
|
||||
'AsyncSendEmail' => __DIR__ . '/../..' . '/core/asynctask.class.inc.php',
|
||||
'AsyncSendNewsroom' => __DIR__ . '/../..' . '/core/asynctask.class.inc.php',
|
||||
'AsyncTask' => __DIR__ . '/../..' . '/core/asynctask.class.inc.php',
|
||||
'AttributeApplicationLanguage' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php',
|
||||
'AttributeArchiveDate' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php',
|
||||
'AttributeArchiveFlag' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php',
|
||||
'AttributeBlob' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php',
|
||||
'AttributeBoolean' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php',
|
||||
'AttributeCaseLog' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php',
|
||||
'AttributeClass' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php',
|
||||
'AttributeClassAttCodeSet' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php',
|
||||
'AttributeClassState' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php',
|
||||
'AttributeCustomFields' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php',
|
||||
'AttributeDBField' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php',
|
||||
'AttributeDBFieldVoid' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php',
|
||||
'AttributeDashboard' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php',
|
||||
'AttributeDate' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php',
|
||||
'AttributeDateTime' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php',
|
||||
'AttributeDeadline' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php',
|
||||
'AttributeDecimal' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php',
|
||||
'AttributeDefinition' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php',
|
||||
'AttributeDuration' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php',
|
||||
'AttributeEmailAddress' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php',
|
||||
'AttributeEncryptedString' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php',
|
||||
'AttributeEnum' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php',
|
||||
'AttributeEnumSet' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php',
|
||||
'AttributeExternalField' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php',
|
||||
'AttributeExternalKey' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php',
|
||||
'AttributeFinalClass' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php',
|
||||
'AttributeFriendlyName' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php',
|
||||
'AttributeHTML' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php',
|
||||
'AttributeHierarchicalKey' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php',
|
||||
'AttributeIPAddress' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php',
|
||||
'AttributeImage' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php',
|
||||
'AttributeInteger' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php',
|
||||
'AttributeLinkedSet' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php',
|
||||
'AttributeLinkedSetIndirect' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php',
|
||||
'AttributeLongText' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php',
|
||||
'AttributeMetaEnum' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php',
|
||||
'AttributeOQL' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php',
|
||||
'AttributeObjectKey' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php',
|
||||
'AttributeObsolescenceDate' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php',
|
||||
'AttributeObsolescenceFlag' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php',
|
||||
'AttributeOneWayPassword' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php',
|
||||
'AttributePassword' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php',
|
||||
'AttributePercentage' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php',
|
||||
'AttributePhoneNumber' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php',
|
||||
'AttributePropertySet' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php',
|
||||
'AttributeQueryAttCodeSet' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php',
|
||||
'AttributeRedundancySettings' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php',
|
||||
'AttributeSet' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php',
|
||||
'AttributeStopWatch' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php',
|
||||
'AttributeString' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php',
|
||||
'AttributeSubItem' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php',
|
||||
'AttributeTable' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php',
|
||||
'AttributeTagSet' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php',
|
||||
'AttributeTemplateHTML' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php',
|
||||
'AttributeTemplateString' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php',
|
||||
'AttributeTemplateText' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php',
|
||||
'AttributeText' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php',
|
||||
'AttributeURL' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php',
|
||||
'AsyncSendEmail' => __DIR__ . '/../..' . '/sources/Core/DataModel/AsyncTask/AsyncSendEmail.php',
|
||||
'AsyncSendNewsroom' => __DIR__ . '/../..' . '/sources/Core/DataModel/AsyncTask/AsyncSendNewsroom.php',
|
||||
'AsyncTask' => __DIR__ . '/../..' . '/sources/Core/DataModel/AsyncTask/AsyncTask.php',
|
||||
'AttributeApplicationLanguage' => __DIR__ . '/../..' . '/sources/Core/AttributeDefinition/AttributeApplicationLanguage.php',
|
||||
'AttributeArchiveDate' => __DIR__ . '/../..' . '/sources/Core/AttributeDefinition/AttributeArchiveDate.php',
|
||||
'AttributeArchiveFlag' => __DIR__ . '/../..' . '/sources/Core/AttributeDefinition/AttributeArchiveFlag.php',
|
||||
'AttributeBlob' => __DIR__ . '/../..' . '/sources/Core/AttributeDefinition/AttributeBlob.php',
|
||||
'AttributeBoolean' => __DIR__ . '/../..' . '/sources/Core/AttributeDefinition/AttributeBoolean.php',
|
||||
'AttributeCaseLog' => __DIR__ . '/../..' . '/sources/Core/AttributeDefinition/AttributeCaseLog.php',
|
||||
'AttributeClass' => __DIR__ . '/../..' . '/sources/Core/AttributeDefinition/AttributeClass.php',
|
||||
'AttributeClassAttCodeSet' => __DIR__ . '/../..' . '/sources/Core/AttributeDefinition/AttributeClassAttCodeSet.php',
|
||||
'AttributeClassState' => __DIR__ . '/../..' . '/sources/Core/AttributeDefinition/AttributeClassState.php',
|
||||
'AttributeCustomFields' => __DIR__ . '/../..' . '/sources/Core/AttributeDefinition/AttributeCustomFields.php',
|
||||
'AttributeDBField' => __DIR__ . '/../..' . '/sources/Core/AttributeDefinition/AttributeDBField.php',
|
||||
'AttributeDBFieldVoid' => __DIR__ . '/../..' . '/sources/Core/AttributeDefinition/AttributeDBFieldVoid.php',
|
||||
'AttributeDashboard' => __DIR__ . '/../..' . '/sources/Core/AttributeDefinition/AttributeDashboard.php',
|
||||
'AttributeDate' => __DIR__ . '/../..' . '/sources/Core/AttributeDefinition/AttributeDate.php',
|
||||
'AttributeDateTime' => __DIR__ . '/../..' . '/sources/Core/AttributeDefinition/AttributeDateTime.php',
|
||||
'AttributeDeadline' => __DIR__ . '/../..' . '/sources/Core/AttributeDefinition/AttributeDeadline.php',
|
||||
'AttributeDecimal' => __DIR__ . '/../..' . '/sources/Core/AttributeDefinition/AttributeDecimal.php',
|
||||
'AttributeDefinition' => __DIR__ . '/../..' . '/sources/Core/AttributeDefinition/AttributeDefinition.php',
|
||||
'AttributeDuration' => __DIR__ . '/../..' . '/sources/Core/AttributeDefinition/AttributeDuration.php',
|
||||
'AttributeEmailAddress' => __DIR__ . '/../..' . '/sources/Core/AttributeDefinition/AttributeEmailAddress.php',
|
||||
'AttributeEncryptedString' => __DIR__ . '/../..' . '/sources/Core/AttributeDefinition/AttributeEncryptedString.php',
|
||||
'AttributeEnum' => __DIR__ . '/../..' . '/sources/Core/AttributeDefinition/AttributeEnum.php',
|
||||
'AttributeEnumSet' => __DIR__ . '/../..' . '/sources/Core/AttributeDefinition/AttributeEnumSet.php',
|
||||
'AttributeExternalField' => __DIR__ . '/../..' . '/sources/Core/AttributeDefinition/AttributeExternalField.php',
|
||||
'AttributeExternalKey' => __DIR__ . '/../..' . '/sources/Core/AttributeDefinition/AttributeExternalKey.php',
|
||||
'AttributeFinalClass' => __DIR__ . '/../..' . '/sources/Core/AttributeDefinition/AttributeFinalClass.php',
|
||||
'AttributeFriendlyName' => __DIR__ . '/../..' . '/sources/Core/AttributeDefinition/AttributeFriendlyName.php',
|
||||
'AttributeHTML' => __DIR__ . '/../..' . '/sources/Core/AttributeDefinition/AttributeHTML.php',
|
||||
'AttributeHierarchicalKey' => __DIR__ . '/../..' . '/sources/Core/AttributeDefinition/AttributeHierarchicalKey.php',
|
||||
'AttributeIPAddress' => __DIR__ . '/../..' . '/sources/Core/AttributeDefinition/AttributeIPAddress.php',
|
||||
'AttributeImage' => __DIR__ . '/../..' . '/sources/Core/AttributeDefinition/AttributeImage.php',
|
||||
'AttributeInteger' => __DIR__ . '/../..' . '/sources/Core/AttributeDefinition/AttributeInteger.php',
|
||||
'AttributeLinkedSet' => __DIR__ . '/../..' . '/sources/Core/AttributeDefinition/AttributeLinkedSet.php',
|
||||
'AttributeLinkedSetIndirect' => __DIR__ . '/../..' . '/sources/Core/AttributeDefinition/AttributeLinkedSetIndirect.php',
|
||||
'AttributeLongText' => __DIR__ . '/../..' . '/sources/Core/AttributeDefinition/AttributeLongText.php',
|
||||
'AttributeMetaEnum' => __DIR__ . '/../..' . '/sources/Core/AttributeDefinition/AttributeMetaEnum.php',
|
||||
'AttributeOQL' => __DIR__ . '/../..' . '/sources/Core/AttributeDefinition/AttributeOQL.php',
|
||||
'AttributeObjectKey' => __DIR__ . '/../..' . '/sources/Core/AttributeDefinition/AttributeObjectKey.php',
|
||||
'AttributeObsolescenceDate' => __DIR__ . '/../..' . '/sources/Core/AttributeDefinition/AttributeObsolescenceDate.php',
|
||||
'AttributeObsolescenceFlag' => __DIR__ . '/../..' . '/sources/Core/AttributeDefinition/AttributeObsolescenceFlag.php',
|
||||
'AttributeOneWayPassword' => __DIR__ . '/../..' . '/sources/Core/AttributeDefinition/AttributeOneWayPassword.php',
|
||||
'AttributePassword' => __DIR__ . '/../..' . '/sources/Core/AttributeDefinition/AttributePassword.php',
|
||||
'AttributePercentage' => __DIR__ . '/../..' . '/sources/Core/AttributeDefinition/AttributePercentage.php',
|
||||
'AttributePhoneNumber' => __DIR__ . '/../..' . '/sources/Core/AttributeDefinition/AttributePhoneNumber.php',
|
||||
'AttributePropertySet' => __DIR__ . '/../..' . '/sources/Core/AttributeDefinition/AttributePropertySet.php',
|
||||
'AttributeQueryAttCodeSet' => __DIR__ . '/../..' . '/sources/Core/AttributeDefinition/AttributeQueryAttCodeSet.php',
|
||||
'AttributeRedundancySettings' => __DIR__ . '/../..' . '/sources/Core/AttributeDefinition/AttributeRedundancySettings.php',
|
||||
'AttributeSet' => __DIR__ . '/../..' . '/sources/Core/AttributeDefinition/AttributeSet.php',
|
||||
'AttributeStopWatch' => __DIR__ . '/../..' . '/sources/Core/AttributeDefinition/AttributeStopWatch.php',
|
||||
'AttributeString' => __DIR__ . '/../..' . '/sources/Core/AttributeDefinition/AttributeString.php',
|
||||
'AttributeSubItem' => __DIR__ . '/../..' . '/sources/Core/AttributeDefinition/AttributeSubItem.php',
|
||||
'AttributeTable' => __DIR__ . '/../..' . '/sources/Core/AttributeDefinition/AttributeTable.php',
|
||||
'AttributeTagSet' => __DIR__ . '/../..' . '/sources/Core/AttributeDefinition/AttributeTagSet.php',
|
||||
'AttributeTemplateHTML' => __DIR__ . '/../..' . '/sources/Core/AttributeDefinition/AttributeTemplateHTML.php',
|
||||
'AttributeTemplateString' => __DIR__ . '/../..' . '/sources/Core/AttributeDefinition/AttributeTemplateString.php',
|
||||
'AttributeTemplateText' => __DIR__ . '/../..' . '/sources/Core/AttributeDefinition/AttributeTemplateText.php',
|
||||
'AttributeText' => __DIR__ . '/../..' . '/sources/Core/AttributeDefinition/AttributeText.php',
|
||||
'AttributeURL' => __DIR__ . '/../..' . '/sources/Core/AttributeDefinition/AttributeURL.php',
|
||||
'AuditCategory' => __DIR__ . '/../..' . '/application/audit.category.class.inc.php',
|
||||
'AuditDomain' => __DIR__ . '/../..' . '/application/audit.domain.class.inc.php',
|
||||
'AuditRule' => __DIR__ . '/../..' . '/application/audit.rule.class.inc.php',
|
||||
'BackgroundTask' => __DIR__ . '/../..' . '/core/backgroundtask.class.inc.php',
|
||||
'BackgroundTask' => __DIR__ . '/../..' . '/sources/Core/DataModel/BackgroundTask.php',
|
||||
'BinaryExpression' => __DIR__ . '/../..' . '/core/oql/expression.class.inc.php',
|
||||
'BinaryOqlExpression' => __DIR__ . '/../..' . '/core/oql/oqlquery.class.inc.php',
|
||||
'BulkChange' => __DIR__ . '/../..' . '/core/bulkchange.class.inc.php',
|
||||
'BulkChange' => __DIR__ . '/../..' . '/sources/Core/BulkChange/BulkChange.php',
|
||||
'BulkChangeException' => __DIR__ . '/../..' . '/application/exceptions/BulkChangeException.php',
|
||||
'BulkExport' => __DIR__ . '/../..' . '/core/bulkexport.class.inc.php',
|
||||
'BulkExportException' => __DIR__ . '/../..' . '/core/bulkexport.class.inc.php',
|
||||
'BulkExportMissingParameterException' => __DIR__ . '/../..' . '/core/bulkexport.class.inc.php',
|
||||
'BulkExportResult' => __DIR__ . '/../..' . '/core/bulkexport.class.inc.php',
|
||||
'BulkExportResultGC' => __DIR__ . '/../..' . '/core/bulkexport.class.inc.php',
|
||||
'BulkExport' => __DIR__ . '/../..' . '/sources/Application/BulkExport/BulkExport.php',
|
||||
'BulkExportException' => __DIR__ . '/../..' . '/sources/Application/BulkExport/BulkExportException.php',
|
||||
'BulkExportMissingParameterException' => __DIR__ . '/../..' . '/sources/Application/BulkExport/BulkExportMissingParameterException.php',
|
||||
'BulkExportResult' => __DIR__ . '/../..' . '/sources/Core/DataModel/BulkExportResult.php',
|
||||
'BulkExportResultGC' => __DIR__ . '/../..' . '/sources/Application/BulkExport/BulkExportResultGC.php',
|
||||
'CAS_AuthenticationException' => __DIR__ . '/..' . '/apereo/phpcas/source/CAS/AuthenticationException.php',
|
||||
'CAS_Client' => __DIR__ . '/..' . '/apereo/phpcas/source/CAS/Client.php',
|
||||
'CAS_CookieJar' => __DIR__ . '/..' . '/apereo/phpcas/source/CAS/CookieJar.php',
|
||||
@@ -529,25 +529,25 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
|
||||
'CAS_Session_PhpSession' => __DIR__ . '/..' . '/apereo/phpcas/source/CAS/Session/PhpSession.php',
|
||||
'CAS_TypeMismatchException' => __DIR__ . '/..' . '/apereo/phpcas/source/CAS/TypeMismatchException.php',
|
||||
'CMDBChange' => __DIR__ . '/../..' . '/core/cmdbchange.class.inc.php',
|
||||
'CMDBChangeOp' => __DIR__ . '/../..' . '/core/cmdbchangeop.class.inc.php',
|
||||
'CMDBChangeOpCreate' => __DIR__ . '/../..' . '/core/cmdbchangeop.class.inc.php',
|
||||
'CMDBChangeOpDelete' => __DIR__ . '/../..' . '/core/cmdbchangeop.class.inc.php',
|
||||
'CMDBChangeOpPlugin' => __DIR__ . '/../..' . '/core/cmdbchangeop.class.inc.php',
|
||||
'CMDBChangeOpSetAttribute' => __DIR__ . '/../..' . '/core/cmdbchangeop.class.inc.php',
|
||||
'CMDBChangeOpSetAttributeBlob' => __DIR__ . '/../..' . '/core/cmdbchangeop.class.inc.php',
|
||||
'CMDBChangeOpSetAttributeCaseLog' => __DIR__ . '/../..' . '/core/cmdbchangeop.class.inc.php',
|
||||
'CMDBChangeOpSetAttributeCustomFields' => __DIR__ . '/../..' . '/core/cmdbchangeop.class.inc.php',
|
||||
'CMDBChangeOpSetAttributeEncrypted' => __DIR__ . '/../..' . '/core/cmdbchangeop.class.inc.php',
|
||||
'CMDBChangeOpSetAttributeHTML' => __DIR__ . '/../..' . '/core/cmdbchangeop.class.inc.php',
|
||||
'CMDBChangeOpSetAttributeLinks' => __DIR__ . '/../..' . '/core/cmdbchangeop.class.inc.php',
|
||||
'CMDBChangeOpSetAttributeLinksAddRemove' => __DIR__ . '/../..' . '/core/cmdbchangeop.class.inc.php',
|
||||
'CMDBChangeOpSetAttributeLinksTune' => __DIR__ . '/../..' . '/core/cmdbchangeop.class.inc.php',
|
||||
'CMDBChangeOpSetAttributeLongText' => __DIR__ . '/../..' . '/core/cmdbchangeop.class.inc.php',
|
||||
'CMDBChangeOpSetAttributeOneWayPassword' => __DIR__ . '/../..' . '/core/cmdbchangeop.class.inc.php',
|
||||
'CMDBChangeOpSetAttributeScalar' => __DIR__ . '/../..' . '/core/cmdbchangeop.class.inc.php',
|
||||
'CMDBChangeOpSetAttributeTagSet' => __DIR__ . '/../..' . '/core/cmdbchangeop.class.inc.php',
|
||||
'CMDBChangeOpSetAttributeText' => __DIR__ . '/../..' . '/core/cmdbchangeop.class.inc.php',
|
||||
'CMDBChangeOpSetAttributeURL' => __DIR__ . '/../..' . '/core/cmdbchangeop.class.inc.php',
|
||||
'CMDBChangeOp' => __DIR__ . '/../..' . '/sources/Core/DataModel/CMDBChange/CMDBChangeOp.php',
|
||||
'CMDBChangeOpCreate' => __DIR__ . '/../..' . '/sources/Core/DataModel/CMDBChange/CMDBChangeOpCreate.php',
|
||||
'CMDBChangeOpDelete' => __DIR__ . '/../..' . '/sources/Core/DataModel/CMDBChange/CMDBChangeOpDelete.php',
|
||||
'CMDBChangeOpPlugin' => __DIR__ . '/../..' . '/sources/Core/DataModel/CMDBChange/CMDBChangeOpPlugin.php',
|
||||
'CMDBChangeOpSetAttribute' => __DIR__ . '/../..' . '/sources/Core/DataModel/CMDBChange/CMDBChangeOpSetAttribute.php',
|
||||
'CMDBChangeOpSetAttributeBlob' => __DIR__ . '/../..' . '/sources/Core/DataModel/CMDBChange/CMDBChangeOpSetAttributeBlob.php',
|
||||
'CMDBChangeOpSetAttributeCaseLog' => __DIR__ . '/../..' . '/sources/Core/DataModel/CMDBChange/CMDBChangeOpSetAttributeCaseLog.php',
|
||||
'CMDBChangeOpSetAttributeCustomFields' => __DIR__ . '/../..' . '/sources/Core/DataModel/CMDBChange/CMDBChangeOpSetAttributeCustomFields.php',
|
||||
'CMDBChangeOpSetAttributeEncrypted' => __DIR__ . '/../..' . '/sources/Core/DataModel/CMDBChange/CMDBChangeOpSetAttributeEncrypted.php',
|
||||
'CMDBChangeOpSetAttributeHTML' => __DIR__ . '/../..' . '/sources/Core/DataModel/CMDBChange/CMDBChangeOpSetAttributeHTML.php',
|
||||
'CMDBChangeOpSetAttributeLinks' => __DIR__ . '/../..' . '/sources/Core/DataModel/CMDBChange/CMDBChangeOpSetAttributeLinks.php',
|
||||
'CMDBChangeOpSetAttributeLinksAddRemove' => __DIR__ . '/../..' . '/sources/Core/DataModel/CMDBChange/CMDBChangeOpSetAttributeLinksAddRemove.php',
|
||||
'CMDBChangeOpSetAttributeLinksTune' => __DIR__ . '/../..' . '/sources/Core/DataModel/CMDBChange/CMDBChangeOpSetAttributeLinksTune.php',
|
||||
'CMDBChangeOpSetAttributeLongText' => __DIR__ . '/../..' . '/sources/Core/DataModel/CMDBChange/CMDBChangeOpSetAttributeLongText.php',
|
||||
'CMDBChangeOpSetAttributeOneWayPassword' => __DIR__ . '/../..' . '/sources/Core/DataModel/CMDBChange/CMDBChangeOpSetAttributeOneWayPassword.php',
|
||||
'CMDBChangeOpSetAttributeScalar' => __DIR__ . '/../..' . '/sources/Core/DataModel/CMDBChange/CMDBChangeOpSetAttributeScalar.php',
|
||||
'CMDBChangeOpSetAttributeTagSet' => __DIR__ . '/../..' . '/sources/Core/DataModel/CMDBChange/CMDBChangeOpSetAttributeTagSet.php',
|
||||
'CMDBChangeOpSetAttributeText' => __DIR__ . '/../..' . '/sources/Core/DataModel/CMDBChange/CMDBChangeOpSetAttributeText.php',
|
||||
'CMDBChangeOpSetAttributeURL' => __DIR__ . '/../..' . '/sources/Core/DataModel/CMDBChange/CMDBChangeOpSetAttributeURL.php',
|
||||
'CMDBObject' => __DIR__ . '/../..' . '/core/cmdbobject.class.inc.php',
|
||||
'CMDBObjectSet' => __DIR__ . '/../..' . '/core/cmdbobject.class.inc.php',
|
||||
'CMDBSource' => __DIR__ . '/../..' . '/core/cmdbsource.class.inc.php',
|
||||
@@ -555,16 +555,16 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
|
||||
'CSVParser' => __DIR__ . '/../..' . '/core/csvparser.class.inc.php',
|
||||
'CSVParserException' => __DIR__ . '/../..' . '/application/exceptions/CSVParserException.php',
|
||||
'CURLStringFile' => __DIR__ . '/..' . '/symfony/polyfill-php81/Resources/stubs/CURLStringFile.php',
|
||||
'CellChangeSpec' => __DIR__ . '/../..' . '/core/bulkchange.class.inc.php',
|
||||
'CellStatus_Ambiguous' => __DIR__ . '/../..' . '/core/bulkchange.class.inc.php',
|
||||
'CellStatus_Issue' => __DIR__ . '/../..' . '/core/bulkchange.class.inc.php',
|
||||
'CellStatus_Modify' => __DIR__ . '/../..' . '/core/bulkchange.class.inc.php',
|
||||
'CellStatus_NullIssue' => __DIR__ . '/../..' . '/core/bulkchange.class.inc.php',
|
||||
'CellStatus_SearchIssue' => __DIR__ . '/../..' . '/core/bulkchange.class.inc.php',
|
||||
'CellStatus_Void' => __DIR__ . '/../..' . '/core/bulkchange.class.inc.php',
|
||||
'CellChangeSpec' => __DIR__ . '/../..' . '/sources/Core/BulkChange/CellChangeSpec.php',
|
||||
'CellStatus_Ambiguous' => __DIR__ . '/../..' . '/sources/Core/BulkChange/CellStatus_Ambiguous.php',
|
||||
'CellStatus_Issue' => __DIR__ . '/../..' . '/sources/Core/BulkChange/CellStatus_Issue.php',
|
||||
'CellStatus_Modify' => __DIR__ . '/../..' . '/sources/Core/BulkChange/CellStatus_Modify.php',
|
||||
'CellStatus_NullIssue' => __DIR__ . '/../..' . '/sources/Core/BulkChange/CellStatus_NullIssue.php',
|
||||
'CellStatus_SearchIssue' => __DIR__ . '/../..' . '/sources/Core/BulkChange/CellStatus_SearchIssue.php',
|
||||
'CellStatus_Void' => __DIR__ . '/../..' . '/sources/Core/BulkChange/CellStatus_Void.php',
|
||||
'CharConcatExpression' => __DIR__ . '/../..' . '/core/oql/expression.class.inc.php',
|
||||
'CharConcatWSExpression' => __DIR__ . '/../..' . '/core/oql/expression.class.inc.php',
|
||||
'CheckStopWatchThresholds' => __DIR__ . '/../..' . '/core/ormstopwatch.class.inc.php',
|
||||
'CheckStopWatchThresholds' => __DIR__ . '/../..' . '/sources/Core/Orm/ormStopWatch.php',
|
||||
'CheckableExpression' => __DIR__ . '/../..' . '/core/oql/oqlquery.class.inc.php',
|
||||
'Combodo\\iTop\\Application\\Branding' => __DIR__ . '/../..' . '/sources/Application/Branding.php',
|
||||
'Combodo\\iTop\\Application\\EventRegister\\ApplicationEvents' => __DIR__ . '/../..' . '/sources/Application/EventRegister/ApplicationEvents.php',
|
||||
@@ -917,13 +917,13 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
|
||||
'CoreTemplateException' => __DIR__ . '/../..' . '/application/exceptions/CoreTemplateException.php',
|
||||
'CoreUnexpectedValue' => __DIR__ . '/../..' . '/application/exceptions/CoreUnexpectedValue.php',
|
||||
'CoreWarning' => __DIR__ . '/../..' . '/application/exceptions/CoreWarning.php',
|
||||
'CryptEngine' => __DIR__ . '/../..' . '/core/simplecrypt.class.inc.php',
|
||||
'CryptEngine' => __DIR__ . '/../..' . '/sources/Application/SimpleCrypt/CryptEngine.php',
|
||||
'CustomFieldsHandler' => __DIR__ . '/../..' . '/core/customfieldshandler.class.inc.php',
|
||||
'DBObject' => __DIR__ . '/../..' . '/core/dbobject.class.php',
|
||||
'DBObjectSearch' => __DIR__ . '/../..' . '/core/dbobjectsearch.class.php',
|
||||
'DBObjectSet' => __DIR__ . '/../..' . '/core/dbobjectset.class.php',
|
||||
'DBObjectSetComparator' => __DIR__ . '/../..' . '/core/dbobjectset.class.php',
|
||||
'DBProperty' => __DIR__ . '/../..' . '/core/dbproperty.class.inc.php',
|
||||
'DBProperty' => __DIR__ . '/../..' . '/sources/Core/DataModel/DBProperty.php',
|
||||
'DBSearch' => __DIR__ . '/../..' . '/core/dbsearch.class.php',
|
||||
'DBSearchHelper' => __DIR__ . '/../..' . '/application/DBSearchHelper.php',
|
||||
'DBUnionSearch' => __DIR__ . '/../..' . '/core/dbunionsearch.class.php',
|
||||
@@ -994,18 +994,18 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
|
||||
'DisplayableNode' => __DIR__ . '/../..' . '/core/displayablegraph.class.inc.php',
|
||||
'DisplayableRedundancyNode' => __DIR__ . '/../..' . '/core/displayablegraph.class.inc.php',
|
||||
'EMail' => __DIR__ . '/../..' . '/core/email.class.inc.php',
|
||||
'Event' => __DIR__ . '/../..' . '/core/event.class.inc.php',
|
||||
'EventIssue' => __DIR__ . '/../..' . '/core/event.class.inc.php',
|
||||
'EventLoginUsage' => __DIR__ . '/../..' . '/core/event.class.inc.php',
|
||||
'EventNotification' => __DIR__ . '/../..' . '/core/event.class.inc.php',
|
||||
'EventNotificationEmail' => __DIR__ . '/../..' . '/core/event.class.inc.php',
|
||||
'EventOnObject' => __DIR__ . '/../..' . '/core/event.class.inc.php',
|
||||
'EventRestService' => __DIR__ . '/../..' . '/core/event.class.inc.php',
|
||||
'EventWebService' => __DIR__ . '/../..' . '/core/event.class.inc.php',
|
||||
'ExcelBulkExport' => __DIR__ . '/../..' . '/core/excelbulkexport.class.inc.php',
|
||||
'Event' => __DIR__ . '/../..' . '/sources/Application/DataModel/Event/Event.php',
|
||||
'EventIssue' => __DIR__ . '/../..' . '/sources/Application/DataModel/Event/EventIssue.php',
|
||||
'EventLoginUsage' => __DIR__ . '/../..' . '/sources/Application/DataModel/Event/EventLoginUsage.php',
|
||||
'EventNotification' => __DIR__ . '/../..' . '/sources/Application/DataModel/Event/EventNotification.php',
|
||||
'EventNotificationEmail' => __DIR__ . '/../..' . '/sources/Application/DataModel/Event/EventNotificationEmail.php',
|
||||
'EventOnObject' => __DIR__ . '/../..' . '/sources/Application/DataModel/Event/EventOnObject.php',
|
||||
'EventRestService' => __DIR__ . '/../..' . '/sources/Application/DataModel/Event/EventRestService.php',
|
||||
'EventWebService' => __DIR__ . '/../..' . '/sources/Application/DataModel/Event/EventWebService.php',
|
||||
'ExcelBulkExport' => __DIR__ . '/../..' . '/sources/Application/BulkExport/ExcelBulkExport.php',
|
||||
'ExcelExporter' => __DIR__ . '/../..' . '/application/excelexporter.class.inc.php',
|
||||
'ExceptionLog' => __DIR__ . '/../..' . '/core/log.class.inc.php',
|
||||
'ExecAsyncTask' => __DIR__ . '/../..' . '/core/asynctask.class.inc.php',
|
||||
'ExecAsyncTask' => __DIR__ . '/../..' . '/sources/Core/DataModel/AsyncTask/ExecAsyncTask.php',
|
||||
'ExecutionKPI' => __DIR__ . '/../..' . '/core/kpi.class.inc.php',
|
||||
'Expression' => __DIR__ . '/../..' . '/core/oql/expression.class.inc.php',
|
||||
'ExpressionCache' => __DIR__ . '/../..' . '/core/expressioncache.class.inc.php',
|
||||
@@ -1116,7 +1116,7 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
|
||||
'GuzzleHttp\\RetryMiddleware' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/RetryMiddleware.php',
|
||||
'GuzzleHttp\\TransferStats' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/TransferStats.php',
|
||||
'GuzzleHttp\\Utils' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Utils.php',
|
||||
'HTMLBulkExport' => __DIR__ . '/../..' . '/core/htmlbulkexport.class.inc.php',
|
||||
'HTMLBulkExport' => __DIR__ . '/../..' . '/sources/Application/BulkExport/HTMLBulkExport.php',
|
||||
'HTMLDOMSanitizer' => __DIR__ . '/../..' . '/core/htmlsanitizer.class.inc.php',
|
||||
'HTMLNullSanitizer' => __DIR__ . '/../..' . '/core/htmlsanitizer.class.inc.php',
|
||||
'HTMLSanitizer' => __DIR__ . '/../..' . '/core/htmlsanitizer.class.inc.php',
|
||||
@@ -1131,10 +1131,10 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
|
||||
'InvalidExternalKeyValueException' => __DIR__ . '/../..' . '/application/exceptions/InvalidExternalKeyValueException.php',
|
||||
'InvalidPasswordAttributeOneWayPassword' => __DIR__ . '/../..' . '/application/exceptions/InvalidPasswordAttributeOneWayPassword.php',
|
||||
'IssueLog' => __DIR__ . '/../..' . '/core/log.class.inc.php',
|
||||
'ItopCounter' => __DIR__ . '/../..' . '/core/counter.class.inc.php',
|
||||
'JSButtonItem' => __DIR__ . '/../..' . '/application/applicationextension.inc.php',
|
||||
'JSPopupMenuItem' => __DIR__ . '/../..' . '/application/applicationextension.inc.php',
|
||||
'KeyValueStore' => __DIR__ . '/../..' . '/core/counter.class.inc.php',
|
||||
'ItopCounter' => __DIR__ . '/../..' . '/sources/Core/ItopCounter.php',
|
||||
'JSButtonItem' => __DIR__ . '/../..' . '/application/applicationextension/backoffice/JSButtonItem.php',
|
||||
'JSPopupMenuItem' => __DIR__ . '/../..' . '/application/applicationextension/backoffice/JSPopupMenuItem.php',
|
||||
'KeyValueStore' => __DIR__ . '/../..' . '/sources/Core/DataModel/KeyValueStore.php',
|
||||
'Laminas\\Loader\\AutoloaderFactory' => __DIR__ . '/..' . '/laminas/laminas-loader/src/AutoloaderFactory.php',
|
||||
'Laminas\\Loader\\ClassMapAutoloader' => __DIR__ . '/..' . '/laminas/laminas-loader/src/ClassMapAutoloader.php',
|
||||
'Laminas\\Loader\\Exception\\BadMethodCallException' => __DIR__ . '/..' . '/laminas/laminas-loader/src/Exception/BadMethodCallException.php',
|
||||
@@ -1495,7 +1495,7 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
|
||||
'MenuGroup' => __DIR__ . '/../..' . '/application/menunode.class.inc.php',
|
||||
'MenuNode' => __DIR__ . '/../..' . '/application/menunode.class.inc.php',
|
||||
'MetaModel' => __DIR__ . '/../..' . '/core/metamodel.class.php',
|
||||
'MissingColumnException' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php',
|
||||
'MissingColumnException' => __DIR__ . '/../..' . '/sources/Core/AttributeDefinition/MissingColumnException.php',
|
||||
'MissingQueryArgument' => __DIR__ . '/../..' . '/core/oql/expression.class.inc.php',
|
||||
'ModelReflection' => __DIR__ . '/../..' . '/core/modelreflection.class.inc.php',
|
||||
'ModelReflectionRuntime' => __DIR__ . '/../..' . '/core/modelreflection.class.inc.php',
|
||||
@@ -1548,7 +1548,7 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
|
||||
'OqlUnionQuery' => __DIR__ . '/../..' . '/core/oql/oqlquery.class.inc.php',
|
||||
'Override' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/Override.php',
|
||||
'PDF417' => __DIR__ . '/..' . '/tecnickcom/tcpdf/include/barcodes/pdf417.php',
|
||||
'PDFBulkExport' => __DIR__ . '/../..' . '/core/pdfbulkexport.class.inc.php',
|
||||
'PDFBulkExport' => __DIR__ . '/../..' . '/sources/Application/BulkExport/PDFBulkExport.php',
|
||||
'PEAR' => __DIR__ . '/..' . '/pear/pear-core-minimal/src/PEAR.php',
|
||||
'PEAR_ErrorStack' => __DIR__ . '/..' . '/pear/pear-core-minimal/src/PEAR/ErrorStack.php',
|
||||
'PEAR_Exception' => __DIR__ . '/..' . '/pear/pear_exception/PEAR/Exception.php',
|
||||
@@ -1879,26 +1879,26 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
|
||||
'QueryOQL' => __DIR__ . '/../..' . '/application/query.class.inc.php',
|
||||
'QueryReflection' => __DIR__ . '/../..' . '/core/modelreflection.class.inc.php',
|
||||
'QueryReflectionRuntime' => __DIR__ . '/../..' . '/core/modelreflection.class.inc.php',
|
||||
'RelationEdge' => __DIR__ . '/../..' . '/core/relationgraph.class.inc.php',
|
||||
'RelationGraph' => __DIR__ . '/../..' . '/core/relationgraph.class.inc.php',
|
||||
'RelationObjectNode' => __DIR__ . '/../..' . '/core/relationgraph.class.inc.php',
|
||||
'RelationRedundancyNode' => __DIR__ . '/../..' . '/core/relationgraph.class.inc.php',
|
||||
'RelationEdge' => __DIR__ . '/../..' . '/sources/Core/RelationGraph/RelationEdge.php',
|
||||
'RelationGraph' => __DIR__ . '/../..' . '/sources/Core/RelationGraph/RelationGraph.php',
|
||||
'RelationObjectNode' => __DIR__ . '/../..' . '/sources/Core/RelationGraph/RelationObjectNode.php',
|
||||
'RelationRedundancyNode' => __DIR__ . '/../..' . '/sources/Core/RelationGraph/RelationRedundancyNode.php',
|
||||
'RelationTypeIterator' => __DIR__ . '/../..' . '/core/simplegraph.class.inc.php',
|
||||
'ReportValue' => __DIR__ . '/../..' . '/core/bulkchange.class.inc.php',
|
||||
'ReportValue' => __DIR__ . '/../..' . '/sources/Core/BulkChange/ReportValue.php',
|
||||
'RestDelete' => __DIR__ . '/../..' . '/core/restservices.class.inc.php',
|
||||
'RestResult' => __DIR__ . '/../..' . '/application/applicationextension.inc.php',
|
||||
'RestResult' => __DIR__ . '/../..' . '/application/applicationextension/rest/RestResult.php',
|
||||
'RestResultWithObjects' => __DIR__ . '/../..' . '/core/restservices.class.inc.php',
|
||||
'RestResultWithRelations' => __DIR__ . '/../..' . '/core/restservices.class.inc.php',
|
||||
'RestUtils' => __DIR__ . '/../..' . '/application/applicationextension.inc.php',
|
||||
'RestUtils' => __DIR__ . '/../..' . '/application/applicationextension/rest/RestUtils.php',
|
||||
'ReturnTypeWillChange' => __DIR__ . '/..' . '/symfony/polyfill-php81/Resources/stubs/ReturnTypeWillChange.php',
|
||||
'RotatingLogFileNameBuilder' => __DIR__ . '/../..' . '/core/log.class.inc.php',
|
||||
'RowStatus' => __DIR__ . '/../..' . '/core/bulkchange.class.inc.php',
|
||||
'RowStatus_Disappeared' => __DIR__ . '/../..' . '/core/bulkchange.class.inc.php',
|
||||
'RowStatus_Error' => __DIR__ . '/../..' . '/core/bulkchange.class.inc.php',
|
||||
'RowStatus_Issue' => __DIR__ . '/../..' . '/core/bulkchange.class.inc.php',
|
||||
'RowStatus_Modify' => __DIR__ . '/../..' . '/core/bulkchange.class.inc.php',
|
||||
'RowStatus_NewObj' => __DIR__ . '/../..' . '/core/bulkchange.class.inc.php',
|
||||
'RowStatus_NoChange' => __DIR__ . '/../..' . '/core/bulkchange.class.inc.php',
|
||||
'RowStatus' => __DIR__ . '/../..' . '/sources/Core/BulkChange/RowStatus.php',
|
||||
'RowStatus_Disappeared' => __DIR__ . '/../..' . '/sources/Core/BulkChange/RowStatus_Disappeared.php',
|
||||
'RowStatus_Error' => __DIR__ . '/../..' . '/sources/Core/BulkChange/RowStatus_Error.php',
|
||||
'RowStatus_Issue' => __DIR__ . '/../..' . '/sources/Core/BulkChange/RowStatus_Issue.php',
|
||||
'RowStatus_Modify' => __DIR__ . '/../..' . '/sources/Core/BulkChange/RowStatus_Modify.php',
|
||||
'RowStatus_NewObj' => __DIR__ . '/../..' . '/sources/Core/BulkChange/RowStatus_NewObj.php',
|
||||
'RowStatus_NoChange' => __DIR__ . '/../..' . '/sources/Core/BulkChange/RowStatus_NoChange.php',
|
||||
'RunTimeIconSelectionField' => __DIR__ . '/../..' . '/application/forms.class.inc.php',
|
||||
'RuntimeDashboard' => __DIR__ . '/../..' . '/application/dashboard.class.inc.php',
|
||||
'SQLExpression' => __DIR__ . '/../..' . '/core/oql/expression.class.inc.php',
|
||||
@@ -2002,23 +2002,23 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
|
||||
'ScssPhp\\ScssPhp\\Warn' => __DIR__ . '/..' . '/scssphp/scssphp/src/Warn.php',
|
||||
'SearchMenuNode' => __DIR__ . '/../..' . '/application/menunode.class.inc.php',
|
||||
'SecurityException' => __DIR__ . '/../..' . '/application/exceptions/SecurityException.php',
|
||||
'SeparatorPopupMenuItem' => __DIR__ . '/../..' . '/application/applicationextension.inc.php',
|
||||
'SeparatorPopupMenuItem' => __DIR__ . '/../..' . '/application/applicationextension/backoffice/SeparatorPopupMenuItem.php',
|
||||
'SetupLog' => __DIR__ . '/../..' . '/core/log.class.inc.php',
|
||||
'Shortcut' => __DIR__ . '/../..' . '/application/shortcut.class.inc.php',
|
||||
'ShortcutContainerMenuNode' => __DIR__ . '/../..' . '/application/menunode.class.inc.php',
|
||||
'ShortcutMenuNode' => __DIR__ . '/../..' . '/application/menunode.class.inc.php',
|
||||
'ShortcutOQL' => __DIR__ . '/../..' . '/application/shortcut.class.inc.php',
|
||||
'SimpleCrypt' => __DIR__ . '/../..' . '/core/simplecrypt.class.inc.php',
|
||||
'SimpleCryptMcryptEngine' => __DIR__ . '/../..' . '/core/simplecrypt.class.inc.php',
|
||||
'SimpleCryptOpenSSLEngine' => __DIR__ . '/../..' . '/core/simplecrypt.class.inc.php',
|
||||
'SimpleCryptOpenSSLMcryptCompatibilityEngine' => __DIR__ . '/../..' . '/core/simplecrypt.class.inc.php',
|
||||
'SimpleCryptSimpleEngine' => __DIR__ . '/../..' . '/core/simplecrypt.class.inc.php',
|
||||
'SimpleCryptSodiumEngine' => __DIR__ . '/../..' . '/core/simplecrypt.class.inc.php',
|
||||
'SimpleCrypt' => __DIR__ . '/../..' . '/sources/Application/SimpleCrypt/SimpleCrypt.php',
|
||||
'SimpleCryptMcryptEngine' => __DIR__ . '/../..' . '/sources/Application/SimpleCrypt/SimpleCryptMcryptEngine.php',
|
||||
'SimpleCryptOpenSSLEngine' => __DIR__ . '/../..' . '/sources/Application/SimpleCrypt/SimpleCryptOpenSSLEngine.php',
|
||||
'SimpleCryptOpenSSLMcryptCompatibilityEngine' => __DIR__ . '/../..' . '/sources/Application/SimpleCrypt/SimpleCryptOpenSSLMcryptCompatibilityEngine.php',
|
||||
'SimpleCryptSimpleEngine' => __DIR__ . '/../..' . '/sources/Application/SimpleCrypt/SimpleCryptSimpleEngine.php',
|
||||
'SimpleCryptSodiumEngine' => __DIR__ . '/../..' . '/sources/Application/SimpleCrypt/SimpleCryptSodiumEngine.php',
|
||||
'SimpleGraph' => __DIR__ . '/../..' . '/core/simplegraph.class.inc.php',
|
||||
'SimpleGraphException' => __DIR__ . '/../..' . '/core/simplegraph.class.inc.php',
|
||||
'Soundasleep\\Html2Text' => __DIR__ . '/..' . '/soundasleep/html2text/src/Html2Text.php',
|
||||
'Soundasleep\\Html2TextException' => __DIR__ . '/..' . '/soundasleep/html2text/src/Html2TextException.php',
|
||||
'SpreadsheetBulkExport' => __DIR__ . '/../..' . '/core/spreadsheetbulkexport.class.inc.php',
|
||||
'SpreadsheetBulkExport' => __DIR__ . '/../..' . '/sources/Application/BulkExport/SpreadsheetBulkExport.php',
|
||||
'StimulusChecker' => __DIR__ . '/../..' . '/core/userrights.class.inc.php',
|
||||
'StimulusInternal' => __DIR__ . '/../..' . '/core/stimulus.class.inc.php',
|
||||
'StimulusUserAction' => __DIR__ . '/../..' . '/core/stimulus.class.inc.php',
|
||||
@@ -3294,12 +3294,12 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
|
||||
'TCPDF_IMPORT' => __DIR__ . '/..' . '/tecnickcom/tcpdf/tcpdf_import.php',
|
||||
'TCPDF_PARSER' => __DIR__ . '/..' . '/tecnickcom/tcpdf/tcpdf_parser.php',
|
||||
'TCPDF_STATIC' => __DIR__ . '/..' . '/tecnickcom/tcpdf/include/tcpdf_static.php',
|
||||
'TabularBulkExport' => __DIR__ . '/../..' . '/core/tabularbulkexport.class.inc.php',
|
||||
'TagSetFieldData' => __DIR__ . '/../..' . '/core/tagsetfield.class.inc.php',
|
||||
'TabularBulkExport' => __DIR__ . '/../..' . '/sources/Application/BulkExport/TabularBulkExport.php',
|
||||
'TagSetFieldData' => __DIR__ . '/../..' . '/sources/Core/DataModel/TagSetFieldData.php',
|
||||
'TemplateMenuNode' => __DIR__ . '/../..' . '/application/menunode.class.inc.php',
|
||||
'TemplateString' => __DIR__ . '/../..' . '/core/templatestring.class.inc.php',
|
||||
'TemplateStringPlaceholder' => __DIR__ . '/../..' . '/core/templatestring.class.inc.php',
|
||||
'TemporaryObjectDescriptor' => __DIR__ . '/../..' . '/core/TemporaryObjectDescriptor.php',
|
||||
'TemporaryObjectDescriptor' => __DIR__ . '/../..' . '/sources/Core/DataModel/TemporaryObjectDescriptor.php',
|
||||
'TheNetworg\\OAuth2\\Client\\Grant\\JwtBearer' => __DIR__ . '/..' . '/thenetworg/oauth2-azure/src/Grant/JwtBearer.php',
|
||||
'TheNetworg\\OAuth2\\Client\\Provider\\Azure' => __DIR__ . '/..' . '/thenetworg/oauth2-azure/src/Provider/Azure.php',
|
||||
'TheNetworg\\OAuth2\\Client\\Provider\\AzureResourceOwner' => __DIR__ . '/..' . '/thenetworg/oauth2-azure/src/Provider/AzureResourceOwner.php',
|
||||
@@ -3307,18 +3307,18 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
|
||||
'ThemeHandler' => __DIR__ . '/../..' . '/application/themehandler.class.inc.php',
|
||||
'ThemeHandlerService' => __DIR__ . '/../..' . '/application/themehandlerservice.class.inc.php',
|
||||
'ToolsLog' => __DIR__ . '/../..' . '/core/log.class.inc.php',
|
||||
'Trigger' => __DIR__ . '/../..' . '/core/trigger.class.inc.php',
|
||||
'TriggerOnAttributeBlobDownload' => __DIR__ . '/../..' . '/core/trigger.class.inc.php',
|
||||
'TriggerOnObject' => __DIR__ . '/../..' . '/core/trigger.class.inc.php',
|
||||
'TriggerOnObjectCreate' => __DIR__ . '/../..' . '/core/trigger.class.inc.php',
|
||||
'TriggerOnObjectDelete' => __DIR__ . '/../..' . '/core/trigger.class.inc.php',
|
||||
'TriggerOnObjectMention' => __DIR__ . '/../..' . '/core/trigger.class.inc.php',
|
||||
'TriggerOnObjectUpdate' => __DIR__ . '/../..' . '/core/trigger.class.inc.php',
|
||||
'TriggerOnPortalUpdate' => __DIR__ . '/../..' . '/core/trigger.class.inc.php',
|
||||
'TriggerOnStateChange' => __DIR__ . '/../..' . '/core/trigger.class.inc.php',
|
||||
'TriggerOnStateEnter' => __DIR__ . '/../..' . '/core/trigger.class.inc.php',
|
||||
'TriggerOnStateLeave' => __DIR__ . '/../..' . '/core/trigger.class.inc.php',
|
||||
'TriggerOnThresholdReached' => __DIR__ . '/../..' . '/core/trigger.class.inc.php',
|
||||
'Trigger' => __DIR__ . '/../..' . '/sources/Application/DataModel/TriggerAndAction/Trigger.php',
|
||||
'TriggerOnAttributeBlobDownload' => __DIR__ . '/../..' . '/sources/Application/DataModel/TriggerAndAction/TriggerOnAttributeBlobDownload.php',
|
||||
'TriggerOnObject' => __DIR__ . '/../..' . '/sources/Application/DataModel/TriggerAndAction/TriggerOnObject.php',
|
||||
'TriggerOnObjectCreate' => __DIR__ . '/../..' . '/sources/Application/DataModel/TriggerAndAction/TriggerOnObjectCreate.php',
|
||||
'TriggerOnObjectDelete' => __DIR__ . '/../..' . '/sources/Application/DataModel/TriggerAndAction/TriggerOnObjectDelete.php',
|
||||
'TriggerOnObjectMention' => __DIR__ . '/../..' . '/sources/Application/DataModel/TriggerAndAction/TriggerOnObjectMention.php',
|
||||
'TriggerOnObjectUpdate' => __DIR__ . '/../..' . '/sources/Application/DataModel/TriggerAndAction/TriggerOnObjectUpdate.php',
|
||||
'TriggerOnPortalUpdate' => __DIR__ . '/../..' . '/sources/Application/DataModel/TriggerAndAction/TriggerOnPortalUpdate.php',
|
||||
'TriggerOnStateChange' => __DIR__ . '/../..' . '/sources/Application/DataModel/TriggerAndAction/TriggerOnStateChange.php',
|
||||
'TriggerOnStateEnter' => __DIR__ . '/../..' . '/sources/Application/DataModel/TriggerAndAction/TriggerOnStateEnter.php',
|
||||
'TriggerOnStateLeave' => __DIR__ . '/../..' . '/sources/Application/DataModel/TriggerAndAction/TriggerOnStateLeave.php',
|
||||
'TriggerOnThresholdReached' => __DIR__ . '/../..' . '/sources/Application/DataModel/TriggerAndAction/TriggerOnThresholdReached.php',
|
||||
'TrueExpression' => __DIR__ . '/../..' . '/core/oql/expression.class.inc.php',
|
||||
'Twig\\AbstractTwigCallable' => __DIR__ . '/..' . '/twig/twig/src/AbstractTwigCallable.php',
|
||||
'Twig\\Attribute\\FirstClassTwigCallableReady' => __DIR__ . '/..' . '/twig/twig/src/Attribute/FirstClassTwigCallableReady.php',
|
||||
@@ -3534,8 +3534,8 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
|
||||
'UIPasswordWidget' => __DIR__ . '/../..' . '/application/ui.passwordwidget.class.inc.php',
|
||||
'UISearchFormForeignKeys' => __DIR__ . '/../..' . '/application/ui.searchformforeignkeys.class.inc.php',
|
||||
'UIWizard' => __DIR__ . '/../..' . '/application/uiwizard.class.inc.php',
|
||||
'URLButtonItem' => __DIR__ . '/../..' . '/application/applicationextension.inc.php',
|
||||
'URLPopupMenuItem' => __DIR__ . '/../..' . '/application/applicationextension.inc.php',
|
||||
'URLButtonItem' => __DIR__ . '/../..' . '/application/applicationextension/backoffice/URLButtonItem.php',
|
||||
'URLPopupMenuItem' => __DIR__ . '/../..' . '/application/applicationextension/backoffice/URLPopupMenuItem.php',
|
||||
'UnaryExpression' => __DIR__ . '/../..' . '/core/oql/expression.class.inc.php',
|
||||
'UnknownClassOqlException' => __DIR__ . '/../..' . '/core/oql/oqlinterpreter.class.inc.php',
|
||||
'User' => __DIR__ . '/../..' . '/core/userrights.class.inc.php',
|
||||
@@ -3544,12 +3544,12 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
|
||||
'UserRightException' => __DIR__ . '/../..' . '/application/exceptions/UserRightException.php',
|
||||
'UserRights' => __DIR__ . '/../..' . '/core/userrights.class.inc.php',
|
||||
'UserRightsAddOnAPI' => __DIR__ . '/../..' . '/core/userrights.class.inc.php',
|
||||
'ValueSetDefinition' => __DIR__ . '/../..' . '/core/valuesetdef.class.inc.php',
|
||||
'ValueSetEnum' => __DIR__ . '/../..' . '/core/valuesetdef.class.inc.php',
|
||||
'ValueSetEnumClasses' => __DIR__ . '/../..' . '/core/valuesetdef.class.inc.php',
|
||||
'ValueSetEnumPadded' => __DIR__ . '/../..' . '/core/valuesetdef.class.inc.php',
|
||||
'ValueSetObjects' => __DIR__ . '/../..' . '/core/valuesetdef.class.inc.php',
|
||||
'ValueSetRange' => __DIR__ . '/../..' . '/core/valuesetdef.class.inc.php',
|
||||
'ValueSetDefinition' => __DIR__ . '/../..' . '/sources/Core/ValueSetDefinition/ValueSetDefinition.php',
|
||||
'ValueSetEnum' => __DIR__ . '/../..' . '/sources/Core/ValueSetDefinition/ValueSetEnum.php',
|
||||
'ValueSetEnumClasses' => __DIR__ . '/../..' . '/sources/Core/ValueSetDefinition/ValueSetEnumClasses.php',
|
||||
'ValueSetEnumPadded' => __DIR__ . '/../..' . '/sources/Core/ValueSetDefinition/ValueSetEnumPadded.php',
|
||||
'ValueSetObjects' => __DIR__ . '/../..' . '/sources/Core/ValueSetDefinition/ValueSetObjects.php',
|
||||
'ValueSetRange' => __DIR__ . '/../..' . '/sources/Core/ValueSetDefinition/ValueSetRange.php',
|
||||
'VariableExpression' => __DIR__ . '/../..' . '/core/oql/expression.class.inc.php',
|
||||
'VariableOqlExpression' => __DIR__ . '/../..' . '/core/oql/oqlquery.class.inc.php',
|
||||
'WebPageMenuNode' => __DIR__ . '/../..' . '/application/menunode.class.inc.php',
|
||||
@@ -3559,48 +3559,48 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
|
||||
'WeeklyRotatingLogFileNameBuilder' => __DIR__ . '/../..' . '/core/log.class.inc.php',
|
||||
'WizardHelper' => __DIR__ . '/../..' . '/application/wizardhelper.class.inc.php',
|
||||
'XLSXWriter' => __DIR__ . '/../..' . '/application/xlsxwriter.class.php',
|
||||
'XMLBulkExport' => __DIR__ . '/../..' . '/core/xmlbulkexport.class.inc.php',
|
||||
'XMLBulkExport' => __DIR__ . '/../..' . '/sources/Application/BulkExport/XMLBulkExport.php',
|
||||
'appUserPreferences' => __DIR__ . '/../..' . '/application/user.preferences.class.inc.php',
|
||||
'cmdbAbstractObject' => __DIR__ . '/../..' . '/application/cmdbabstract.class.inc.php',
|
||||
'cmdbDataGenerator' => __DIR__ . '/../..' . '/core/data.generator.class.inc.php',
|
||||
'iApplicationObjectExtension' => __DIR__ . '/../..' . '/application/applicationextension.inc.php',
|
||||
'iApplicationUIExtension' => __DIR__ . '/../..' . '/application/applicationextension.inc.php',
|
||||
'iAttributeNoGroupBy' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php',
|
||||
'iApplicationObjectExtension' => __DIR__ . '/../..' . '/application/applicationextension/backoffice/iApplicationObjectExtension.php',
|
||||
'iApplicationUIExtension' => __DIR__ . '/../..' . '/application/applicationextension/backoffice/iApplicationUIExtension.php',
|
||||
'iAttributeNoGroupBy' => __DIR__ . '/../..' . '/sources/Core/AttributeDefinition/iAttributeNoGroupBy.php',
|
||||
'iBackgroundProcess' => __DIR__ . '/../..' . '/core/backgroundprocess.inc.php',
|
||||
'iBackofficeDictEntriesExtension' => __DIR__ . '/../..' . '/application/applicationextension.inc.php',
|
||||
'iBackofficeDictEntriesPrefixesExtension' => __DIR__ . '/../..' . '/application/applicationextension.inc.php',
|
||||
'iBackofficeEarlyScriptExtension' => __DIR__ . '/../..' . '/application/applicationextension.inc.php',
|
||||
'iBackofficeInitScriptExtension' => __DIR__ . '/../..' . '/application/applicationextension.inc.php',
|
||||
'iBackofficeLinkedScriptsExtension' => __DIR__ . '/../..' . '/application/applicationextension.inc.php',
|
||||
'iBackofficeLinkedStylesheetsExtension' => __DIR__ . '/../..' . '/application/applicationextension.inc.php',
|
||||
'iBackofficeReadyScriptExtension' => __DIR__ . '/../..' . '/application/applicationextension.inc.php',
|
||||
'iBackofficeSassExtension' => __DIR__ . '/../..' . '/application/applicationextension.inc.php',
|
||||
'iBackofficeScriptExtension' => __DIR__ . '/../..' . '/application/applicationextension.inc.php',
|
||||
'iBackofficeStyleExtension' => __DIR__ . '/../..' . '/application/applicationextension.inc.php',
|
||||
'iBackupExtraFilesExtension' => __DIR__ . '/../..' . '/application/applicationextension.inc.php',
|
||||
'iCMDBChangeOp' => __DIR__ . '/../..' . '/core/cmdbchangeop.class.inc.php',
|
||||
'iBackofficeDictEntriesExtension' => __DIR__ . '/../..' . '/application/applicationextension/backoffice/iBackofficeDictEntriesExtension.php',
|
||||
'iBackofficeDictEntriesPrefixesExtension' => __DIR__ . '/../..' . '/application/applicationextension/backoffice/iBackofficeDictEntriesPrefixesExtension.php',
|
||||
'iBackofficeEarlyScriptExtension' => __DIR__ . '/../..' . '/application/applicationextension/backoffice/iBackofficeEarlyScriptExtension.php',
|
||||
'iBackofficeInitScriptExtension' => __DIR__ . '/../..' . '/application/applicationextension/backoffice/iBackofficeInitScriptExtension.php',
|
||||
'iBackofficeLinkedScriptsExtension' => __DIR__ . '/../..' . '/application/applicationextension/backoffice/iBackofficeLinkedScriptsExtension.php',
|
||||
'iBackofficeLinkedStylesheetsExtension' => __DIR__ . '/../..' . '/application/applicationextension/backoffice/iBackofficeLinkedStylesheetsExtension.php',
|
||||
'iBackofficeReadyScriptExtension' => __DIR__ . '/../..' . '/application/applicationextension/backoffice/iBackofficeReadyScriptExtension.php',
|
||||
'iBackofficeSassExtension' => __DIR__ . '/../..' . '/application/applicationextension/backoffice/iBackofficeSassExtension.php',
|
||||
'iBackofficeScriptExtension' => __DIR__ . '/../..' . '/application/applicationextension/backoffice/iBackofficeScriptExtension.php',
|
||||
'iBackofficeStyleExtension' => __DIR__ . '/../..' . '/application/applicationextension/backoffice/iBackofficeStyleExtension.php',
|
||||
'iBackupExtraFilesExtension' => __DIR__ . '/../..' . '/application/applicationextension/iBackupExtraFilesExtension.php',
|
||||
'iCMDBChangeOp' => __DIR__ . '/../..' . '/sources/Core/DataModel/CMDBChange/iCMDBChangeOp.php',
|
||||
'iDBObjectSetIterator' => __DIR__ . '/../..' . '/core/dbobjectiterator.php',
|
||||
'iDBObjectURLMaker' => __DIR__ . '/../..' . '/application/applicationcontext.class.inc.php',
|
||||
'iDisplay' => __DIR__ . '/../..' . '/core/dbobject.class.php',
|
||||
'iFieldRendererMappingsExtension' => __DIR__ . '/../..' . '/application/applicationextension.inc.php',
|
||||
'iKPILoggerExtension' => __DIR__ . '/../..' . '/application/applicationextension.inc.php',
|
||||
'iFieldRendererMappingsExtension' => __DIR__ . '/../..' . '/application/applicationextension/backoffice/iFieldRendererMappingsExtension.php',
|
||||
'iKPILoggerExtension' => __DIR__ . '/../..' . '/application/applicationextension/iKPILoggerExtension.php',
|
||||
'iLogFileNameBuilder' => __DIR__ . '/../..' . '/core/log.class.inc.php',
|
||||
'iLoginExtension' => __DIR__ . '/../..' . '/application/applicationextension.inc.php',
|
||||
'iLoginFSMExtension' => __DIR__ . '/../..' . '/application/applicationextension.inc.php',
|
||||
'iLoginUIExtension' => __DIR__ . '/../..' . '/application/applicationextension.inc.php',
|
||||
'iLogoutExtension' => __DIR__ . '/../..' . '/application/applicationextension.inc.php',
|
||||
'iLoginExtension' => __DIR__ . '/../..' . '/application/applicationextension/login/iLoginExtension.php',
|
||||
'iLoginFSMExtension' => __DIR__ . '/../..' . '/application/applicationextension/login/iLoginFSMExtension.php',
|
||||
'iLoginUIExtension' => __DIR__ . '/../..' . '/application/applicationextension/login/iLoginUIExtension.php',
|
||||
'iLogoutExtension' => __DIR__ . '/../..' . '/application/applicationextension/login/iLogoutExtension.php',
|
||||
'iMetricComputer' => __DIR__ . '/../..' . '/core/computing.inc.php',
|
||||
'iModuleExtension' => __DIR__ . '/../..' . '/application/applicationextension.inc.php',
|
||||
'iModuleExtension' => __DIR__ . '/../..' . '/application/applicationextension/iModuleExtension.php',
|
||||
'iNewsroomProvider' => __DIR__ . '/../..' . '/application/newsroomprovider.class.inc.php',
|
||||
'iOnClassInitialization' => __DIR__ . '/../..' . '/core/metamodelmodifier.inc.php',
|
||||
'iPageUIBlockExtension' => __DIR__ . '/../..' . '/application/applicationextension.inc.php',
|
||||
'iPopupMenuExtension' => __DIR__ . '/../..' . '/application/applicationextension.inc.php',
|
||||
'iPortalUIExtension' => __DIR__ . '/../..' . '/application/applicationextension.inc.php',
|
||||
'iPreferencesExtension' => __DIR__ . '/../..' . '/application/applicationextension.inc.php',
|
||||
'iPageUIBlockExtension' => __DIR__ . '/../..' . '/application/applicationextension/backoffice/iPageUIBlockExtension.php',
|
||||
'iPopupMenuExtension' => __DIR__ . '/../..' . '/application/applicationextension/backoffice/iPopupMenuExtension.php',
|
||||
'iPortalUIExtension' => __DIR__ . '/../..' . '/application/applicationextension/portal/iPortalUIExtension.php',
|
||||
'iPreferencesExtension' => __DIR__ . '/../..' . '/application/applicationextension/backoffice/iPreferencesExtension.php',
|
||||
'iProcess' => __DIR__ . '/../..' . '/core/backgroundprocess.inc.php',
|
||||
'iQueryModifier' => __DIR__ . '/../..' . '/core/querymodifier.class.inc.php',
|
||||
'iRestInputSanitizer' => __DIR__ . '/../..' . '/application/applicationextension.inc.php',
|
||||
'iRestServiceProvider' => __DIR__ . '/../..' . '/application/applicationextension.inc.php',
|
||||
'iRestInputSanitizer' => __DIR__ . '/../..' . '/application/applicationextension/rest/iRestInputSanitizer.php',
|
||||
'iRestServiceProvider' => __DIR__ . '/../..' . '/application/applicationextension/rest/iRestServiceProvider.php',
|
||||
'iScheduledProcess' => __DIR__ . '/../..' . '/core/backgroundprocess.inc.php',
|
||||
'iSelfRegister' => __DIR__ . '/../..' . '/core/userrights.class.inc.php',
|
||||
'iTopConfigParser' => __DIR__ . '/../..' . '/core/iTopConfigParser.php',
|
||||
@@ -3609,19 +3609,19 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
|
||||
'iTopOwnershipToken' => __DIR__ . '/../..' . '/core/ownershiplock.class.inc.php',
|
||||
'iTopStandardURLMaker' => __DIR__ . '/../..' . '/application/applicationcontext.class.inc.php',
|
||||
'iTopXmlException' => __DIR__ . '/../..' . '/application/exceptions/iTopXmlException.php',
|
||||
'iWelcomePopupExtension' => __DIR__ . '/../..' . '/application/applicationextension.inc.php',
|
||||
'iWelcomePopupExtension' => __DIR__ . '/../..' . '/application/applicationextension/backoffice/iWelcomePopupExtension.php',
|
||||
'iWorkingTimeComputer' => __DIR__ . '/../..' . '/core/computing.inc.php',
|
||||
'lnkAuditCategoryToAuditDomain' => __DIR__ . '/../..' . '/application/audit.domain.class.inc.php',
|
||||
'lnkTriggerAction' => __DIR__ . '/../..' . '/core/trigger.class.inc.php',
|
||||
'ormCaseLog' => __DIR__ . '/../..' . '/core/ormcaselog.class.inc.php',
|
||||
'ormCustomFieldsValue' => __DIR__ . '/../..' . '/core/ormcustomfieldsvalue.class.inc.php',
|
||||
'ormDocument' => __DIR__ . '/../..' . '/core/ormdocument.class.inc.php',
|
||||
'ormLinkSet' => __DIR__ . '/../..' . '/core/ormlinkset.class.inc.php',
|
||||
'ormPassword' => __DIR__ . '/../..' . '/core/ormpassword.class.inc.php',
|
||||
'ormSet' => __DIR__ . '/../..' . '/core/ormset.class.inc.php',
|
||||
'ormStopWatch' => __DIR__ . '/../..' . '/core/ormstopwatch.class.inc.php',
|
||||
'ormStyle' => __DIR__ . '/../..' . '/core/ormStyle.class.inc.php',
|
||||
'ormTagSet' => __DIR__ . '/../..' . '/core/ormtagset.class.inc.php',
|
||||
'lnkTriggerAction' => __DIR__ . '/../..' . '/sources/Application/DataModel/TriggerAndAction/lnkTriggerAction.php',
|
||||
'ormCaseLog' => __DIR__ . '/../..' . '/sources/Core/Orm/ormCaseLog.php',
|
||||
'ormCustomFieldsValue' => __DIR__ . '/../..' . '/sources/Core/Orm/ormCustomFieldsValue.php',
|
||||
'ormDocument' => __DIR__ . '/../..' . '/sources/Core/Orm/ormDocument.php',
|
||||
'ormLinkSet' => __DIR__ . '/../..' . '/sources/Core/Orm/ormLinkSet.php',
|
||||
'ormPassword' => __DIR__ . '/../..' . '/sources/Core/Orm/ormPassword.php',
|
||||
'ormSet' => __DIR__ . '/../..' . '/sources/Core/Orm/ormSet.php',
|
||||
'ormStopWatch' => __DIR__ . '/../..' . '/sources/Core/Orm/ormStopWatch.php',
|
||||
'ormStyle' => __DIR__ . '/../..' . '/sources/Core/Orm/ormStyle.php',
|
||||
'ormTagSet' => __DIR__ . '/../..' . '/sources/Core/Orm/ormTagSet.php',
|
||||
'phpCAS' => __DIR__ . '/..' . '/apereo/phpcas/source/CAS.php',
|
||||
'privUITransaction' => __DIR__ . '/../..' . '/application/transaction.class.inc.php',
|
||||
'privUITransactionFile' => __DIR__ . '/../..' . '/application/transaction.class.inc.php',
|
||||
|
||||
@@ -36,7 +36,8 @@ if ($issues) {
|
||||
echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL;
|
||||
}
|
||||
}
|
||||
throw new \RuntimeException(
|
||||
'Composer detected issues in your platform: ' . implode(' ', $issues)
|
||||
trigger_error(
|
||||
'Composer detected issues in your platform: ' . implode(' ', $issues),
|
||||
E_USER_ERROR
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1397,7 +1397,10 @@ try
|
||||
case 'swf_navigator': /** @deprecated SWF was removed in iTop */
|
||||
case 'view_relations': // Graphical display of the relations "impact" / "depends on"
|
||||
require_once(APPROOT.'core/simplegraph.class.inc.php');
|
||||
require_once(APPROOT.'core/relationgraph.class.inc.php');
|
||||
require_once(APPROOT.'/sources/Core/RelationGraph/RelationEdge.php');
|
||||
require_once(APPROOT.'/sources/Core/RelationGraph/RelationGraph.php');
|
||||
require_once(APPROOT.'/sources/Core/RelationGraph/RelationObjectNode.php');
|
||||
require_once(APPROOT.'/sources/Core/RelationGraph/RelationRedundancyNode.php');
|
||||
require_once(APPROOT.'core/displayablegraph.class.inc.php');
|
||||
$sClass = utils::ReadParam('class', '', false, 'class');
|
||||
$id = utils::ReadParam('id', 0);
|
||||
|
||||
@@ -1538,7 +1538,10 @@ EOF
|
||||
case 'relation_pdf':
|
||||
case 'relation_attachment':
|
||||
require_once(APPROOT.'core/simplegraph.class.inc.php');
|
||||
require_once(APPROOT.'core/relationgraph.class.inc.php');
|
||||
require_once(APPROOT.'/sources/Core/RelationGraph/RelationEdge.php');
|
||||
require_once(APPROOT.'/sources/Core/RelationGraph/RelationGraph.php');
|
||||
require_once(APPROOT.'/sources/Core/RelationGraph/RelationObjectNode.php');
|
||||
require_once(APPROOT.'/sources/Core/RelationGraph/RelationRedundancyNode.php');
|
||||
require_once(APPROOT.'core/displayablegraph.class.inc.php');
|
||||
$sRelation = utils::ReadParam('relation', 'impacts');
|
||||
$sDirection = utils::ReadParam('direction', 'down');
|
||||
@@ -1696,7 +1699,11 @@ EOF
|
||||
|
||||
case 'relation_json':
|
||||
require_once(APPROOT.'core/simplegraph.class.inc.php');
|
||||
require_once(APPROOT.'core/relationgraph.class.inc.php');
|
||||
|
||||
require_once(APPROOT.'/sources/Core/RelationGraph/RelationEdge.php');
|
||||
require_once(APPROOT.'/sources/Core/RelationGraph/RelationGraph.php');
|
||||
require_once(APPROOT.'/sources/Core/RelationGraph/RelationObjectNode.php');
|
||||
require_once(APPROOT.'/sources/Core/RelationGraph/RelationRedundancyNode.php');
|
||||
require_once(APPROOT.'core/displayablegraph.class.inc.php');
|
||||
$sRelation = utils::ReadParam('relation', 'impacts');
|
||||
$sDirection = utils::ReadParam('direction', 'down');
|
||||
@@ -1801,7 +1808,10 @@ EOF
|
||||
|
||||
case 'ticket_impact':
|
||||
require_once(APPROOT.'core/simplegraph.class.inc.php');
|
||||
require_once(APPROOT.'core/relationgraph.class.inc.php');
|
||||
require_once(APPROOT.'/sources/Core/RelationGraph/RelationEdge.php');
|
||||
require_once(APPROOT.'/sources/Core/RelationGraph/RelationGraph.php');
|
||||
require_once(APPROOT.'/sources/Core/RelationGraph/RelationObjectNode.php');
|
||||
require_once(APPROOT.'/sources/Core/RelationGraph/RelationRedundancyNode.php');
|
||||
require_once(APPROOT.'core/displayablegraph.class.inc.php');
|
||||
|
||||
$sRelation = utils::ReadParam('relation', 'impacts');
|
||||
|
||||
371
sources/Application/BulkExport/BulkExport.php
Normal file
371
sources/Application/BulkExport/BulkExport.php
Normal file
@@ -0,0 +1,371 @@
|
||||
<?php
|
||||
|
||||
use Combodo\iTop\Application\WebPage\Page;
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
|
||||
/**
|
||||
* Class BulkExport
|
||||
*
|
||||
* @copyright Copyright (C) 2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
abstract class BulkExport
|
||||
{
|
||||
protected $oSearch;
|
||||
protected $iChunkSize;
|
||||
protected $sFormatCode;
|
||||
protected $aStatusInfo;
|
||||
protected $oBulkExportResult;
|
||||
protected $sTmpFile;
|
||||
protected $bLocalizeOutput;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->oSearch = null;
|
||||
$this->iChunkSize = 0;
|
||||
$this->sFormatCode = null;
|
||||
$this->aStatusInfo = [
|
||||
'show_obsolete_data' => utils::ShowObsoleteData(),
|
||||
];
|
||||
$this->oBulkExportResult = null;
|
||||
$this->sTmpFile = '';
|
||||
$this->bLocalizeOutput = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the first class capable of exporting the data in the given format
|
||||
*
|
||||
* @param string $sFormatCode The lowercase format (e.g. html, csv, spreadsheet, xlsx, xml, json, pdf...)
|
||||
* @param DBSearch $oSearch The search/filter defining the set of objects to export or null when listing the supported formats
|
||||
*
|
||||
* @return BulkExport|null
|
||||
* @throws ReflectionException
|
||||
*/
|
||||
static public function FindExporter($sFormatCode, $oSearch = null)
|
||||
{
|
||||
foreach (get_declared_classes() as $sPHPClass) {
|
||||
$oRefClass = new ReflectionClass($sPHPClass);
|
||||
if ($oRefClass->isSubclassOf('BulkExport') && !$oRefClass->isAbstract()) {
|
||||
/** @var BulkExport $oBulkExporter */
|
||||
$oBulkExporter = new $sPHPClass();
|
||||
if ($oBulkExporter->IsFormatSupported($sFormatCode, $oSearch)) {
|
||||
if ($oSearch) {
|
||||
$oBulkExporter->SetObjectList($oSearch);
|
||||
}
|
||||
|
||||
return $oBulkExporter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the exporter corresponding to the given persistent token
|
||||
*
|
||||
* @param int $iPersistentToken The identifier of the BulkExportResult object storing the information
|
||||
*
|
||||
* @return BulkExport|null
|
||||
* @throws ArchivedObjectException
|
||||
* @throws CoreException
|
||||
* @throws ReflectionException
|
||||
*/
|
||||
static public function FindExporterFromToken($iPersistentToken = null)
|
||||
{
|
||||
$oBulkExporter = null;
|
||||
$oInfo = MetaModel::GetObject('BulkExportResult', $iPersistentToken, false);
|
||||
if ($oInfo && ($oInfo->Get('user_id') == UserRights::GetUserId())) {
|
||||
$sFormatCode = $oInfo->Get('format');
|
||||
$aStatusInfo = json_decode($oInfo->Get('status_info'), true);
|
||||
|
||||
$oSearch = DBObjectSearch::unserialize($oInfo->Get('search'));
|
||||
$oSearch->SetShowObsoleteData($aStatusInfo['show_obsolete_data']);
|
||||
$oBulkExporter = self::FindExporter($sFormatCode, $oSearch);
|
||||
if ($oBulkExporter) {
|
||||
$oBulkExporter->SetFormat($sFormatCode);
|
||||
$oBulkExporter->SetObjectList($oSearch);
|
||||
$oBulkExporter->SetChunkSize($oInfo->Get('chunk_size'));
|
||||
$oBulkExporter->SetStatusInfo($aStatusInfo);
|
||||
|
||||
$oBulkExporter->SetLocalizeOutput($oInfo->Get('localize_output'));
|
||||
|
||||
|
||||
$oBulkExporter->sTmpFile = $oInfo->Get('temp_file_path');
|
||||
$oBulkExporter->oBulkExportResult = $oInfo;
|
||||
}
|
||||
}
|
||||
|
||||
return $oBulkExporter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $data
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function AppendToTmpFile($data)
|
||||
{
|
||||
if ($this->sTmpFile == '') {
|
||||
$this->sTmpFile = $this->MakeTmpFile($this->GetFileExtension());
|
||||
}
|
||||
$hFile = fopen($this->sTmpFile, 'ab');
|
||||
if ($hFile !== false) {
|
||||
fwrite($hFile, $data);
|
||||
fclose($hFile);
|
||||
}
|
||||
}
|
||||
|
||||
public function GetTmpFilePath()
|
||||
{
|
||||
return $this->sTmpFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists all possible export formats. The output is a hash array in the form: 'format_code' => 'localized format label'
|
||||
*
|
||||
* @return array :string
|
||||
*/
|
||||
static public function FindSupportedFormats()
|
||||
{
|
||||
$aSupportedFormats = array();
|
||||
foreach (get_declared_classes() as $sPHPClass) {
|
||||
$oRefClass = new ReflectionClass($sPHPClass);
|
||||
if ($oRefClass->isSubClassOf('BulkExport') && !$oRefClass->isAbstract()) {
|
||||
$oBulkExporter = new $sPHPClass;
|
||||
$aFormats = $oBulkExporter->GetSupportedFormats();
|
||||
$aSupportedFormats = array_merge($aSupportedFormats, $aFormats);
|
||||
}
|
||||
}
|
||||
|
||||
return $aSupportedFormats;
|
||||
}
|
||||
|
||||
/**
|
||||
* (non-PHPdoc)
|
||||
*
|
||||
* @see iBulkExport::SetChunkSize()
|
||||
*/
|
||||
public function SetChunkSize($iChunkSize)
|
||||
{
|
||||
$this->iChunkSize = $iChunkSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $bLocalizeOutput
|
||||
*/
|
||||
public function SetLocalizeOutput($bLocalizeOutput)
|
||||
{
|
||||
$this->bLocalizeOutput = $bLocalizeOutput;
|
||||
}
|
||||
|
||||
/**
|
||||
* (non-PHPdoc)
|
||||
*
|
||||
* @see iBulkExport::SetObjectList()
|
||||
*/
|
||||
public function SetObjectList(DBSearch $oSearch)
|
||||
{
|
||||
$oSearch->SetShowObsoleteData($this->aStatusInfo['show_obsolete_data']);
|
||||
$this->oSearch = $oSearch;
|
||||
}
|
||||
|
||||
public function SetFormat($sFormatCode)
|
||||
{
|
||||
$this->sFormatCode = $sFormatCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* (non-PHPdoc)
|
||||
*
|
||||
* @see iBulkExport::IsFormatSupported()
|
||||
*/
|
||||
public function IsFormatSupported($sFormatCode, $oSearch = null)
|
||||
{
|
||||
return array_key_exists($sFormatCode, $this->GetSupportedFormats());
|
||||
}
|
||||
|
||||
/**
|
||||
* (non-PHPdoc)
|
||||
*
|
||||
* @see iBulkExport::GetSupportedFormats()
|
||||
*/
|
||||
public function GetSupportedFormats()
|
||||
{
|
||||
return array(); // return array('csv' => Dict::S('UI:ExportFormatCSV'));
|
||||
}
|
||||
|
||||
|
||||
public function SetHttpHeaders(WebPage $oPage)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function GetHeader()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
abstract public function GetNextChunk(&$aStatus);
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function GetFooter()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function SaveState()
|
||||
{
|
||||
if ($this->oBulkExportResult === null) {
|
||||
$this->oBulkExportResult = new BulkExportResult();
|
||||
$this->oBulkExportResult->Set('format', $this->sFormatCode);
|
||||
$this->oBulkExportResult->Set('search', $this->oSearch->serialize());
|
||||
$this->oBulkExportResult->Set('chunk_size', $this->iChunkSize);
|
||||
$this->oBulkExportResult->Set('localize_output', $this->bLocalizeOutput);
|
||||
}
|
||||
$this->oBulkExportResult->Set('status_info', json_encode($this->GetStatusInfo()));
|
||||
$this->oBulkExportResult->Set('temp_file_path', $this->sTmpFile);
|
||||
utils::PushArchiveMode(false);
|
||||
$ret = $this->oBulkExportResult->DBWrite();
|
||||
utils::PopArchiveMode();
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
public function Cleanup()
|
||||
{
|
||||
if (($this->oBulkExportResult && (!$this->oBulkExportResult->IsNew()))) {
|
||||
$sFilename = $this->oBulkExportResult->Get('temp_file_path');
|
||||
if ($sFilename != '') {
|
||||
@unlink($sFilename);
|
||||
}
|
||||
utils::PushArchiveMode(false);
|
||||
$this->oBulkExportResult->DBDelete();
|
||||
utils::PopArchiveMode();
|
||||
}
|
||||
}
|
||||
|
||||
public function EnumFormParts()
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated 3.0.0 use GetFormPart instead
|
||||
*/
|
||||
public function DisplayFormPart(WebPage $oP, $sPartId)
|
||||
{
|
||||
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('use GetFormPart instead');
|
||||
$oP->AddSubBlock($this->GetFormPart($oP, $sPartId));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param \Combodo\iTop\Application\WebPage\WebPage $oP
|
||||
* @param $sPartId
|
||||
*
|
||||
* @return UIContentBlock
|
||||
*/
|
||||
public function GetFormPart(WebPage $oP, $sPartId)
|
||||
{
|
||||
}
|
||||
|
||||
public function DisplayUsage(Page $oP)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function ReadParameters()
|
||||
{
|
||||
$this->bLocalizeOutput = !((bool)utils::ReadParam('no_localize', 0, true, 'integer'));
|
||||
}
|
||||
|
||||
public function GetResultAsHtml()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function GetRawResult()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function GetMimeType()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function GetFileExtension()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function GetCharacterSet()
|
||||
{
|
||||
return 'UTF-8';
|
||||
}
|
||||
|
||||
public function GetStatistics()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function SetFields($sFields)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function GetDownloadFileName()
|
||||
{
|
||||
return Dict::Format('Core:BulkExportOf_Class', MetaModel::GetName($this->oSearch->GetClass())).'.'.$this->GetFileExtension();
|
||||
}
|
||||
|
||||
public function SetStatusInfo($aStatusInfo)
|
||||
{
|
||||
$this->aStatusInfo = $aStatusInfo;
|
||||
}
|
||||
|
||||
public function GetStatusInfo()
|
||||
{
|
||||
return $this->aStatusInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $sExtension
|
||||
*
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function MakeTmpFile($sExtension)
|
||||
{
|
||||
if (!is_dir(utils::GetDataPath()."bulk_export")) {
|
||||
@mkdir(utils::GetDataPath()."bulk_export", 0777, true /* recursive */);
|
||||
clearstatcache();
|
||||
}
|
||||
if (!is_writable(utils::GetDataPath()."bulk_export")) {
|
||||
throw new Exception('Data directory "'.utils::GetDataPath().'bulk_export" could not be written.');
|
||||
}
|
||||
|
||||
$iNum = rand();
|
||||
do {
|
||||
$iNum++;
|
||||
$sToken = sprintf("%08x", $iNum);
|
||||
$sFileName = utils::GetDataPath()."bulk_export/$sToken.".$sExtension;
|
||||
$hFile = @fopen($sFileName, 'x');
|
||||
} while ($hFile === false);
|
||||
|
||||
fclose($hFile);
|
||||
|
||||
return $sFileName;
|
||||
}
|
||||
}
|
||||
17
sources/Application/BulkExport/BulkExportException.php
Normal file
17
sources/Application/BulkExport/BulkExportException.php
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
class BulkExportException extends Exception
|
||||
{
|
||||
protected $sLocalizedMessage;
|
||||
|
||||
public function __construct($message, $sLocalizedMessage, $code = 0, $previous = null)
|
||||
{
|
||||
parent::__construct($message, $code, $previous);
|
||||
$this->sLocalizedMessage = $sLocalizedMessage;
|
||||
}
|
||||
|
||||
public function GetLocalizedMessage()
|
||||
{
|
||||
return $this->sLocalizedMessage;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
class BulkExportMissingParameterException extends BulkExportException
|
||||
{
|
||||
public function __construct($sFieldCode)
|
||||
{
|
||||
parent::__construct('Missing parameter: ' . $sFieldCode, Dict::Format('Core:BulkExport:MissingParameter_Param', $sFieldCode));
|
||||
}
|
||||
|
||||
}
|
||||
38
sources/Application/BulkExport/BulkExportResultGC.php
Normal file
38
sources/Application/BulkExport/BulkExportResultGC.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Garbage collector for cleaning "old" export results from the database and the disk.
|
||||
* This background process runs once per day and deletes the results of all exports which
|
||||
* are older than one day.
|
||||
*/
|
||||
class BulkExportResultGC implements iBackgroundProcess
|
||||
{
|
||||
public function GetPeriodicity()
|
||||
{
|
||||
return 24 * 3600; // seconds
|
||||
}
|
||||
|
||||
public function Process($iTimeLimit)
|
||||
{
|
||||
$sDateLimit = date(AttributeDateTime::GetSQLFormat(), time() - 24 * 3600); // Every BulkExportResult older than one day will be deleted
|
||||
|
||||
$sOQL = "SELECT BulkExportResult WHERE created < '$sDateLimit'";
|
||||
$iProcessed = 0;
|
||||
while (time() < $iTimeLimit) {
|
||||
// Next one ?
|
||||
$oSet = new CMDBObjectSet(DBObjectSearch::FromOQL($sOQL), array('created' => true) /* order by*/, array(), null, 1 /* limit count */);
|
||||
$oSet->OptimizeColumnLoad(array('BulkExportResult' => array('temp_file_path')));
|
||||
$oResult = $oSet->Fetch();
|
||||
if (is_null($oResult)) {
|
||||
// Nothing to be done
|
||||
break;
|
||||
}
|
||||
$iProcessed++;
|
||||
@unlink($oResult->Get('temp_file_path'));
|
||||
utils::PushArchiveMode(false);
|
||||
$oResult->DBDelete();
|
||||
utils::PopArchiveMode();
|
||||
}
|
||||
return "Cleaned $iProcessed old export results(s).";
|
||||
}
|
||||
}
|
||||
110
sources/Application/DataModel/Event/Event.php
Normal file
110
sources/Application/DataModel/Event/Event.php
Normal file
@@ -0,0 +1,110 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Copyright (C) 2013-2024 Combodo SAS
|
||||
*
|
||||
* 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 Event extends DBObject implements iDisplay
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "core/cmdb,view_in_gui",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_event",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "realclass",
|
||||
"order_by_default" => array('date' => false)
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeText("message", array("allowed_values" => null, "sql" => "message", "default_value" => null, "is_null_allowed" => false, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeDateTime("date", array("allowed_values" => null, "sql" => "date", "default_value" => "NOW()", "is_null_allowed" => false, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("userinfo", array("allowed_values" => null, "sql" => "userinfo", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
|
||||
// MetaModel::Init_AddAttribute(new AttributeString("userinfo", array("allowed_values"=>null, "sql"=>"userinfo", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('date', 'message', 'userinfo')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('date', 'finalclass', 'message')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
|
||||
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps the given context parameter name to the appropriate filter/search code for this class
|
||||
* @param string $sContextParam Name of the context parameter, i.e. 'org_id'
|
||||
* @return string Filter code, i.e. 'customer_id'
|
||||
*/
|
||||
public static function MapContextParam($sContextParam)
|
||||
{
|
||||
if ($sContextParam == 'menu') {
|
||||
return null;
|
||||
} else {
|
||||
return $sContextParam;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns a 'hilight' CSS class, used to hilight a given row in a table
|
||||
* There are currently (i.e defined in the CSS) 4 possible values HILIGHT_CLASS_CRITICAL,
|
||||
* HILIGHT_CLASS_WARNING, HILIGHT_CLASS_OK, HILIGHT_CLASS_NONE
|
||||
* To Be overridden by derived classes
|
||||
* @param void
|
||||
* @return String The desired higlight class for the object/row
|
||||
*/
|
||||
public function GetHilightClass()
|
||||
{
|
||||
// Possible return values are:
|
||||
// HILIGHT_CLASS_CRITICAL, HILIGHT_CLASS_WARNING, HILIGHT_CLASS_OK, HILIGHT_CLASS_NONE
|
||||
return HILIGHT_CLASS_NONE; // Not hilighted by default
|
||||
}
|
||||
|
||||
public static function GetUIPage()
|
||||
{
|
||||
return 'UI.php';
|
||||
}
|
||||
|
||||
function DisplayDetails(\Combodo\iTop\Application\WebPage\WebPage $oPage, $bEditMode = false)
|
||||
{
|
||||
// Object's details
|
||||
//$this->DisplayBareHeader($oPage, $bEditMode);
|
||||
$oPage->AddTabContainer(OBJECT_PROPERTIES_TAB);
|
||||
$oPage->SetCurrentTabContainer(OBJECT_PROPERTIES_TAB);
|
||||
$oPage->SetCurrentTab('UI:PropertiesTab');
|
||||
$this->DisplayBareProperties($oPage, $bEditMode);
|
||||
}
|
||||
|
||||
function DisplayBareProperties(\Combodo\iTop\Application\WebPage\WebPage $oPage, $bEditMode = false, $sPrefix = '', $aExtraParams = array())
|
||||
{
|
||||
if ($bEditMode) return array(); // Not editable
|
||||
|
||||
$aDetails = array();
|
||||
$sClass = get_class($this);
|
||||
$aZList = MetaModel::FlattenZlist(MetaModel::GetZListItems($sClass, 'details'));
|
||||
foreach ($aZList as $sAttCode) {
|
||||
$sDisplayValue = $this->GetAsHTML($sAttCode);
|
||||
$aDetails[] = array('label' => '<span title="' . MetaModel::GetDescription($sClass, $sAttCode) . '">' . MetaModel::GetLabel($sClass, $sAttCode) . '</span>', 'value' => $sDisplayValue);
|
||||
}
|
||||
$oPage->Details($aDetails);
|
||||
|
||||
return array();
|
||||
}
|
||||
}
|
||||
96
sources/Application/DataModel/Event/EventIssue.php
Normal file
96
sources/Application/DataModel/Event/EventIssue.php
Normal file
@@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
class EventIssue extends Event
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "core/cmdb,view_in_gui",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_event_issue",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"order_by_default" => array('date' => false)
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeString("issue", array("allowed_values" => null, "sql" => "issue", "default_value" => null, "is_null_allowed" => false, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("impact", array("allowed_values" => null, "sql" => "impact", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("page", array("allowed_values" => null, "sql" => "page", "default_value" => null, "is_null_allowed" => false, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributePropertySet("arguments_post", array("allowed_values" => null, "sql" => "arguments_post", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributePropertySet("arguments_get", array("allowed_values" => null, "sql" => "arguments_get", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeTable("callstack", array("allowed_values" => null, "sql" => "callstack", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributePropertySet("data", array("allowed_values" => null, "sql" => "data", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('date', 'message', 'userinfo', 'issue', 'impact', 'page', 'arguments_post', 'arguments_get', 'callstack', 'data')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('date', 'userinfo', 'issue', 'impact')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
|
||||
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
|
||||
}
|
||||
|
||||
protected function OnInsert()
|
||||
{
|
||||
// Init page information: name, arguments
|
||||
//
|
||||
$this->Set('page', @$GLOBALS['_SERVER']['SCRIPT_NAME']);
|
||||
|
||||
if (strlen($this->Get('userinfo')) == 0) {
|
||||
$this->Set('userinfo', UserRights::GetUserId());
|
||||
}
|
||||
|
||||
if (array_key_exists('_GET', $GLOBALS) && is_array($GLOBALS['_GET'])) {
|
||||
$this->Set('arguments_get', $this->SanitizeRequestParams($GLOBALS['_GET']));
|
||||
} else {
|
||||
$this->Set('arguments_get', array());
|
||||
}
|
||||
|
||||
if (array_key_exists('_POST', $GLOBALS) && is_array($GLOBALS['_POST'])) {
|
||||
$this->Set('arguments_post', $this->SanitizeRequestParams($GLOBALS['_POST']));
|
||||
} else {
|
||||
$this->Set('arguments_post', array());
|
||||
}
|
||||
$sLength = mb_strlen($this->Get('issue'));
|
||||
if ($sLength > 255) {
|
||||
$this->Set('issue', mb_substr($this->Get('issue'), 0, 210) . " -truncated ($sLength chars)");
|
||||
}
|
||||
|
||||
$sLength = mb_strlen($this->Get('impact'));
|
||||
if ($sLength > 255) {
|
||||
$this->Set('impact', mb_substr($this->Get('impact'), 0, 210) . " -truncated ($sLength chars)");
|
||||
}
|
||||
|
||||
$sLength = mb_strlen($this->Get('page'));
|
||||
if ($sLength > 255) {
|
||||
$this->Set('page', mb_substr($this->Get('page'), 0, 210) . " -truncated ($sLength chars)");
|
||||
}
|
||||
}
|
||||
|
||||
protected function SanitizeRequestParams(array $aParams): array
|
||||
{
|
||||
$aSanitizedParams = [];
|
||||
|
||||
foreach ($aParams as $sKey => $sValue) {
|
||||
if (is_string($sValue)) {
|
||||
if (stristr($sKey, 'pwd') !== false || stristr($sKey, 'passwd') !== false || stristr($sKey, 'password') !== false) {
|
||||
$aSanitizedParams[$sKey] = '****';
|
||||
} elseif (mb_strlen($sValue) < 256) {
|
||||
$aSanitizedParams[$sKey] = $sValue;
|
||||
} else {
|
||||
$aSanitizedParams[$sKey] = '!long string: ' . mb_strlen($sValue) . ' chars';
|
||||
}
|
||||
} else {
|
||||
// Not a string (avoid warnings in case the value cannot be easily cast into a string)
|
||||
$aSanitizedParams[$sKey] = @(string)$sValue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return $aSanitizedParams;
|
||||
}
|
||||
}
|
||||
39
sources/Application/DataModel/Event/EventLoginUsage.php
Normal file
39
sources/Application/DataModel/Event/EventLoginUsage.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
class EventLoginUsage extends Event
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "core/cmdb,view_in_gui",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_event_loginusage",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"order_by_default" => array('date' => false)
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("user_id", array("targetclass" => "User", "jointype" => "", "allowed_values" => null, "sql" => "user_id", "is_null_allowed" => false, "on_target_delete" => DEL_SILENT, "depends_on" => array())));
|
||||
$aZList = array('date', 'user_id');
|
||||
if (MetaModel::IsValidAttCode('Contact', 'name')) {
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalField("contact_name", array("allowed_values" => null, "extkey_attcode" => "user_id", "target_attcode" => "contactid", "is_null_allowed" => true, "depends_on" => array())));
|
||||
$aZList[] = 'contact_name';
|
||||
}
|
||||
if (MetaModel::IsValidAttCode('Contact', 'email')) {
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalField("contact_email", array("allowed_values" => null, "extkey_attcode" => "user_id", "target_attcode" => "email", "is_null_allowed" => true, "depends_on" => array())));
|
||||
$aZList[] = 'contact_email';
|
||||
}
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array_merge($aZList, array('userinfo', 'message'))); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array_merge($aZList, array('userinfo'))); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', $aZList); // Criteria of the std search form
|
||||
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
|
||||
}
|
||||
}
|
||||
37
sources/Application/DataModel/Event/EventNotification.php
Normal file
37
sources/Application/DataModel/Event/EventNotification.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
class EventNotification extends Event
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "core/cmdb,view_in_gui",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_event_notification",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"order_by_default" => array('date' => false),
|
||||
'indexes' => array(
|
||||
array('object_class', 'object_id'),
|
||||
)
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("trigger_id", array("targetclass" => "Trigger", "jointype" => "", "allowed_values" => null, "sql" => "trigger_id", "is_null_allowed" => false, "on_target_delete" => DEL_AUTO, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("action_id", array("targetclass" => "Action", "jointype" => "", "allowed_values" => null, "sql" => "action_id", "is_null_allowed" => false, "on_target_delete" => DEL_AUTO, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeInteger("object_id", array("allowed_values" => null, "sql" => "object_id", "default_value" => 0, "is_null_allowed" => false, "depends_on" => array())));
|
||||
//@since 3.2.0
|
||||
MetaModel::Init_AddAttribute(new AttributeClass("object_class", array("class_category" => "", "more_values" => "", "sql" => "object_class", "default_value" => null, "is_null_allowed" => true /*to avoid setting AbstractResource as default in database*/, "depends_on" => array())));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('date', 'message', 'userinfo', 'trigger_id', 'action_id', 'object_class', 'object_id')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('date', 'message')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
|
||||
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
class EventNotificationEmail extends EventNotification
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "core/cmdb,view_in_gui",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_event_email",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"order_by_default" => array('date' => false)
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeText("to", array("allowed_values" => null, "sql" => "to", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("cc", array("allowed_values" => null, "sql" => "cc", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("bcc", array("allowed_values" => null, "sql" => "bcc", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("from", array("allowed_values" => null, "sql" => "from", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("subject", array("allowed_values" => null, "sql" => "subject", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeHTML("body", array("allowed_values" => null, "sql" => "body", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeTable("attachments", array("allowed_values" => null, "sql" => "attachments", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('date', 'userinfo', 'message', 'trigger_id', 'action_id', 'object_class', 'object_id', 'to', 'cc', 'bcc', 'from', 'subject', 'body', 'attachments')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('date', 'message', 'to', 'subject', 'attachments')); // Attributes to be displayed for a list
|
||||
|
||||
// Search criteria
|
||||
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
|
||||
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
|
||||
}
|
||||
}
|
||||
29
sources/Application/DataModel/Event/EventOnObject.php
Normal file
29
sources/Application/DataModel/Event/EventOnObject.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
class EventOnObject extends Event
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "core/cmdb,view_in_gui",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_event_onobject",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
"order_by_default" => array('date' => false)
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeString("obj_class", array("allowed_values" => null, "sql" => "obj_class", "default_value" => null, "is_null_allowed" => false, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeInteger("obj_key", array("allowed_values" => null, "sql" => "obj_key", "default_value" => null, "is_null_allowed" => false, "depends_on" => array())));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('date', 'userinfo', 'obj_class', 'obj_key', 'message')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('date', 'userinfo', 'obj_class', 'obj_key', 'message')); // Attributes to be displayed for a list
|
||||
}
|
||||
}
|
||||
36
sources/Application/DataModel/Event/EventRestService.php
Normal file
36
sources/Application/DataModel/Event/EventRestService.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
class EventRestService extends Event
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "core/cmdb,view_in_gui",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_event_restservice",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"order_by_default" => array('date' => false)
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeString("operation", array("allowed_values" => null, "sql" => "operation", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("version", array("allowed_values" => null, "sql" => "version", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("json_input", array("allowed_values" => null, "sql" => "json_input", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeInteger("code", array("allowed_values" => null, "sql" => "code", "default_value" => 0, "is_null_allowed" => false, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("json_output", array("allowed_values" => null, "sql" => "json_output", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("provider", array("allowed_values" => null, "sql" => "provider", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('date', 'userinfo', 'operation', 'version', 'json_input', 'message', 'code', 'json_output', 'provider')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('date', 'userinfo', 'operation', 'message')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
|
||||
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
|
||||
}
|
||||
}
|
||||
36
sources/Application/DataModel/Event/EventWebService.php
Normal file
36
sources/Application/DataModel/Event/EventWebService.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
class EventWebService extends Event
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "core/cmdb,view_in_gui",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_event_webservice",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"order_by_default" => array('date' => false)
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeString("verb", array("allowed_values" => null, "sql" => "verb", "default_value" => null, "is_null_allowed" => false, "depends_on" => array())));
|
||||
//MetaModel::Init_AddAttribute(new AttributeStructure("arguments", array("allowed_values"=>null, "sql"=>"data", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeBoolean("result", array("allowed_values" => null, "sql" => "result", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("log_info", array("allowed_values" => null, "sql" => "log_info", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("log_warning", array("allowed_values" => null, "sql" => "log_warning", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("log_error", array("allowed_values" => null, "sql" => "log_error", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("data", array("allowed_values" => null, "sql" => "data", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('date', 'userinfo', 'verb', 'result', 'log_info', 'log_warning', 'log_error', 'data')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('date', 'userinfo', 'verb', 'result')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
|
||||
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
|
||||
}
|
||||
}
|
||||
234
sources/Application/DataModel/TriggerAndAction/Action.php
Normal file
234
sources/Application/DataModel/TriggerAndAction/Action.php
Normal file
@@ -0,0 +1,234 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* A user defined action, to customize the application
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
abstract class Action extends cmdbAbstractObject
|
||||
{
|
||||
/**
|
||||
* @throws \CoreException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "grant_by_profile,core/cmdb",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "name",
|
||||
"complementary_name_attcode" => ['finalclass', 'description'],
|
||||
"state_attcode" => "status",
|
||||
"reconc_keys" => ['name'],
|
||||
"db_table" => "priv_action",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "realclass",
|
||||
"style" => new ormStyle("ibo-dm-class--Action", "ibo-dm-class-alt--Action", "var(--ibo-dm-class--Action--main-color)", "var(--ibo-dm-class--Action--complementary-color)", null, '../images/icons/icons8-in-transit.svg'),
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values" => null, "sql" => "name", "default_value" => null, "is_null_allowed" => false, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values" => null, "sql" => "description", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("status", array(
|
||||
"allowed_values" => new ValueSetEnum(array('test' => 'Being tested', 'enabled' => 'In production', 'disabled' => 'Inactive')),
|
||||
"styled_values" => [
|
||||
'test' => new ormStyle('ibo-dm-enum--Action-status-test', 'ibo-dm-enum-alt--Action-status-test', 'var(--ibo-dm-enum--Action-status-test--main-color)', 'var(--ibo-dm-enum--Action-status-test--complementary-color)', null, null),
|
||||
'enabled' => new ormStyle('ibo-dm-enum--Action-status-enabled', 'ibo-dm-enum-alt--Action-status-enabled', 'var(--ibo-dm-enum--Action-status-enabled--main-color)', 'var(--ibo-dm-enum--Action-status-enabled--complementary-color)', 'fas fa-check', null),
|
||||
'disabled' => new ormStyle('ibo-dm-enum--Action-status-disabled', 'ibo-dm-enum-alt--Action-status-disabled', 'var(--ibo-dm-enum--Action-status-disabled--main-color)', 'var(--ibo-dm-enum--Action-status-disabled--complementary-color)', null, null),
|
||||
],
|
||||
"display_style" => 'list',
|
||||
"sql" => "status",
|
||||
"default_value" => "test",
|
||||
"is_null_allowed" => false,
|
||||
"depends_on" => array(),
|
||||
)));
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect("trigger_list",
|
||||
array("linked_class" => "lnkTriggerAction", "ext_key_to_me" => "action_id", "ext_key_to_remote" => "trigger_id", "allowed_values" => null, "count_min" => 0, "count_max" => 0, "depends_on" => array(), "display_style" => 'property')));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("asynchronous", array("allowed_values" => new ValueSetEnum(['use_global_setting' => 'Use global settings', 'yes' => 'Yes', 'no' => 'No']), "sql" => "asynchronous", "default_value" => 'use_global_setting', "is_null_allowed" => false, "depends_on" => array())));
|
||||
|
||||
// Display lists
|
||||
// - Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('details', array('name', 'description', 'status', 'trigger_list'));
|
||||
// - Attributes to be displayed for a list
|
||||
MetaModel::Init_SetZListItems('list', array('finalclass', 'name', 'description', 'status'));
|
||||
// Search criteria
|
||||
// - Default criteria of the search form
|
||||
MetaModel::Init_SetZListItems('default_search', array('name', 'description', 'status'));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Encapsulate the execution of the action and handle failure & logging
|
||||
*
|
||||
* @param \Trigger $oTrigger
|
||||
* @param array $aContextArgs
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function DoExecute($oTrigger, $aContextArgs);
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public function IsActive()
|
||||
{
|
||||
switch ($this->Get('status')) {
|
||||
case 'enabled':
|
||||
case 'test':
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the current action status is set on "test"
|
||||
*
|
||||
* @return bool
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public function IsBeingTested()
|
||||
{
|
||||
switch ($this->Get('status')) {
|
||||
case 'test':
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public function AfterInsert()
|
||||
{
|
||||
parent::AfterInsert();
|
||||
$this->DoCheckIfHasTrigger();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public function AfterUpdate()
|
||||
{
|
||||
parent::AfterUpdate();
|
||||
$this->DoCheckIfHasTrigger();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the Action has at least 1 trigger linked. Otherwise, it adds a warning.
|
||||
* @return void
|
||||
* @since 3.0.0
|
||||
*/
|
||||
protected function DoCheckIfHasTrigger()
|
||||
{
|
||||
$oTriggersSet = $this->Get('trigger_list');
|
||||
if ($oTriggersSet->Count() === 0) {
|
||||
$this->m_aCheckWarnings[] = Dict::S('Action:WarningNoTriggerLinked');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 3.2.0 N°5472 method creation
|
||||
*/
|
||||
public function DisplayBareRelations(\Combodo\iTop\Application\WebPage\WebPage $oPage, $bEditMode = false)
|
||||
{
|
||||
parent::DisplayBareRelations($oPage, false);
|
||||
|
||||
if ($oPage instanceof iTopWebPage && !$this->IsNew()) {
|
||||
$this->GenerateLastExecutionsTab($oPage, $bEditMode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 3.2.0 N°5472 method creation
|
||||
*/
|
||||
protected function GenerateLastExecutionsTab(iTopWebPage $oPage, $bEditMode)
|
||||
{
|
||||
$oRouter = \Combodo\iTop\Service\Router\Router::GetInstance();
|
||||
$sActionLastExecutionsPageUrl = $oRouter->GenerateUrl('notifications.action.last_executions_tab', ['action_id' => $this->GetKey()]);
|
||||
$oPage->AddAjaxTab('action_errors', $sActionLastExecutionsPageUrl, false, Dict::S('Action:last_executions_tab'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Combodo\iTop\Application\WebPage\WebPage $oPage
|
||||
*
|
||||
* @throws \ApplicationException
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \ConfigException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \DictExceptionMissingString
|
||||
* @throws \InvalidConfigParamException
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
* @throws \OQLException
|
||||
* @throws \ReflectionException
|
||||
* @since 3.2.0 N°5472 method creation
|
||||
*/
|
||||
public function GetLastExecutionsTabContent(\Combodo\iTop\Application\WebPage\WebPage $oPage): void
|
||||
{
|
||||
$oConfig = utils::GetConfig();
|
||||
$sLastExecutionDaysConfigParamName = 'notifications.last_executions_days';
|
||||
$iLastExecutionDays = $oConfig->Get($sLastExecutionDaysConfigParamName);
|
||||
|
||||
if ($iLastExecutionDays < 0) {
|
||||
throw new InvalidConfigParamException("Invalid value for {$sLastExecutionDaysConfigParamName} config parameter. Param desc: " . $oConfig->GetDescription($sLastExecutionDaysConfigParamName));
|
||||
}
|
||||
|
||||
$sActionQueryOql = 'SELECT EventNotification WHERE action_id = :action_id';
|
||||
$aActionQueryParams = ['action_id' => $this->GetKey()];
|
||||
if ($iLastExecutionDays > 0) {
|
||||
$sActionQueryOql .= ' AND date > DATE_SUB(NOW(), INTERVAL :days DAY)';
|
||||
$aActionQueryParams['days'] = $iLastExecutionDays;
|
||||
$sActionQueryLimit = Dict::Format('Action:last_executions_tab_limit_days', $iLastExecutionDays);
|
||||
} else {
|
||||
$sActionQueryLimit = Dict::S('Action:last_executions_tab_limit_none');
|
||||
}
|
||||
|
||||
$oActionFilter = DBObjectSearch::FromOQL($sActionQueryOql, $aActionQueryParams);
|
||||
$oSet = new DBObjectSet($oActionFilter, ['date' => false]);
|
||||
|
||||
$sPanelTitle = Dict::Format('Action:last_executions_tab_panel_title', $sActionQueryLimit);
|
||||
$oExecutionsListBlock = \Combodo\iTop\Application\UI\Base\Component\DataTable\DataTableUIBlockFactory::MakeForResult($oPage, 'action_executions_list', $oSet, ['panel_title' => $sPanelTitle]);
|
||||
|
||||
$oPage->AddUiBlock($oExecutionsListBlock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Will be overloaded by the children classes to return the value of their global asynchronous setting (eg. `email_asynchronous` for `\ActionEmail`, `prefer_asynchronous` for `\ActionWebhook`, ...)
|
||||
*
|
||||
* @return bool true if the global setting for this kind of action if to be executed asynchronously, false otherwise.
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public static function GetAsynchronousGlobalSetting(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool true if that action instance should be executed asynchronously, otherwise false
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function IsAsynchronous(): bool
|
||||
{
|
||||
$sAsynchronous = $this->Get('asynchronous');
|
||||
if ($sAsynchronous === 'use_global_setting') {
|
||||
return static::GetAsynchronousGlobalSetting();
|
||||
}
|
||||
return $sAsynchronous === 'yes';
|
||||
}
|
||||
}
|
||||
567
sources/Application/DataModel/TriggerAndAction/ActionEmail.php
Normal file
567
sources/Application/DataModel/TriggerAndAction/ActionEmail.php
Normal file
@@ -0,0 +1,567 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* An email notification
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
class ActionEmail extends ActionNotification
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
* @since 3.0.1
|
||||
*/
|
||||
const ENUM_HEADER_NAME_MESSAGE_ID = 'Message-ID';
|
||||
/**
|
||||
* @var string
|
||||
* @since 3.0.1
|
||||
*/
|
||||
const ENUM_HEADER_NAME_REFERENCES = 'References';
|
||||
/**
|
||||
* @var string
|
||||
* @since 3.1.0
|
||||
*/
|
||||
const TEMPLATE_BODY_CONTENT = '$content$';
|
||||
/**
|
||||
* Wraps the 'body' of the message for previewing inside an IFRAME -- i.e. without any of the iTop stylesheets being applied
|
||||
* @var string
|
||||
* @since 3.1.0
|
||||
*/
|
||||
const CONTENT_HIGHLIGHT = '<div style="border:2px dashed #6800ff;position:relative;padding:2px;margin-top:14px;"><div style="background-color:#6800ff;color:#fff;font-family:Courier New, sans-serif;font-size:14px;line-height:16px;padding:3px;display:block;position:absolute;top:-22px;right:0;">$content$</div>%s</div>';
|
||||
/**
|
||||
* Wraps a placeholder of the email's body for previewing inside an IFRAME -- i.e. without any of the iTop stylesheets being applied
|
||||
* @var string
|
||||
*/
|
||||
const FIELD_HIGHLIGHT = '<span style="background-color:#6800ff;color:#fff;font-size:smaller;font-family:Courier New, sans-serif;padding:2px;">\\$$1\\$</span>';
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "grant_by_profile,core/cmdb,application",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "name",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array('name'),
|
||||
"db_table" => "priv_action_email",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
'style' => new ormStyle(null, null, null, null, null, '../images/icons/icons8-mailing.svg'),
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeEmailAddress("test_recipient", array("allowed_values" => null, "sql" => "test_recipient", "default_value" => "", "is_null_allowed" => true, "depends_on" => array())));
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeString("from", array("allowed_values" => null, "sql" => "from", "default_value" => null, "is_null_allowed" => false, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("from_label", array("allowed_values" => null, "sql" => "from_label", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("reply_to", array("allowed_values" => null, "sql" => "reply_to", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("reply_to_label", array("allowed_values" => null, "sql" => "reply_to_label", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeOQL("to", array("allowed_values" => null, "sql" => "to", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeOQL("cc", array("allowed_values" => null, "sql" => "cc", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeOQL("bcc", array("allowed_values" => null, "sql" => "bcc", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeTemplateString("subject", array("allowed_values" => null, "sql" => "subject", "default_value" => null, "is_null_allowed" => false, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeTemplateHTML("body", array("allowed_values" => null, "sql" => "body", "default_value" => null, "is_null_allowed" => false, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("importance", array("allowed_values" => new ValueSetEnum('low,normal,high'), "sql" => "importance", "default_value" => 'normal', "is_null_allowed" => false, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeBlob("html_template", array("is_null_allowed" => true, "depends_on" => array(), "always_load_in_tables" => false)));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("ignore_notify", array("allowed_values" => new ValueSetEnum('yes,no'), "sql" => "ignore_notify", "default_value" => 'yes', "is_null_allowed" => false, "depends_on" => array())));
|
||||
|
||||
|
||||
// Display lists
|
||||
// - Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('details', array(
|
||||
'col:col1' => array(
|
||||
'fieldset:ActionEmail:main' => array(
|
||||
0 => 'name',
|
||||
1 => 'description',
|
||||
2 => 'status',
|
||||
3 => 'language',
|
||||
4 => 'html_template',
|
||||
5 => 'subject',
|
||||
6 => 'body',
|
||||
// 5 => 'importance', not handled when sending the mail, better hide it then
|
||||
),
|
||||
'fieldset:ActionEmail:trigger' => array(
|
||||
0 => 'trigger_list',
|
||||
1 => 'asynchronous'
|
||||
),
|
||||
),
|
||||
'col:col2' => array(
|
||||
'fieldset:ActionEmail:recipients' => array(
|
||||
0 => 'from',
|
||||
1 => 'from_label',
|
||||
2 => 'reply_to',
|
||||
3 => 'reply_to_label',
|
||||
4 => 'test_recipient',
|
||||
5 => 'ignore_notify',
|
||||
6 => 'to',
|
||||
7 => 'cc',
|
||||
8 => 'bcc',
|
||||
),
|
||||
),
|
||||
));
|
||||
|
||||
// - Attributes to be displayed for a list
|
||||
MetaModel::Init_SetZListItems('list', array('status', 'to', 'subject', 'language'));
|
||||
// Search criteria
|
||||
// - Standard criteria of the search
|
||||
MetaModel::Init_SetZListItems('standard_search', array('name', 'description', 'status', 'subject', 'language'));
|
||||
// - Default criteria for the search
|
||||
MetaModel::Init_SetZListItems('default_search', array('name', 'description', 'status', 'subject', 'language'));
|
||||
}
|
||||
|
||||
// count the recipients found
|
||||
protected $m_iRecipients;
|
||||
|
||||
// Errors management : not that simple because we need that function to be
|
||||
// executed in the background, while making sure that any issue would be reported clearly
|
||||
protected $m_aMailErrors; //array of strings explaining the issue
|
||||
|
||||
/**
|
||||
* Return the list of emails as a string, or a detailed error description
|
||||
*
|
||||
* @param string $sRecipAttCode
|
||||
* @param array $aArgs
|
||||
*
|
||||
* @return string
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreCannotSaveObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \CoreWarning
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
protected function FindRecipients($sRecipAttCode, $aArgs)
|
||||
{
|
||||
$oTrigger = $aArgs['trigger->object()'] ?? null;
|
||||
$sOQL = $this->Get($sRecipAttCode);
|
||||
if (utils::IsNullOrEmptyString($sOQL)) return '';
|
||||
|
||||
try {
|
||||
$oSearch = DBObjectSearch::FromOQL($sOQL);
|
||||
if ($this->Get('ignore_notify') === 'no') {
|
||||
// In theory, it is possible to notify *any* kind of object,
|
||||
// as long as there is an email attribute in the class
|
||||
// So let's not assume that the selected class is a Person
|
||||
$sFirstSelectedClass = $oSearch->GetClass();
|
||||
if (MetaModel::IsValidAttCode($sFirstSelectedClass, 'notify')) {
|
||||
$oSearch->AddCondition('notify', 'yes');
|
||||
}
|
||||
}
|
||||
$oSearch->AllowAllData();
|
||||
} catch (OQLException $e) {
|
||||
$this->m_aMailErrors[] = "query syntax error for recipient '$sRecipAttCode'";
|
||||
return $e->getMessage();
|
||||
}
|
||||
|
||||
$sClass = $oSearch->GetClass();
|
||||
// Determine the email attribute (the first one will be our choice)
|
||||
foreach (MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef) {
|
||||
if ($oAttDef instanceof AttributeEmailAddress) {
|
||||
$sEmailAttCode = $sAttCode;
|
||||
// we've got one, exit the loop
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!isset($sEmailAttCode)) {
|
||||
$this->m_aMailErrors[] = "wrong target for recipient '$sRecipAttCode'";
|
||||
return "The objects of the class '$sClass' do not have any email attribute";
|
||||
}
|
||||
|
||||
if ($oTrigger !== null && in_array('Contact', MetaModel::EnumParentClasses($sClass, ENUM_CHILD_CLASSES_ALL), true)) {
|
||||
$aArgs['trigger_id'] = $oTrigger->GetKey();
|
||||
$aArgs['action_id'] = $this->GetKey();
|
||||
|
||||
$sSubscribedContactsOQL = \Combodo\iTop\Service\Notification\NotificationsRepository::GetInstance()->GetSearchOQLContactUnsubscribedByTriggerAndAction();
|
||||
$sSubscribedContactsOQL->ApplyParameters($aArgs);
|
||||
$sAlias = $oSearch->GetClassAlias();
|
||||
$oSearch->AddConditionExpression(Expression::FromOQL("`$sAlias`.id NOT IN ($sSubscribedContactsOQL)"));
|
||||
}
|
||||
|
||||
$oSet = new DBObjectSet($oSearch, array() /* order */, $aArgs);
|
||||
$aRecipients = array();
|
||||
while ($oObj = $oSet->Fetch()) {
|
||||
$sAddress = trim($oObj->Get($sEmailAttCode));
|
||||
if (utils::IsNotNullOrEmptyString($sAddress)) {
|
||||
$aRecipients[] = $sAddress;
|
||||
$this->m_iRecipients++;
|
||||
}
|
||||
if ($oTrigger !== null && in_array('Contact', MetaModel::EnumParentClasses($sClass, ENUM_CHILD_CLASSES_ALL), true)) {
|
||||
\Combodo\iTop\Service\Notification\NotificationsService::GetInstance()->RegisterSubscription($oTrigger, $this, $oObj);
|
||||
}
|
||||
}
|
||||
return implode(', ', $aRecipients);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \CoreWarning
|
||||
*/
|
||||
public function DoExecute($oTrigger, $aContextArgs)
|
||||
{
|
||||
if (MetaModel::IsLogEnabledNotification()) {
|
||||
$oLog = new EventNotificationEmail();
|
||||
if ($this->IsBeingTested()) {
|
||||
$oLog->Set('message', 'TEST - Notification sent (' . $this->Get('test_recipient') . ')');
|
||||
} else {
|
||||
$oLog->Set('message', 'Notification pending');
|
||||
}
|
||||
$oLog->Set('userinfo', UserRights::GetUser());
|
||||
$oLog->Set('trigger_id', $oTrigger->GetKey());
|
||||
$oLog->Set('action_id', $this->GetKey());
|
||||
$oLog->Set('object_id', $aContextArgs['this->object()']->GetKey());
|
||||
$oLog->Set('object_class', get_class($aContextArgs['this->object()']));
|
||||
// Must be inserted now so that it gets a valid id that will make the link
|
||||
// between an eventual asynchronous task (queued) and the log
|
||||
$oLog->DBInsertNoReload();
|
||||
} else {
|
||||
$oLog = null;
|
||||
}
|
||||
|
||||
try {
|
||||
$sRes = $this->_DoExecute($oTrigger, $aContextArgs, $oLog);
|
||||
|
||||
if ($this->IsBeingTested()) {
|
||||
$sPrefix = 'TEST (' . $this->Get('test_recipient') . ') - ';
|
||||
} else {
|
||||
$sPrefix = '';
|
||||
}
|
||||
|
||||
if ($oLog) {
|
||||
$oLog->Set('message', $sPrefix . $sRes);
|
||||
$oLog->DBUpdate();
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
if ($oLog) {
|
||||
$oLog->Set('message', 'Error: ' . $e->getMessage());
|
||||
|
||||
try {
|
||||
$oLog->DBUpdate();
|
||||
} catch (Exception $eSecondTryUpdate) {
|
||||
IssueLog::Error("Failed to process email " . $oLog->GetKey() . " - reason: " . $e->getMessage() . "\nTrace:\n" . $e->getTraceAsString());
|
||||
|
||||
$oLog->Set('message', 'Error: more details in the log for email "' . $oLog->GetKey() . '"');
|
||||
$oLog->DBUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Trigger $oTrigger
|
||||
* @param array $aContextArgs
|
||||
* @param \EventNotification $oLog
|
||||
*
|
||||
* @return string
|
||||
* @throws \CoreException
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function _DoExecute($oTrigger, $aContextArgs, &$oLog)
|
||||
{
|
||||
$sStyles = file_get_contents(APPROOT . utils::GetCSSFromSASS("css/email.scss"));
|
||||
$sStyles .= MetaModel::GetConfig()->Get('email_css');
|
||||
|
||||
$oEmail = new EMail();
|
||||
|
||||
$aEmailContent = $this->PrepareMessageContent($aContextArgs, $oLog);
|
||||
$oEmail->SetSubject($aEmailContent['subject']);
|
||||
$oEmail->SetBody($aEmailContent['body'], 'text/html', $sStyles);
|
||||
$oEmail->SetRecipientTO($aEmailContent['to']);
|
||||
$oEmail->SetRecipientCC($aEmailContent['cc']);
|
||||
$oEmail->SetRecipientBCC($aEmailContent['bcc']);
|
||||
$oEmail->SetRecipientFrom($aEmailContent['from'], $aEmailContent['from_label']);
|
||||
$oEmail->SetRecipientReplyTo($aEmailContent['reply_to'], $aEmailContent['reply_to_label']);
|
||||
$oEmail->SetReferences($aEmailContent['references']);
|
||||
$oEmail->SetMessageId($aEmailContent['message_id']);
|
||||
$oEmail->SetInReplyTo($aEmailContent['in_reply_to']);
|
||||
|
||||
foreach ($aEmailContent['attachments'] as $aAttachment) {
|
||||
$oEmail->AddAttachment($aAttachment['data'], $aAttachment['filename'], $aAttachment['mime_type']);
|
||||
}
|
||||
|
||||
if (empty($this->m_aMailErrors)) {
|
||||
if ($this->m_iRecipients == 0) {
|
||||
return 'No recipient';
|
||||
} else {
|
||||
$aErrors = [];
|
||||
$iRes = $oEmail->Send($aErrors, $this->IsAsynchronous() ? Email::ENUM_SEND_FORCE_ASYNCHRONOUS : Email::ENUM_SEND_FORCE_SYNCHRONOUS, $oLog);
|
||||
switch ($iRes) {
|
||||
case EMAIL_SEND_OK:
|
||||
return "Sent";
|
||||
|
||||
case EMAIL_SEND_PENDING:
|
||||
return "Pending";
|
||||
|
||||
case EMAIL_SEND_ERROR:
|
||||
return "Errors: " . implode(', ', $aErrors);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (is_array($this->m_aMailErrors) && count($this->m_aMailErrors) > 0) {
|
||||
$sError = implode(', ', $this->m_aMailErrors);
|
||||
} else {
|
||||
$sError = 'Unknown reason';
|
||||
}
|
||||
|
||||
return 'Notification was not sent: ' . $sError;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $aContextArgs
|
||||
* @param \EventNotification $oLog
|
||||
*
|
||||
* @return array
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreCannotSaveObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \CoreWarning
|
||||
* @throws \DictExceptionMissingString
|
||||
* @throws \DictExceptionUnknownLanguage
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
* @throws \OQLException
|
||||
* @since 3.1.0 N°918
|
||||
*/
|
||||
protected function PrepareMessageContent($aContextArgs, &$oLog): array
|
||||
{
|
||||
$aMessageContent = [
|
||||
'to' => '',
|
||||
'cc' => '',
|
||||
'bcc' => '',
|
||||
'from' => '',
|
||||
'from_label' => '',
|
||||
'reply_to' => '',
|
||||
'reply_to_label' => '',
|
||||
'subject' => '',
|
||||
'body' => '',
|
||||
'references' => '',
|
||||
'message_id' => '',
|
||||
'in_reply_to' => '',
|
||||
'attachments' => [],
|
||||
];
|
||||
$sPreviousUrlMaker = ApplicationContext::SetUrlMakerClass();
|
||||
[$sPreviousLanguage, $aPreviousPluginProperties] = $this->SetNotificationLanguage();
|
||||
|
||||
try {
|
||||
$this->m_iRecipients = 0;
|
||||
$this->m_aMailErrors = array();
|
||||
|
||||
// Determine recipients
|
||||
//
|
||||
$aMessageContent['to'] = $this->FindRecipients('to', $aContextArgs);
|
||||
$aMessageContent['cc'] = $this->FindRecipients('cc', $aContextArgs);
|
||||
$aMessageContent['bcc'] = $this->FindRecipients('bcc', $aContextArgs);
|
||||
|
||||
$aMessageContent['from'] = MetaModel::ApplyParams($this->Get('from'), $aContextArgs);
|
||||
$aMessageContent['from_label'] = MetaModel::ApplyParams($this->Get('from_label'), $aContextArgs);
|
||||
$aMessageContent['reply_to'] = MetaModel::ApplyParams($this->Get('reply_to'), $aContextArgs);
|
||||
$aMessageContent['reply_to_label'] = MetaModel::ApplyParams($this->Get('reply_to_label'), $aContextArgs);
|
||||
|
||||
$aMessageContent['subject'] = MetaModel::ApplyParams($this->Get('subject'), $aContextArgs);
|
||||
$sBody = $this->BuildMessageBody(false);
|
||||
$aMessageContent['body'] = MetaModel::ApplyParams($sBody, $aContextArgs);
|
||||
|
||||
$oObj = $aContextArgs['this->object()'];
|
||||
$aMessageContent['message_id'] = $this->GenerateIdentifierForHeaders($oObj, static::ENUM_HEADER_NAME_MESSAGE_ID);
|
||||
$aMessageContent['references'] = $this->GenerateIdentifierForHeaders($oObj, static::ENUM_HEADER_NAME_REFERENCES);
|
||||
} catch (Exception $e) {
|
||||
/** @noinspection PhpUnhandledExceptionInspection */
|
||||
throw $e;
|
||||
} finally {
|
||||
ApplicationContext::SetUrlMakerClass($sPreviousUrlMaker);
|
||||
$this->SetNotificationLanguage($sPreviousLanguage, $aPreviousPluginProperties['language_code'] ?? null);
|
||||
}
|
||||
|
||||
if (!is_null($oLog)) {
|
||||
// Note: we have to secure this because those values are calculated
|
||||
// inside the try statement, and we would like to keep track of as
|
||||
// many data as we could while some variables may still be undefined
|
||||
if (isset($aMessageContent['to'])) {
|
||||
$oLog->Set('to', $aMessageContent['to']);
|
||||
}
|
||||
if (isset($aMessageContent['cc'])) {
|
||||
$oLog->Set('cc', $aMessageContent['cc']);
|
||||
}
|
||||
if (isset($aMessageContent['bcc'])) {
|
||||
$oLog->Set('bcc', $aMessageContent['bcc']);
|
||||
}
|
||||
if (isset($aMessageContent['from'])) {
|
||||
$oLog->Set('from', $aMessageContent['from']);
|
||||
}
|
||||
if (isset($aMessageContent['subject'])) {
|
||||
$oLog->Set('subject', $aMessageContent['subject']);
|
||||
}
|
||||
if (isset($aMessageContent['body'])) {
|
||||
$oLog->Set('body', HTMLSanitizer::Sanitize($aMessageContent['body']));
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->IsBeingTested()) {
|
||||
$sTestBody = $aMessageContent['body'];
|
||||
$sTestBody .= "<div style=\"border: dashed;\">\n";
|
||||
$sTestBody .= "<h1>Testing email notification " . $this->GetHyperlink() . "</h1>\n";
|
||||
$sTestBody .= "<p>The email should be sent with the following properties\n";
|
||||
$sTestBody .= "<ul>\n";
|
||||
$sTestBody .= "<li>TO: {$aMessageContent['to']}</li>\n";
|
||||
$sTestBody .= "<li>CC: {$aMessageContent['cc']}</li>\n";
|
||||
$sTestBody .= "<li>BCC: {$aMessageContent['bcc']}</li>\n";
|
||||
$sTestBody .= empty($aMessageContent['from_label']) ? "<li>From: {$aMessageContent['from']}</li>\n" : "<li>From: {$aMessageContent['from_label']} <{$aMessageContent['from']}></li>\n";
|
||||
$sTestBody .= empty($aMessageContent['reply_to_label']) ? "<li>Reply-To: {$aMessageContent['reply_to']}</li>\n" : "<li>Reply-To: {$aMessageContent['reply_to_label']} <{$aMessageContent['reply_to']}></li>\n";
|
||||
$sTestBody .= "<li>References: {$aMessageContent['references']}</li>\n";
|
||||
$sTestBody .= "</ul>\n";
|
||||
$sTestBody .= "</p>\n";
|
||||
$sTestBody .= "</div>\n";
|
||||
$aMessageContent['subject'] = 'TEST[' . $aMessageContent['subject'] . ']';
|
||||
$aMessageContent['body'] = $sTestBody;
|
||||
$aMessageContent['to'] = $this->Get('test_recipient');
|
||||
// N°6677 Ensure emails in test are never sent to cc'd and bcc'd addresses
|
||||
$aMessageContent['cc'] = '';
|
||||
$aMessageContent['bcc'] = '';
|
||||
}
|
||||
// Note: N°4849 We pass the "References" identifier instead of the "Message-ID" on purpose as we want notifications emails to group around the triggering iTop object, not just the users' replies to the notification
|
||||
$aMessageContent['in_reply_to'] = $aMessageContent['references'];
|
||||
|
||||
if (isset($aContextArgs['attachments'])) {
|
||||
$aAttachmentReport = array();
|
||||
/** @var \ormDocument $oDocument */
|
||||
foreach ($aContextArgs['attachments'] as $oDocument) {
|
||||
$aMessageContent['attachments'][] = ['data' => $oDocument->GetData(), 'filename' => $oDocument->GetFileName(), 'mime_type' => $oDocument->GetMimeType()];
|
||||
$aAttachmentReport[] = array($oDocument->GetFileName(), $oDocument->GetMimeType(), strlen($oDocument->GetData() ?? ''));
|
||||
}
|
||||
$oLog->Set('attachments', $aAttachmentReport);
|
||||
}
|
||||
|
||||
return $aMessageContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \DBObject $oObject
|
||||
* @param string $sHeaderName {@see \ActionEmail::ENUM_HEADER_NAME_REFERENCES}, {@see \ActionEmail::ENUM_HEADER_NAME_MESSAGE_ID}
|
||||
*
|
||||
* @return string The formatted identifier for $sHeaderName based on $oObject
|
||||
* @throws \Exception
|
||||
* @since 3.1.0 N°4849
|
||||
*/
|
||||
protected function GenerateIdentifierForHeaders(DBObject $oObject, string $sHeaderName): string
|
||||
{
|
||||
$sObjClass = get_class($oObject);
|
||||
$sObjId = $oObject->GetKey();
|
||||
$sAppName = utils::Sanitize(ITOP_APPLICATION_SHORT, '', utils::ENUM_SANITIZATION_FILTER_VARIABLE_NAME);
|
||||
|
||||
switch ($sHeaderName) {
|
||||
case static::ENUM_HEADER_NAME_MESSAGE_ID:
|
||||
case static::ENUM_HEADER_NAME_REFERENCES:
|
||||
// Prefix
|
||||
$sPrefix = sprintf('%s_%s_%d', $sAppName, $sObjClass, $sObjId);
|
||||
if ($sHeaderName === static::ENUM_HEADER_NAME_MESSAGE_ID) {
|
||||
$sPrefix .= sprintf('_%F', microtime(true /* get as float*/));
|
||||
}
|
||||
// Suffix
|
||||
$sSuffix = sprintf('@%s.openitop.org', MetaModel::GetEnvironmentId());
|
||||
// Identifier
|
||||
$sIdentifier = $sPrefix . $sSuffix;
|
||||
if ($sHeaderName === static::ENUM_HEADER_NAME_REFERENCES) {
|
||||
$sIdentifier = "<$sIdentifier>";
|
||||
}
|
||||
|
||||
return $sIdentifier;
|
||||
}
|
||||
|
||||
// Requested header name invalid
|
||||
$sErrorMessage = sprintf('%s: Could not generate identifier for header "%s", only %s are supported', static::class, $sHeaderName, implode(' / ', [static::ENUM_HEADER_NAME_MESSAGE_ID, static::ENUM_HEADER_NAME_REFERENCES]));
|
||||
IssueLog::Error($sErrorMessage, LogChannels::NOTIFICATIONS, [
|
||||
'Object' => $sObjClass . '::' . $sObjId . ' (' . $oObject->GetRawName() . ')',
|
||||
'Action' => get_class($this) . '::' . $this->GetKey() . ' (' . $this->GetRawName() . ')',
|
||||
]);
|
||||
throw new Exception($sErrorMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compose the body of the message from the 'body' attribute and the HTML template (if any)
|
||||
* @param bool $bHighlightPlaceholders If true add some extra HTML around placeholders to highlight them
|
||||
* @return string
|
||||
* @since 3.1.0 N°4849
|
||||
*/
|
||||
protected function BuildMessageBody(bool $bHighlightPlaceholders = false): string
|
||||
{
|
||||
// Wrap content with a specific class in order to apply styles of HTML fields through the emogrifier (see `css/email.scss`)
|
||||
$sBody = <<<HTML
|
||||
<div class="email-is-html-content">
|
||||
{$this->Get('body')}
|
||||
</div>
|
||||
HTML;
|
||||
|
||||
/** @var ormDocument $oHtmlTemplate */
|
||||
$oHtmlTemplate = $this->Get('html_template');
|
||||
if ($oHtmlTemplate && !$oHtmlTemplate->IsEmpty()) {
|
||||
$sHtmlTemplate = $oHtmlTemplate->GetData();
|
||||
if (false !== mb_strpos($sHtmlTemplate, static::TEMPLATE_BODY_CONTENT)) {
|
||||
if ($bHighlightPlaceholders) {
|
||||
// Highlight the $content$ block
|
||||
$sBody = sprintf(static::CONTENT_HIGHLIGHT, $sBody);
|
||||
}
|
||||
$sBody = str_replace(static::TEMPLATE_BODY_CONTENT, $sBody, $oHtmlTemplate->GetData()); // str_replace is ok as long as both strings are well-formed UTF-8
|
||||
} else {
|
||||
$sBody = $oHtmlTemplate->GetData();
|
||||
}
|
||||
}
|
||||
if ($bHighlightPlaceholders) {
|
||||
// Highlight all placeholders
|
||||
$sBody = preg_replace('/\\$([^$]+)\\$/', static::FIELD_HIGHLIGHT, $sBody);
|
||||
}
|
||||
return $sBody;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 3.1.0 N°4849
|
||||
* @inheritDoc
|
||||
* @see cmdbAbstractObject::DisplayBareRelations()
|
||||
*/
|
||||
public function DisplayBareRelations(\Combodo\iTop\Application\WebPage\WebPage $oPage, $bEditMode = false)
|
||||
{
|
||||
parent::DisplayBareRelations($oPage, false);
|
||||
if (!$bEditMode) {
|
||||
$oPage->SetCurrentTab('action_email__preview', Dict::S('ActionEmail:preview_tab'), Dict::S('ActionEmail:preview_tab+'));
|
||||
$sBody = $this->BuildMessageBody(true);
|
||||
\Combodo\iTop\Application\TwigBase\Twig\TwigHelper::RenderIntoPage($oPage, APPROOT . '/', 'templates/datamodel/ActionEmail/email-notification-preview', ['iframe_content' => $sBody]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 3.1.0
|
||||
* @inheritDoc
|
||||
* @see cmdbAbstractObject::DoCheckToWrite()
|
||||
*/
|
||||
public function DoCheckToWrite()
|
||||
{
|
||||
parent::DoCheckToWrite();
|
||||
$oHtmlTemplate = $this->Get('html_template');
|
||||
if ($oHtmlTemplate && !$oHtmlTemplate->IsEmpty()) {
|
||||
if (false === mb_strpos($oHtmlTemplate->GetData(), static::TEMPLATE_BODY_CONTENT)) {
|
||||
$this->m_aCheckWarnings[] = Dict::Format('ActionEmail:content_placeholder_missing', static::TEMPLATE_BODY_CONTENT, Dict::S('Class:ActionEmail/Attribute:body'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public static function GetAsynchronousGlobalSetting(): bool
|
||||
{
|
||||
return utils::GetConfig()->Get('email_asynchronous');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* A notification
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
abstract class ActionNotification extends Action
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "grant_by_profile,core/cmdb",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "name",
|
||||
"complementary_name_attcode" => ['finalclass', 'description'],
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => ['name'],
|
||||
"db_table" => "priv_action_notification",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
|
||||
// Display lists
|
||||
// - Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('details', array('name', 'description', 'status', 'trigger_list'));
|
||||
// - Attributes to be displayed for a list
|
||||
MetaModel::Init_SetZListItems('list', array('finalclass', 'description', 'status'));
|
||||
MetaModel::Init_AddAttribute(new AttributeApplicationLanguage("language", array("sql" => "language", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
|
||||
|
||||
// Search criteria
|
||||
// - Criteria of the std search form
|
||||
// MetaModel::Init_SetZListItems('standard_search', array('name'));
|
||||
// - Default criteria of the search form
|
||||
// MetaModel::Init_SetZListItems('default_search', array('name'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $sLanguage
|
||||
* @param $sLanguageCode
|
||||
*
|
||||
* @return array [$sPreviousLanguage, $aPreviousPluginProperties]
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \DictExceptionUnknownLanguage
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function SetNotificationLanguage($sLanguage = null, $sLanguageCode = null)
|
||||
{
|
||||
$sPreviousLanguage = Dict::GetUserLanguage();
|
||||
$aPreviousPluginProperties = ApplicationContext::GetPluginProperties('QueryLocalizerPlugin');
|
||||
$sLanguage = $sLanguage ?? $this->Get('language');
|
||||
$sLanguageCode = $sLanguageCode ?? $sLanguage;
|
||||
if (!utils::IsNullOrEmptyString($sLanguage)) {
|
||||
// If a language is specified for this action, force this language
|
||||
// when rendering all placeholders inside this message
|
||||
Dict::SetUserLanguage($sLanguage);
|
||||
AttributeDateTime::LoadFormatFromConfig();
|
||||
ApplicationContext::SetPluginProperty('QueryLocalizerPlugin', 'language_code', $sLanguageCode);
|
||||
}
|
||||
return [$sPreviousLanguage, $aPreviousPluginProperties];
|
||||
}
|
||||
}
|
||||
137
sources/Application/DataModel/TriggerAndAction/Trigger.php
Normal file
137
sources/Application/DataModel/TriggerAndAction/Trigger.php
Normal file
@@ -0,0 +1,137 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* A user defined trigger, to customize the application
|
||||
* A trigger will activate an action
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
abstract class Trigger extends cmdbAbstractObject
|
||||
{
|
||||
/**
|
||||
* @throws \CoreException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "grant_by_profile,core/cmdb",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "description",
|
||||
"complementary_name_attcode" => ['finalclass', 'complement'],
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => ['description'],
|
||||
"db_table" => "priv_trigger",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "realclass",
|
||||
'style' => new ormStyle(null, null, null, null, null, '../images/icons/icons8-conflict.svg'),
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values" => null, "sql" => "description", "default_value" => null, "is_null_allowed" => false, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect("action_list",
|
||||
array("linked_class" => "lnkTriggerAction", "ext_key_to_me" => "trigger_id", "ext_key_to_remote" => "action_id", "allowed_values" => null, "count_min" => 1, "count_max" => 0, "depends_on" => array())));
|
||||
$aTags = ContextTag::GetTags();
|
||||
MetaModel::Init_AddAttribute(new AttributeEnumSet("context", array("allowed_values" => null, "possible_values" => new ValueSetEnumPadded($aTags, true), "sql" => "context", "depends_on" => array(), "is_null_allowed" => true, "max_items" => 12)));
|
||||
// "complement" is a computed field, fed by Trigger sub-classes, in general in ComputeValues method, for eg. the TriggerOnObject fed it with target_class info
|
||||
MetaModel::Init_AddAttribute(new AttributeString("complement", array("allowed_values" => null, "sql" => "complement", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("subscription_policy", array("allowed_values" => new ValueSetEnum(Combodo\iTop\Core\Trigger\Enum\SubscriptionPolicy::cases()), "sql" => "subscription_policy", "default_value" => \Combodo\iTop\Core\Trigger\Enum\SubscriptionPolicy::AllowNoChannel->value, "is_null_allowed" => false, "depends_on" => array())));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('finalclass', 'description', 'context', 'subscription_policy', 'action_list', 'complement')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('finalclass', 'complement')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
|
||||
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the trigger can be used in the current context
|
||||
*
|
||||
* @return bool true if context OK
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public function IsContextValid()
|
||||
{
|
||||
// Check the context
|
||||
$oContext = $this->Get('context');
|
||||
$bChecked = false;
|
||||
$bValid = false;
|
||||
foreach ($oContext->GetValues() as $sValue) {
|
||||
$bChecked = true;
|
||||
if (ContextTag::Check($sValue)) {
|
||||
$bValid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($bChecked && !$bValid) {
|
||||
// Trigger does not match the current context
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $aContextArgs
|
||||
*
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public function DoActivate($aContextArgs)
|
||||
{
|
||||
// Check the context
|
||||
if (!$this->IsContextValid()) {
|
||||
// Trigger does not match the current context
|
||||
$sClass = get_class($this);
|
||||
$sName = $this->Get('friendlyname');
|
||||
IssueLog::Debug("Context NOT valid for : {$sClass} '$sName'");
|
||||
return;
|
||||
}
|
||||
|
||||
$aContextArgs['trigger->object()'] = $this;
|
||||
|
||||
// Find the related actions
|
||||
$oLinkedActions = $this->Get('action_list');
|
||||
|
||||
// Order actions as expected
|
||||
$aActionListOrdered = [];
|
||||
while ($oLink = $oLinkedActions->Fetch()) {
|
||||
$aActionListOrdered[(int)$oLink->Get('order')][] = $oLink;
|
||||
}
|
||||
ksort($aActionListOrdered);
|
||||
|
||||
// Execute actions
|
||||
foreach ($aActionListOrdered as $aActionSubList) {
|
||||
foreach ($aActionSubList as $oLink) /** @var \DBObject $oLink */ {
|
||||
/** @var \DBObject $oLink */
|
||||
$iActionId = $oLink->Get('action_id');
|
||||
/** @var \Action $oAction */
|
||||
$oAction = MetaModel::GetObject('Action', $iActionId);
|
||||
if ($oAction->IsActive()) {
|
||||
$oKPI = new ExecutionKPI();
|
||||
$aContextArgs['action->object()'] = $oAction;
|
||||
$oAction->DoExecute($this, $aContextArgs);
|
||||
$oKPI->ComputeStatsForExtension($oAction, 'DoExecute');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the given object is in the scope of this trigger
|
||||
* and can potentially be the subject of notifications
|
||||
*
|
||||
* @param DBObject $oObject The object to check
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function IsInScope(DBObject $oObject)
|
||||
{
|
||||
// By default the answer is no
|
||||
// Overload this function in your own derived class for a different behavior
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class TriggerOnAttributeBlobDownload
|
||||
*
|
||||
* @since 3.1.0
|
||||
*/
|
||||
class TriggerOnAttributeBlobDownload extends TriggerOnObject
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @throws \CoreException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "grant_by_profile,core/cmdb,application",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "description",
|
||||
"complementary_name_attcode" => ['finalclass', 'complement'],
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => ['description'],
|
||||
"db_table" => "priv_trigger_onattblobdownload",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,229 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class TriggerOnObject
|
||||
*/
|
||||
abstract class TriggerOnObject extends Trigger
|
||||
{
|
||||
/**
|
||||
* @throws \CoreException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "grant_by_profile,core/cmdb",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "description",
|
||||
"complementary_name_attcode" => ['finalclass', 'complement'],
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => ['description'],
|
||||
"db_table" => "priv_trigger_onobject",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeClass("target_class",
|
||||
array("class_category" => "bizmodel", "more_values" => "User,UserExternal,UserInternal,UserLDAP,UserLocal", "sql" => "target_class", "default_value" => null, "is_null_allowed" => false, "depends_on" => array(), "class_exclusion_list" => "Attachment")));
|
||||
MetaModel::Init_AddAttribute(new AttributeOQL("filter", array("allowed_values" => null, "sql" => "filter", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'subscription_policy', 'action_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('finalclass', 'target_class', 'description')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('default_search', array('description', 'target_class')); // Default criteria of the search banner
|
||||
// MetaModel::Init_SetZListItems('standard_search', array('name', 'target_class', 'description')); // Criteria of the search form
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public function DoCheckToWrite()
|
||||
{
|
||||
parent::DoCheckToWrite();
|
||||
|
||||
$sFilter = trim($this->Get('filter') ?? '');
|
||||
if (strlen($sFilter) > 0) {
|
||||
try {
|
||||
$oSearch = DBObjectSearch::FromOQL($sFilter);
|
||||
|
||||
if (!MetaModel::IsParentClass($this->Get('target_class'), $oSearch->GetClass())) {
|
||||
$this->m_aCheckIssues[] = Dict::Format('TriggerOnObject:WrongFilterClass', $this->Get('target_class'));
|
||||
}
|
||||
} catch (OqlException $e) {
|
||||
$this->m_aCheckIssues[] = Dict::Format('TriggerOnObject:WrongFilterQuery', $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public function ComputeValues()
|
||||
{
|
||||
parent::ComputeValues();
|
||||
|
||||
// Complementary name of a Trigger is manually built
|
||||
// - the Trigger finalclass code not translated
|
||||
// - an hardcoded text in english
|
||||
// - the target class code not translated for TriggerOnObject subclasses
|
||||
$this->Set('complement', 'class restriction: ' . $this->Get('target_class'));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check whether the given object is in the scope of this trigger
|
||||
* and can potentially be the subject of notifications
|
||||
*
|
||||
* @param DBObject $oObject The object to check
|
||||
*
|
||||
* @return bool
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public function IsInScope(DBObject $oObject)
|
||||
{
|
||||
$sRootClass = $this->Get('target_class');
|
||||
|
||||
return ($oObject instanceof $sRootClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $aContextArgs
|
||||
*
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public function DoActivate($aContextArgs)
|
||||
{
|
||||
$bGo = true;
|
||||
if (isset($aContextArgs['this->object()'])) {
|
||||
/** @var \DBObject $oObject */
|
||||
$oObject = $aContextArgs['this->object()'];
|
||||
$bGo = $this->IsTargetObject($oObject->GetKey(), $oObject->ListPreviousValuesForUpdatedAttributes());
|
||||
}
|
||||
if ($bGo) {
|
||||
parent::DoActivate($aContextArgs);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* if the target class is Attachment, then the trigger is read-only
|
||||
* @param $sAttCode
|
||||
* @param $aReasons
|
||||
* @param $sTargetState
|
||||
* @return int
|
||||
* @throws ArchivedObjectException
|
||||
* @throws CoreException
|
||||
*/
|
||||
public function GetAttributeFlags($sAttCode, &$aReasons = array(), $sTargetState = '')
|
||||
{
|
||||
// Force the computed field to be read-only, preventing it to be written
|
||||
if ($this->Get('target_class') == 'Attachment') {
|
||||
return OPT_ATT_READONLY;
|
||||
}
|
||||
return parent::GetAttributeFlags($sAttCode, $aReasons, $sTargetState);
|
||||
}
|
||||
|
||||
|
||||
public function DisplayBareHeader(WebPage $oPage, $bEditMode = false)
|
||||
{
|
||||
$aHeaderBlocks = parent::DisplayBareHeader($oPage, $bEditMode);
|
||||
if ($this->Get('target_class') == 'Attachment') {
|
||||
$oPage->AddUiBlock(\Combodo\iTop\Application\UI\Base\Component\Alert\AlertUIBlockFactory::MakeForWarning('', Dict::S('Class:TriggerOnObject:TriggerClassAttachment/ReadOnlyMessage')));
|
||||
$oPage->add_ready_script("$('#UIMenuModify').hide();");
|
||||
}
|
||||
|
||||
return $aHeaderBlocks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Activate trigger based on attribute list given instead of changed attributes
|
||||
*
|
||||
* @param array $aContextArgs
|
||||
* @param array|null $aAttributes if null default to changed attributes
|
||||
*
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
* @throws \OQLException
|
||||
* @since 3.1.1 3.2.0 N°6228
|
||||
*/
|
||||
public function DoActivateForSpecificAttributes(array $aContextArgs, ?array $aAttributes)
|
||||
{
|
||||
if (isset($aContextArgs['this->object()'])) {
|
||||
/** @var \DBObject $oObject */
|
||||
$oObject = $aContextArgs['this->object()'];
|
||||
if (is_null($aAttributes)) {
|
||||
$aChanges = $oObject->ListPreviousValuesForUpdatedAttributes();
|
||||
} else {
|
||||
$aChanges = array_fill_keys($aAttributes, true);
|
||||
}
|
||||
if (false === $this->IsTargetObject($oObject->GetKey(), $aChanges)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
parent::DoActivate($aContextArgs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $iObjectId
|
||||
* @param array $aChanges
|
||||
*
|
||||
* @return bool True if the object of ID $iObjectId is within the scope of the OQL defined by the "filter" attribute
|
||||
*
|
||||
* @throws \CoreException
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public function IsTargetObject($iObjectId, $aChanges = array())
|
||||
{
|
||||
$sFilter = trim($this->Get('filter') ?? '');
|
||||
if (strlen($sFilter) > 0) {
|
||||
$oSearch = DBObjectSearch::FromOQL($sFilter);
|
||||
$oSearch->AddCondition('id', $iObjectId, '=');
|
||||
$oSearch->AllowAllData();
|
||||
$oSet = new DBObjectSet($oSearch);
|
||||
$bRet = ($oSet->Count() > 0);
|
||||
} else {
|
||||
$bRet = true;
|
||||
}
|
||||
|
||||
return $bRet;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Exception $oException
|
||||
* @param \DBObject $oObject
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @uses \IssueLog::Error()
|
||||
*
|
||||
* @since 2.7.9 3.0.3 3.1.0 N°5893
|
||||
*/
|
||||
public function LogException($oException, $oObject)
|
||||
{
|
||||
$sObjectKey = $oObject->GetKey(); // if object wasn't persisted yet, then we'll have a negative value
|
||||
|
||||
$aContext = [
|
||||
'exception.class' => get_class($oException),
|
||||
'exception.message' => $oException->getMessage(),
|
||||
'trigger.class' => get_class($this),
|
||||
'trigger.id' => $this->GetKey(),
|
||||
'trigger.friendlyname' => $this->GetRawName(),
|
||||
'object.class' => get_class($oObject),
|
||||
'object.id' => $sObjectKey,
|
||||
'object.friendlyname' => $oObject->GetRawName(),
|
||||
'current_user' => UserRights::GetUser(),
|
||||
'exception.stack' => $oException->getTraceAsString(),
|
||||
];
|
||||
|
||||
IssueLog::Error('A trigger did throw an exception', null, $aContext);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class TriggerOnObjectCreate
|
||||
*/
|
||||
class TriggerOnObjectCreate extends TriggerOnObject
|
||||
{
|
||||
/**
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "grant_by_profile,core/cmdb,application",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "description",
|
||||
"complementary_name_attcode" => ['finalclass', 'complement'],
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => ['description'],
|
||||
"db_table" => "priv_trigger_onobjcreate",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'subscription_policy', 'action_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('finalclass', 'target_class')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class')); // Criteria of the std search form
|
||||
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class TriggerOnObjectCreate
|
||||
*/
|
||||
class TriggerOnObjectDelete extends TriggerOnObject
|
||||
{
|
||||
/**
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "grant_by_profile,core/cmdb,application",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "description",
|
||||
"complementary_name_attcode" => ['finalclass', 'complement'],
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => ['description'],
|
||||
"db_table" => "priv_trigger_onobjdelete",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'subscription_policy', 'action_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('finalclass', 'target_class')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class')); // Criteria of the std search form
|
||||
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class TriggerOnObjectMention
|
||||
*
|
||||
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
|
||||
* @since 3.0.0
|
||||
*/
|
||||
class TriggerOnObjectMention extends TriggerOnObject
|
||||
{
|
||||
/**
|
||||
* @throws \CoreException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "grant_by_profile,core/cmdb,application",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "description",
|
||||
"complementary_name_attcode" => ['finalclass', 'complement'],
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => ['description'],
|
||||
"db_table" => "priv_trigger_onobjmention",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeOQL("mentioned_filter", array("allowed_values" => null, "sql" => "mentioned_filter", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'mentioned_filter', 'subscription_policy', 'action_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('finalclass', 'target_class')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class')); // Criteria of the std search form
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \DBObject $oObject
|
||||
*
|
||||
* @return bool True if $oObject is within the scope of the OQL defined by the "mentioned_filter" attribute OR if no mentioned_filter defined. Otherwise, returns false.
|
||||
*
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public function IsMentionedObjectInScope(DBObject $oObject)
|
||||
{
|
||||
$sFilter = trim($this->Get('mentioned_filter'));
|
||||
if (strlen($sFilter) > 0) {
|
||||
$oSearch = DBObjectSearch::FromOQL($sFilter);
|
||||
$sSearchClass = $oSearch->GetClass();
|
||||
|
||||
// If filter not on current object class (or descendants), consider it as not in scope
|
||||
if (is_a($oObject, $sSearchClass, true) === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$oSearch->AddCondition('id', $oObject->GetKey(), '=');
|
||||
if (MetaModel::IsAbstract($oSearch->GetClass())) {
|
||||
$oSearch->AddCondition('finalclass', get_class($oObject), '=');
|
||||
}
|
||||
|
||||
$aParams = $oObject->ToArgs('this');
|
||||
$oSet = new DBObjectSet($oSearch, [], $aParams);
|
||||
$bRet = $oSet->CountExceeds(0);
|
||||
} else {
|
||||
$bRet = true;
|
||||
}
|
||||
|
||||
return $bRet;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class TriggerOnObjectCreate
|
||||
*/
|
||||
class TriggerOnObjectUpdate extends TriggerOnObject
|
||||
{
|
||||
/**
|
||||
* @throws \CoreException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "grant_by_profile,core/cmdb,application",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "description",
|
||||
"complementary_name_attcode" => ['finalclass', 'complement'],
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => ['description'],
|
||||
"db_table" => "priv_trigger_onobjupdate",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeClassAttCodeSet('target_attcodes', array("allowed_values" => null, "class_field" => "target_class", "sql" => "target_attcodes", "default_value" => null, "is_null_allowed" => true, "max_items" => 20, "min_items" => 0, "attribute_definition_exclusion_list" => "AttributeDashboard,AttributeExternalField,AttributeFinalClass,AttributeFriendlyName,AttributeObsolescenceDate,AttributeObsolescenceFlag,AttributeSubItem", "attribute_definition_list" => null, "depends_on" => array('target_class'))));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'target_attcodes', 'subscription_policy', 'action_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('finalclass', 'target_class')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class')); // Criteria of the std search form
|
||||
}
|
||||
|
||||
public function IsTargetObject($iObjectId, $aChanges = array())
|
||||
{
|
||||
if (!parent::IsTargetObject($iObjectId, $aChanges)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check the attribute
|
||||
$oAttCodeSet = $this->Get('target_attcodes');
|
||||
$aAttCodes = $oAttCodeSet->GetValues();
|
||||
if (empty($aAttCodes)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
foreach ($aAttCodes as $sAttCode) {
|
||||
if (array_key_exists($sAttCode, $aChanges)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function ComputeValues()
|
||||
{
|
||||
parent::ComputeValues();
|
||||
|
||||
// Remove unwanted attribute codes
|
||||
$aChanges = $this->ListChanges();
|
||||
if (isset($aChanges['target_attcodes'])) {
|
||||
$oAttDef = MetaModel::GetAttributeDef(get_class($this), 'target_attcodes');
|
||||
$aArgs = array('this' => $this);
|
||||
$aAllowedValues = $oAttDef->GetAllowedValues($aArgs);
|
||||
|
||||
/** @var \ormSet $oValue */
|
||||
$oValue = $this->Get('target_attcodes');
|
||||
$aValues = $oValue->GetValues();
|
||||
$bChanged = false;
|
||||
foreach ($aValues as $key => $sValue) {
|
||||
if (!isset($aAllowedValues[$sValue])) {
|
||||
unset($aValues[$key]);
|
||||
$bChanged = true;
|
||||
}
|
||||
}
|
||||
if ($bChanged) {
|
||||
$oValue->SetValues($aValues);
|
||||
$this->Set('target_attcodes', $oValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* To trigger notifications when a ticket is updated from the portal
|
||||
*/
|
||||
class TriggerOnPortalUpdate extends TriggerOnObject
|
||||
{
|
||||
/**
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "grant_by_profile,core/cmdb,application",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "description",
|
||||
"complementary_name_attcode" => ['finalclass', 'complement'],
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => ['description'],
|
||||
"db_table" => "priv_trigger_onportalupdate",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'subscription_policy', 'action_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('finalclass', 'target_class', 'description')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class TriggerOnStateChange
|
||||
*/
|
||||
abstract class TriggerOnStateChange extends TriggerOnObject
|
||||
{
|
||||
/**
|
||||
* @throws \CoreException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "grant_by_profile,core/cmdb",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "description",
|
||||
"complementary_name_attcode" => ['finalclass', 'complement'],
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => ['description'],
|
||||
"db_table" => "priv_trigger_onstatechange",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeClassState("state", array("class_field" => 'target_class', "allowed_values" => null, "sql" => "state", "default_value" => null, "is_null_allowed" => false, "depends_on" => array('target_class'))));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'state', 'subscription_policy', 'action_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('finalclass', 'target_class', 'state')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class', 'state')); // Criteria of the std search form
|
||||
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class TriggerOnStateEnter
|
||||
*/
|
||||
class TriggerOnStateEnter extends TriggerOnStateChange
|
||||
{
|
||||
/**
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "grant_by_profile,core/cmdb,application",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "description",
|
||||
"complementary_name_attcode" => ['finalclass', 'complement'],
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => ['description'],
|
||||
"db_table" => "priv_trigger_onstateenter",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'state', 'subscription_policy', 'action_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('target_class', 'state')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class', 'state')); // Criteria of the std search form
|
||||
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class TriggerOnStateLeave
|
||||
*/
|
||||
class TriggerOnStateLeave extends TriggerOnStateChange
|
||||
{
|
||||
/**
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "grant_by_profile,core/cmdb,application",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "description",
|
||||
"complementary_name_attcode" => ['finalclass', 'complement'],
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => ['description'],
|
||||
"db_table" => "priv_trigger_onstateleave",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'state', 'subscription_policy', 'action_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('target_class', 'state')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class', 'state')); // Criteria of the std search form
|
||||
// MetaModel::Init_SetZListItems('advanced_search', array('')); // Criteria of the advanced search form
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class TriggerOnThresholdReached
|
||||
*/
|
||||
class TriggerOnThresholdReached extends TriggerOnObject
|
||||
{
|
||||
/**
|
||||
* @throws \CoreException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "grant_by_profile,core/cmdb,application",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "description",
|
||||
"complementary_name_attcode" => ['finalclass', 'complement'],
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => ['description'],
|
||||
"db_table" => "priv_trigger_threshold",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeClassAttCodeSet('stop_watch_code', array(
|
||||
"allowed_values" => null,
|
||||
"class_field" => "target_class",
|
||||
"sql" => "stop_watch_code",
|
||||
"default_value" => null,
|
||||
"is_null_allowed" => false,
|
||||
"max_items" => 1,
|
||||
"min_items" => 1,
|
||||
"attribute_definition_exclusion_list" => null,
|
||||
"attribute_definition_list" => "AttributeStopWatch",
|
||||
"include_child_classes_attributes" => true,
|
||||
"depends_on" => array('target_class'),
|
||||
)));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("threshold_index", array("allowed_values" => null, "sql" => "threshold_index", "default_value" => null, "is_null_allowed" => false, "depends_on" => array())));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'stop_watch_code', 'threshold_index', 'filter', 'subscription_policy', 'action_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('target_class', 'threshold_index', 'threshold_index')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class')); // Criteria of the std search form
|
||||
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class lnkTriggerAction
|
||||
*/
|
||||
class lnkTriggerAction extends cmdbAbstractObject
|
||||
{
|
||||
/**
|
||||
* @throws \CoreException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "grant_by_profile,core/cmdb,application",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array('action_id', 'trigger_id'),
|
||||
"db_table" => "priv_link_action_trigger",
|
||||
"db_key_field" => "link_id",
|
||||
"db_finalclass_field" => "",
|
||||
"is_link" => true,
|
||||
'uniqueness_rules' => array(
|
||||
'no_duplicate' => array(
|
||||
'attributes' => array(
|
||||
0 => 'action_id',
|
||||
1 => 'trigger_id',
|
||||
),
|
||||
'filter' => '',
|
||||
'disabled' => false,
|
||||
'is_blocking' => true,
|
||||
),
|
||||
),
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("action_id", array("targetclass" => "Action", "jointype" => '', "allowed_values" => null, "sql" => "action_id", "is_null_allowed" => false, "on_target_delete" => DEL_AUTO, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalField("action_name", array("allowed_values" => null, "extkey_attcode" => 'action_id', "target_attcode" => "name")));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("trigger_id", array("targetclass" => "Trigger", "jointype" => '', "allowed_values" => null, "sql" => "trigger_id", "is_null_allowed" => false, "on_target_delete" => DEL_AUTO, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalField("trigger_name", array("allowed_values" => null, "extkey_attcode" => 'trigger_id', "target_attcode" => "description")));
|
||||
MetaModel::Init_AddAttribute(new AttributeInteger("order", array("allowed_values" => null, "sql" => "order", "default_value" => 0, "is_null_allowed" => true, "depends_on" => array())));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('action_id', 'trigger_id', 'order')); // Attributes to be displayed for a list
|
||||
MetaModel::Init_SetZListItems('list', array('action_id', 'trigger_id', 'order')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', array('action_id', 'trigger_id', 'order')); // Criteria of the std search form
|
||||
MetaModel::Init_SetZListItems('advanced_search', array('action_id', 'trigger_id', 'order')); // Criteria of the advanced search form
|
||||
}
|
||||
}
|
||||
13
sources/Application/SimpleCrypt/CryptEngine.php
Normal file
13
sources/Application/SimpleCrypt/CryptEngine.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Interface for encryption engines
|
||||
*/
|
||||
interface CryptEngine
|
||||
{
|
||||
public static function GetNewDefaultParams();
|
||||
|
||||
function Encrypt($key, $sString);
|
||||
|
||||
function Decrypt($key, $encrypted_data);
|
||||
}
|
||||
163
sources/Application/SimpleCrypt/SimpleCrypt.php
Normal file
163
sources/Application/SimpleCrypt/SimpleCrypt.php
Normal file
@@ -0,0 +1,163 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* SimpleCrypt Class - crypto helpers
|
||||
* Simple encryption of strings, uses mcrypt or degrades to a pure PHP
|
||||
* implementation when mcrypt is not present.
|
||||
* Based on Miguel Ros' work found at:
|
||||
* http://rossoft.wordpress.com/2006/05/22/simple-encryption-class/
|
||||
*
|
||||
* Usage:
|
||||
* $oSimpleCrypt = new SimpleCrypt();
|
||||
* $encrypted = $oSimpleCrypt->encrypt('a_key','the_text');
|
||||
* $sClearText = $oSimpleCrypt->decrypt('a_key',$encrypted);
|
||||
*
|
||||
* The result is $plain equals to 'the_text'
|
||||
*
|
||||
* You can use a different engine if you don't have Mcrypt:
|
||||
* $oSimpleCrypt = new SimpleCrypt('Simple');
|
||||
*
|
||||
* A string encrypted with one engine can't be decrypted with
|
||||
* a different one even if the key is the same.
|
||||
*
|
||||
* @author Miguel Ros <rossoft@gmail.com>
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
class SimpleCrypt
|
||||
{
|
||||
/**
|
||||
* @var \SimpleCrypt
|
||||
* @since 3.1.0 N°5388
|
||||
*/
|
||||
protected $oEngine;
|
||||
|
||||
public static function GetNewDefaultParams()
|
||||
{
|
||||
if (function_exists('sodium_crypto_secretbox_open') && function_exists('random_bytes')) {
|
||||
$sEngineName = 'Sodium';
|
||||
} else if (function_exists('openssl_decrypt')) {
|
||||
$sEngineName = 'OpenSSL';
|
||||
} else if (function_exists('mcrypt_module_open')) {
|
||||
$sEngineName = 'Mcrypt';
|
||||
} else {
|
||||
$sEngineName = 'Simple';
|
||||
}
|
||||
$sEngineName = 'SimpleCrypt' . $sEngineName . 'Engine';
|
||||
return $sEngineName::GetNewDefaultParams();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
case 'Sodium':
|
||||
if (!function_exists('sodium_crypto_secretbox_open')) {
|
||||
$sEngineName = 'Simple';
|
||||
}
|
||||
break;
|
||||
case 'Mcrypt':
|
||||
if (!function_exists('mcrypt_module_open')) {
|
||||
if (function_exists('openssl_decrypt')) {
|
||||
$sEngineName = 'OpenSSLMcryptCompatibility';
|
||||
} else {
|
||||
$sEngineName = 'Simple';
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'OpenSSL':
|
||||
case 'OpenSSLMcryptCompatibility':
|
||||
if (!function_exists('openssl_decrypt')) {
|
||||
$sEngineName = 'Simple';
|
||||
}
|
||||
break;
|
||||
case 'Simple':
|
||||
break;
|
||||
default:
|
||||
throw new Exception(Dict::Format("Core:AttributeEncryptUnknownLibrary", $sEngineName));
|
||||
}
|
||||
|
||||
$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);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Decrypts the string by the given key
|
||||
* @param string $key
|
||||
* @param string $string Ciphered 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"
|
||||
* Tryes to use the best available random number generator
|
||||
* @return string The generated random "salt"
|
||||
*/
|
||||
static function GetNewSalt()
|
||||
{
|
||||
// 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) {
|
||||
//echo "Random bits pulled from /dev/urandom<br/>\n";
|
||||
$sRandomBits .= @fread($fp, 16);
|
||||
@fclose($fp);
|
||||
} else {
|
||||
// MS-Windows platform?
|
||||
if (@class_exists('COM')) {
|
||||
// http://msdn.microsoft.com/en-us/library/aa388176(VS.85).aspx
|
||||
try {
|
||||
$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);
|
||||
}
|
||||
} catch (Exception $ex) {
|
||||
// echo 'Exception: ' . $ex->getMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($sRandomBits == null) {
|
||||
// No "strong" random generator available, use PHP's built-in mechanism
|
||||
//echo "Random bits generated from mt_rand<br/>\n";
|
||||
mt_srand(crc32(microtime()));
|
||||
$sRandomBits = '';
|
||||
for ($i = 0; $i < 4; $i++) {
|
||||
$sRandomBits .= sprintf('%04x', mt_rand(0, 65535));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
return $sRandomBits;
|
||||
}
|
||||
}
|
||||
57
sources/Application/SimpleCrypt/SimpleCryptMcryptEngine.php
Normal file
57
sources/Application/SimpleCrypt/SimpleCryptMcryptEngine.php
Normal file
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* McryptEngine requires Mcrypt extension
|
||||
* Every encryption of the same string with the same key
|
||||
* will return a different encrypted string.
|
||||
*/
|
||||
class SimpleCryptMcryptEngine implements CryptEngine
|
||||
{
|
||||
var $alg = MCRYPT_BLOWFISH;
|
||||
var $td = null;
|
||||
|
||||
public static function GetNewDefaultParams()
|
||||
{
|
||||
return array('lib' => 'Mcrypt', 'key' => null);
|
||||
}
|
||||
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$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_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)) {
|
||||
$sString = str_repeat("\0", 8);
|
||||
}
|
||||
$encrypted_data = mcrypt_generic($this->td, $sString);
|
||||
mcrypt_generic_deinit($this->td);
|
||||
return $iv . $encrypted_data;
|
||||
}
|
||||
|
||||
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));
|
||||
$r = mcrypt_generic_init($this->td, $key, $iv);
|
||||
if (($r < 0) || ($r === false)) {
|
||||
$decrypted_data = Dict::S("Core:AttributeEncryptFailedToDecrypt");
|
||||
} else {
|
||||
$decrypted_data = rtrim(mdecrypt_generic($this->td, $string), "\0");
|
||||
mcrypt_generic_deinit($this->td);
|
||||
}
|
||||
return $decrypted_data;
|
||||
}
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
mcrypt_module_close($this->td);
|
||||
}
|
||||
}
|
||||
30
sources/Application/SimpleCrypt/SimpleCryptOpenSSLEngine.php
Normal file
30
sources/Application/SimpleCrypt/SimpleCryptOpenSSLEngine.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
class SimpleCryptOpenSSLEngine implements CryptEngine
|
||||
{
|
||||
public static function GetNewDefaultParams()
|
||||
{
|
||||
return array('lib' => 'OpenSSL', 'key' => bin2hex(openssl_random_pseudo_bytes(32)));
|
||||
}
|
||||
|
||||
public function Encrypt($key, $sString)
|
||||
{
|
||||
$key = hex2bin($key);
|
||||
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length("AES-256-CBC"));
|
||||
$encrypted_string = openssl_encrypt($sString, "AES-256-CBC", $key, 0, $iv);
|
||||
return $iv . $encrypted_string;
|
||||
}
|
||||
|
||||
public function Decrypt($key, $encrypted_data)
|
||||
{
|
||||
$key = hex2bin($key);
|
||||
$iv = mb_substr($encrypted_data, 0, openssl_cipher_iv_length("AES-256-CBC"), '8bit');
|
||||
$encrypted_data = mb_substr($encrypted_data, openssl_cipher_iv_length("AES-256-CBC"), null, '8bit');
|
||||
$plaintext = openssl_decrypt($encrypted_data, "AES-256-CBC", $key, 0, $iv);
|
||||
if ($plaintext === false) {
|
||||
$plaintext = Dict::S("Core:AttributeEncryptFailedToDecrypt");
|
||||
}
|
||||
return trim($plaintext);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
class SimpleCryptOpenSSLMcryptCompatibilityEngine implements CryptEngine
|
||||
{
|
||||
public static function GetNewDefaultParams()
|
||||
{
|
||||
return array('lib' => 'OpenSSLMcryptCompatibility', 'key' => null);
|
||||
}
|
||||
|
||||
//fix for php < 7.1.8 (keys are Zero padded instead of cycle padded)
|
||||
static private function MakeOpenSSLBlowfishKey($key)
|
||||
{
|
||||
if ("$key" === '') {
|
||||
return $key;
|
||||
}
|
||||
$len = (16 + 2) * 4;
|
||||
while (strlen($key) < $len) {
|
||||
$key .= $key;
|
||||
}
|
||||
$key = substr($key, 0, $len);
|
||||
|
||||
return $key;
|
||||
}
|
||||
|
||||
public function Encrypt($key, $sString)
|
||||
{
|
||||
$key = SimpleCryptOpenSSLMcryptCompatibilityEngine::MakeOpenSSLBlowfishKey($key);
|
||||
$blockSize = 8;
|
||||
$len = strlen($sString);
|
||||
$paddingLen = intval(($len + $blockSize - 1) / $blockSize) * $blockSize - $len;
|
||||
$padding = str_repeat("\0", $paddingLen);
|
||||
$sData = $sString.$padding;
|
||||
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length("BF-CBC"));
|
||||
$encrypted_string = openssl_encrypt($sData, "BF-CBC", $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);
|
||||
|
||||
return $iv.$encrypted_string;
|
||||
}
|
||||
|
||||
public function Decrypt($key, $encrypted_data)
|
||||
{
|
||||
$key = SimpleCryptOpenSSLMcryptCompatibilityEngine::MakeOpenSSLBlowfishKey($key);
|
||||
$iv = mb_substr($encrypted_data, 0, openssl_cipher_iv_length("BF-CBC"), '8bit');
|
||||
$encrypted_data = mb_substr($encrypted_data, openssl_cipher_iv_length("BF-CBC"), null, '8bit');
|
||||
$plaintext = openssl_decrypt($encrypted_data, "BF-CBC", $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);
|
||||
if ($plaintext === false) {
|
||||
$plaintext = Dict::S("Core:AttributeEncryptFailedToDecrypt");
|
||||
}
|
||||
|
||||
return trim($plaintext);
|
||||
}
|
||||
|
||||
}
|
||||
38
sources/Application/SimpleCrypt/SimpleCryptSimpleEngine.php
Normal file
38
sources/Application/SimpleCrypt/SimpleCryptSimpleEngine.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Simple Engine doesn't need any PHP extension.
|
||||
* Every encryption of the same string with the same key
|
||||
* will return the same encrypted string
|
||||
*/
|
||||
class SimpleCryptSimpleEngine implements CryptEngine
|
||||
{
|
||||
public static function GetNewDefaultParams()
|
||||
{
|
||||
return array('lib' => 'Simple', 'key' => null);
|
||||
}
|
||||
|
||||
public function Encrypt($key, $sString)
|
||||
{
|
||||
$result = '';
|
||||
for ($i = 1; $i <= strlen($sString); $i++) {
|
||||
$char = substr($sString, $i - 1, 1);
|
||||
$keychar = substr($key, ($i % strlen($key)) - 1, 1);
|
||||
$char = chr(ord($char) + ord($keychar));
|
||||
$result .= $char;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function Decrypt($key, $encrypted_data)
|
||||
{
|
||||
$result = '';
|
||||
for ($i = 1; $i <= strlen($encrypted_data); $i++) {
|
||||
$char = substr($encrypted_data, $i - 1, 1);
|
||||
$keychar = substr($key, ($i % strlen($key)) - 1, 1);
|
||||
$char = chr(ord($char) - ord($keychar));
|
||||
$result .= $char;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
41
sources/Application/SimpleCrypt/SimpleCryptSodiumEngine.php
Normal file
41
sources/Application/SimpleCrypt/SimpleCryptSodiumEngine.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* SodiumEngine requires Sodium extension
|
||||
* Every encryption of the same string with the same key
|
||||
* will return a different encrypted string.
|
||||
* The key has to be SODIUM_CRYPTO_SECRETBOX_KEYBYTES bytes long.
|
||||
*/
|
||||
class SimpleCryptSodiumEngine implements CryptEngine
|
||||
{
|
||||
public static function GetNewDefaultParams()
|
||||
{
|
||||
return array('lib' => 'Sodium', 'key' => bin2hex(sodium_crypto_secretbox_keygen()));
|
||||
}
|
||||
|
||||
public function Encrypt($key, $sString)
|
||||
{
|
||||
$key = hex2bin($key);
|
||||
$nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
|
||||
$encrypted_string = sodium_crypto_secretbox($sString, $nonce, $key);
|
||||
sodium_memzero($sString);
|
||||
sodium_memzero($key);
|
||||
return base64_encode($nonce . $encrypted_string);
|
||||
}
|
||||
|
||||
public function Decrypt($key, $encrypted_data)
|
||||
{
|
||||
$key = hex2bin($key);
|
||||
$encrypted_data = base64_decode($encrypted_data);
|
||||
$nonce = mb_substr($encrypted_data, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, '8bit');
|
||||
$encrypted_data = mb_substr($encrypted_data, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, null, '8bit');
|
||||
$plaintext = sodium_crypto_secretbox_open($encrypted_data, $nonce, $key);
|
||||
if ($plaintext === false) {
|
||||
$plaintext = Dict::S("Core:AttributeEncryptFailedToDecrypt");
|
||||
}
|
||||
sodium_memzero($encrypted_data);
|
||||
sodium_memzero($key);
|
||||
return $plaintext;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* An attibute that matches one of the language codes availables in the dictionnary
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
class AttributeApplicationLanguage extends AttributeString
|
||||
{
|
||||
const SEARCH_WIDGET_TYPE = self::SEARCH_WIDGET_TYPE_STRING;
|
||||
|
||||
public static function ListExpectedParams()
|
||||
{
|
||||
return parent::ListExpectedParams();
|
||||
}
|
||||
|
||||
public function __construct($sCode, $aParams)
|
||||
{
|
||||
$this->m_sCode = $sCode;
|
||||
$aAvailableLanguages = Dict::GetLanguages();
|
||||
$aLanguageCodes = array();
|
||||
foreach ($aAvailableLanguages as $sLangCode => $aInfo) {
|
||||
$aLanguageCodes[$sLangCode] = $aInfo['description'] . ' (' . $aInfo['localized_description'] . ')';
|
||||
}
|
||||
|
||||
// N°6462 This should be sorted directly in \Dict during the compilation but we can't for 2 reasons:
|
||||
// - Additional languages can be added on the fly even though it is not recommended
|
||||
// - Formatting is done at run time (just above)
|
||||
natcasesort($aLanguageCodes);
|
||||
|
||||
$aParams["allowed_values"] = new ValueSetEnum($aLanguageCodes);
|
||||
parent::__construct($sCode, $aParams);
|
||||
}
|
||||
|
||||
public function RequiresIndex()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function GetBasicFilterLooseOperator()
|
||||
{
|
||||
return '=';
|
||||
}
|
||||
}
|
||||
35
sources/Core/AttributeDefinition/AttributeArchiveDate.php
Normal file
35
sources/Core/AttributeDefinition/AttributeArchiveDate.php
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
class AttributeArchiveDate extends AttributeDate
|
||||
{
|
||||
/**
|
||||
* Useless constructor, but if not present PHP 7.4.0/7.4.1 is crashing :( (N°2329)
|
||||
*
|
||||
* @see https://www.php.net/manual/fr/language.oop5.decon.php states that child constructor can be ommited
|
||||
* @see https://bugs.php.net/bug.php?id=79010 bug solved in PHP 7.4.9
|
||||
*
|
||||
* @param string $sCode
|
||||
* @param array $aParams
|
||||
*
|
||||
* @throws \Exception
|
||||
* @noinspection SenselessProxyMethodInspection
|
||||
*/
|
||||
public function __construct($sCode, $aParams)
|
||||
{
|
||||
parent::__construct($sCode, $aParams);
|
||||
}
|
||||
|
||||
public function GetLabel($sDefault = null)
|
||||
{
|
||||
$sDefault = Dict::S('Core:AttributeArchiveDate/Label', $sDefault);
|
||||
|
||||
return parent::GetLabel($sDefault);
|
||||
}
|
||||
|
||||
public function GetDescription($sDefault = null)
|
||||
{
|
||||
$sDefault = Dict::S('Core:AttributeArchiveDate/Label+', $sDefault);
|
||||
|
||||
return parent::GetDescription($sDefault);
|
||||
}
|
||||
}
|
||||
49
sources/Core/AttributeDefinition/AttributeArchiveFlag.php
Normal file
49
sources/Core/AttributeDefinition/AttributeArchiveFlag.php
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
class AttributeArchiveFlag extends AttributeBoolean
|
||||
{
|
||||
public function __construct($sCode)
|
||||
{
|
||||
parent::__construct($sCode, array(
|
||||
"allowed_values" => null,
|
||||
"sql" => $sCode,
|
||||
"default_value" => false,
|
||||
"is_null_allowed" => false,
|
||||
"depends_on" => array()
|
||||
));
|
||||
}
|
||||
|
||||
public function RequiresIndex()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function CopyOnAllTables()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function IsWritable()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function IsMagic()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function GetLabel($sDefault = null)
|
||||
{
|
||||
$sDefault = Dict::S('Core:AttributeArchiveFlag/Label', $sDefault);
|
||||
|
||||
return parent::GetLabel($sDefault);
|
||||
}
|
||||
|
||||
public function GetDescription($sDefault = null)
|
||||
{
|
||||
$sDefault = Dict::S('Core:AttributeArchiveFlag/Label+', $sDefault);
|
||||
|
||||
return parent::GetDescription($sDefault);
|
||||
}
|
||||
}
|
||||
367
sources/Core/AttributeDefinition/AttributeBlob.php
Normal file
367
sources/Core/AttributeDefinition/AttributeBlob.php
Normal file
@@ -0,0 +1,367 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* A blob is an ormDocument, it is stored as several columns in the database
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
class AttributeBlob extends AttributeDefinition
|
||||
{
|
||||
const SEARCH_WIDGET_TYPE = self::SEARCH_WIDGET_TYPE_RAW;
|
||||
|
||||
/**
|
||||
* Useless constructor, but if not present PHP 7.4.0/7.4.1 is crashing :( (N°2329)
|
||||
*
|
||||
* @see https://www.php.net/manual/fr/language.oop5.decon.php states that child constructor can be ommited
|
||||
* @see https://bugs.php.net/bug.php?id=79010 bug solved in PHP 7.4.9
|
||||
*
|
||||
* @param string $sCode
|
||||
* @param array $aParams
|
||||
*
|
||||
* @throws \Exception
|
||||
* @noinspection SenselessProxyMethodInspection
|
||||
*/
|
||||
public function __construct($sCode, $aParams)
|
||||
{
|
||||
parent::__construct($sCode, $aParams);
|
||||
}
|
||||
|
||||
public static function ListExpectedParams()
|
||||
{
|
||||
return array_merge(parent::ListExpectedParams(), array("depends_on"));
|
||||
}
|
||||
|
||||
public function GetEditClass()
|
||||
{
|
||||
return "Document";
|
||||
}
|
||||
|
||||
public static function IsBasedOnDBColumns()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function IsScalar()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function IsWritable()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function GetDefaultValue(DBObject $oHostObject = null)
|
||||
{
|
||||
return new ormDocument('', '', '');
|
||||
}
|
||||
|
||||
public function IsNullAllowed(DBObject $oHostObject = null)
|
||||
{
|
||||
return $this->GetOptional("is_null_allowed", false);
|
||||
}
|
||||
|
||||
public function GetEditValue($sValue, $oHostObj = null)
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @param string $proposedValue Can be an URL (including an URL to iTop itself), or a local path (CSV import)
|
||||
*
|
||||
* @see AttributeDefinition::MakeRealValue()
|
||||
*/
|
||||
public function MakeRealValue($proposedValue, $oHostObj)
|
||||
{
|
||||
if ($proposedValue === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (is_object($proposedValue)) {
|
||||
$proposedValue = clone $proposedValue;
|
||||
} else {
|
||||
try {
|
||||
// Read the file from iTop, an URL (or the local file system - for admins only)
|
||||
$proposedValue = Utils::FileGetContentsAndMIMEType($proposedValue);
|
||||
} catch (Exception $e) {
|
||||
IssueLog::Warning(get_class($this) . "::MakeRealValue - " . $e->getMessage());
|
||||
// Not a real document !! store is as text !!! (This was the default behavior before)
|
||||
$proposedValue = new ormDocument($e->getMessage() . " \n" . $proposedValue, 'text/plain');
|
||||
}
|
||||
}
|
||||
|
||||
return $proposedValue;
|
||||
}
|
||||
|
||||
public function GetSQLExpressions($sPrefix = '')
|
||||
{
|
||||
if ($sPrefix == '') {
|
||||
$sPrefix = $this->GetCode();
|
||||
}
|
||||
$aColumns = array();
|
||||
// Note: to optimize things, the existence of the attribute is determined by the existence of one column with an empty suffix
|
||||
$aColumns[''] = $sPrefix . '_mimetype';
|
||||
$aColumns['_data'] = $sPrefix . '_data';
|
||||
$aColumns['_filename'] = $sPrefix . '_filename';
|
||||
$aColumns['_downloads_count'] = $sPrefix . '_downloads_count';
|
||||
|
||||
return $aColumns;
|
||||
}
|
||||
|
||||
public function FromSQLToValue($aCols, $sPrefix = '')
|
||||
{
|
||||
if (!array_key_exists($sPrefix, $aCols)) {
|
||||
$sAvailable = implode(', ', array_keys($aCols));
|
||||
throw new MissingColumnException("Missing column '$sPrefix' from {$sAvailable}");
|
||||
}
|
||||
$sMimeType = isset($aCols[$sPrefix]) ? $aCols[$sPrefix] : '';
|
||||
|
||||
if (!array_key_exists($sPrefix . '_data', $aCols)) {
|
||||
$sAvailable = implode(', ', array_keys($aCols));
|
||||
throw new MissingColumnException("Missing column '" . $sPrefix . "_data' from {$sAvailable}");
|
||||
}
|
||||
$data = isset($aCols[$sPrefix . '_data']) ? $aCols[$sPrefix . '_data'] : null;
|
||||
|
||||
if (!array_key_exists($sPrefix . '_filename', $aCols)) {
|
||||
$sAvailable = implode(', ', array_keys($aCols));
|
||||
throw new MissingColumnException("Missing column '" . $sPrefix . "_filename' from {$sAvailable}");
|
||||
}
|
||||
$sFileName = isset($aCols[$sPrefix . '_filename']) ? $aCols[$sPrefix . '_filename'] : '';
|
||||
|
||||
if (!array_key_exists($sPrefix . '_downloads_count', $aCols)) {
|
||||
$sAvailable = implode(', ', array_keys($aCols));
|
||||
throw new MissingColumnException("Missing column '" . $sPrefix . "_downloads_count' from {$sAvailable}");
|
||||
}
|
||||
$iDownloadsCount = isset($aCols[$sPrefix . '_downloads_count']) ? $aCols[$sPrefix . '_downloads_count'] : ormDocument::DEFAULT_DOWNLOADS_COUNT;
|
||||
|
||||
$value = new ormDocument($data, $sMimeType, $sFileName, $iDownloadsCount);
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function GetSQLValues($value)
|
||||
{
|
||||
// #@# Optimization: do not load blobs anytime
|
||||
// As per mySQL doc, selecting blob columns will prevent mySQL from
|
||||
// using memory in case a temporary table has to be created
|
||||
// (temporary tables created on disk)
|
||||
// We will have to remove the blobs from the list of attributes when doing the select
|
||||
// then the use of Get() should finalize the load
|
||||
if ($value instanceof ormDocument) {
|
||||
$aValues = array();
|
||||
if (!$value->IsEmpty()) {
|
||||
$aValues[$this->GetCode() . '_data'] = $value->GetData();
|
||||
} else {
|
||||
$aValues[$this->GetCode() . '_data'] = '';
|
||||
}
|
||||
$aValues[$this->GetCode() . '_mimetype'] = $value->GetMimeType();
|
||||
$aValues[$this->GetCode() . '_filename'] = $value->GetFileName();
|
||||
$aValues[$this->GetCode() . '_downloads_count'] = $value->GetDownloadsCount();
|
||||
} else {
|
||||
$aValues = array();
|
||||
$aValues[$this->GetCode() . '_data'] = '';
|
||||
$aValues[$this->GetCode() . '_mimetype'] = '';
|
||||
$aValues[$this->GetCode() . '_filename'] = '';
|
||||
$aValues[$this->GetCode() . '_downloads_count'] = ormDocument::DEFAULT_DOWNLOADS_COUNT;
|
||||
}
|
||||
|
||||
return $aValues;
|
||||
}
|
||||
|
||||
public function GetSQLColumns($bFullSpec = false)
|
||||
{
|
||||
$aColumns = array();
|
||||
$aColumns[$this->GetCode() . '_data'] = 'LONGBLOB'; // 2^32 (4 Gb)
|
||||
$aColumns[$this->GetCode() . '_mimetype'] = 'VARCHAR(255)' . CMDBSource::GetSqlStringColumnDefinition();
|
||||
$aColumns[$this->GetCode() . '_filename'] = 'VARCHAR(255)' . CMDBSource::GetSqlStringColumnDefinition();
|
||||
$aColumns[$this->GetCode() . '_downloads_count'] = 'INT(11) UNSIGNED';
|
||||
|
||||
return $aColumns;
|
||||
}
|
||||
|
||||
public function GetBasicFilterOperators()
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
public function GetBasicFilterLooseOperator()
|
||||
{
|
||||
return '=';
|
||||
}
|
||||
|
||||
public function GetBasicFilterSQLExpr($sOpCode, $value)
|
||||
{
|
||||
return 'true';
|
||||
}
|
||||
|
||||
public function GetAsHTML($value, $oHostObject = null, $bLocalize = true)
|
||||
{
|
||||
if (is_object($value)) {
|
||||
return $value->GetAsHTML();
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sValue
|
||||
* @param string $sSeparator
|
||||
* @param string $sTextQualifier
|
||||
* @param \DBObject $oHostObject
|
||||
* @param bool $bLocalize
|
||||
* @param bool $bConvertToPlainText
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function GetAsCSV(
|
||||
$sValue, $sSeparator = ',', $sTextQualifier = '"', $oHostObject = null, $bLocalize = true,
|
||||
$bConvertToPlainText = false
|
||||
)
|
||||
{
|
||||
$sAttCode = $this->GetCode();
|
||||
if ($sValue instanceof ormDocument && !$sValue->IsEmpty()) {
|
||||
return $sValue->GetDownloadURL(get_class($oHostObject), $oHostObject->GetKey(), $sAttCode);
|
||||
}
|
||||
|
||||
return ''; // Not exportable in CSV !
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $value
|
||||
* @param \DBObject $oHostObject
|
||||
* @param bool $bLocalize
|
||||
*
|
||||
* @return mixed|string
|
||||
*/
|
||||
public function GetAsXML($value, $oHostObject = null, $bLocalize = true)
|
||||
{
|
||||
$sRet = '';
|
||||
if (is_object($value)) {
|
||||
/** @var \ormDocument $value */
|
||||
if (!$value->IsEmpty()) {
|
||||
$sRet = '<mimetype>' . $value->GetMimeType() . '</mimetype>';
|
||||
$sRet .= '<filename>' . $value->GetFileName() . '</filename>';
|
||||
$sRet .= '<data>' . base64_encode($value->GetData()) . '</data>';
|
||||
$sRet .= '<downloads_count>' . $value->GetDownloadsCount() . '</downloads_count>';
|
||||
}
|
||||
}
|
||||
|
||||
return $sRet;
|
||||
}
|
||||
|
||||
public function GetForJSON($value)
|
||||
{
|
||||
if ($value instanceof ormDocument) {
|
||||
$aValues = array();
|
||||
$aValues['data'] = base64_encode($value->GetData());
|
||||
$aValues['mimetype'] = $value->GetMimeType();
|
||||
$aValues['filename'] = $value->GetFileName();
|
||||
$aValues['downloads_count'] = $value->GetDownloadsCount();
|
||||
} else {
|
||||
$aValues = null;
|
||||
}
|
||||
|
||||
return $aValues;
|
||||
}
|
||||
|
||||
public function FromJSONToValue($json)
|
||||
{
|
||||
if (isset($json->data)) {
|
||||
$data = base64_decode($json->data);
|
||||
$value = new ormDocument($data, $json->mimetype, $json->filename, $json->downloads_count);
|
||||
} else {
|
||||
$value = null;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function Fingerprint($value)
|
||||
{
|
||||
$sFingerprint = '';
|
||||
if ($value instanceof ormDocument) {
|
||||
$sFingerprint = $value->GetSignature();
|
||||
}
|
||||
|
||||
return $sFingerprint;
|
||||
}
|
||||
|
||||
public static function GetFormFieldClass()
|
||||
{
|
||||
return '\\Combodo\\iTop\\Form\\Field\\BlobField';
|
||||
}
|
||||
|
||||
public function MakeFormField(DBObject $oObject, $oFormField = null)
|
||||
{
|
||||
/** @var $oFormField \Combodo\iTop\Form\Field\BlobField */
|
||||
if ($oFormField === null) {
|
||||
$sFormFieldClass = static::GetFormFieldClass();
|
||||
$oFormField = new $sFormFieldClass($this->GetCode());
|
||||
}
|
||||
|
||||
// Note: As of today we want this field to always be read-only
|
||||
$oFormField->SetReadOnly(true);
|
||||
|
||||
// Calling parent before so current value is set, then proceed
|
||||
parent::MakeFormField($oObject, $oFormField);
|
||||
|
||||
// Setting current value correctly as the default method returns an empty string when there is no file yet.
|
||||
/** @var \ormDocument $value */
|
||||
$value = $oObject->Get($this->GetCode());
|
||||
if (!is_object($value)) {
|
||||
$oFormField->SetCurrentValue(new ormDocument());
|
||||
}
|
||||
|
||||
// Generating urls
|
||||
if (is_object($value) && !$value->IsEmpty()) {
|
||||
$oFormField->SetDownloadUrl($value->GetDownloadURL(get_class($oObject), $oObject->GetKey(), $this->GetCode()));
|
||||
$oFormField->SetDisplayUrl($value->GetDisplayURL(get_class($oObject), $oObject->GetKey(), $this->GetCode()));
|
||||
}
|
||||
|
||||
return $oFormField;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function HasAValue($proposedValue): bool
|
||||
{
|
||||
if (false === ($proposedValue instanceof ormDocument)) {
|
||||
return parent::HasAValue($proposedValue);
|
||||
}
|
||||
|
||||
// Empty file (no content, just a filename) are supported since PR {@link https://github.com/Combodo/combodo-email-synchro/pull/17}, so we check for both empty content and empty filename to determine that a document has no value
|
||||
return utils::IsNotNullOrEmptyString($proposedValue->GetData()) && utils::IsNotNullOrEmptyString($proposedValue->GetFileName());
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @param \ormDocument $original
|
||||
* @param \ormDocument $value
|
||||
* @since N°6502
|
||||
*/
|
||||
public function RecordAttChange(DBObject $oObject, $original, $value): void
|
||||
{
|
||||
// N°6502 Don't record history if only the download count has changed
|
||||
if ((null !== $original) && (null !== $value) && $original->EqualsExceptDownloadsCount($value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
parent::RecordAttChange($oObject, $original, $value);
|
||||
}
|
||||
|
||||
protected function GetChangeRecordAdditionalData(CMDBChangeOp $oMyChangeOp, DBObject $oObject, $original, $value): void
|
||||
{
|
||||
if (is_null($original)) {
|
||||
$original = new ormDocument();
|
||||
}
|
||||
$oMyChangeOp->Set("prevdata", $original);
|
||||
}
|
||||
|
||||
protected function GetChangeRecordClassName(): string
|
||||
{
|
||||
return CMDBChangeOpSetAttributeBlob::class;
|
||||
}
|
||||
}
|
||||
242
sources/Core/AttributeDefinition/AttributeBoolean.php
Normal file
242
sources/Core/AttributeDefinition/AttributeBoolean.php
Normal file
@@ -0,0 +1,242 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Map a boolean column to an attribute
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
class AttributeBoolean extends AttributeInteger
|
||||
{
|
||||
const SEARCH_WIDGET_TYPE = self::SEARCH_WIDGET_TYPE_RAW;
|
||||
|
||||
/**
|
||||
* Useless constructor, but if not present PHP 7.4.0/7.4.1 is crashing :( (N°2329)
|
||||
*
|
||||
* @see https://www.php.net/manual/fr/language.oop5.decon.php states that child constructor can be ommited
|
||||
* @see https://bugs.php.net/bug.php?id=79010 bug solved in PHP 7.4.9
|
||||
*
|
||||
* @param string $sCode
|
||||
* @param array $aParams
|
||||
*
|
||||
* @throws \Exception
|
||||
* @noinspection SenselessProxyMethodInspection
|
||||
*/
|
||||
public function __construct($sCode, $aParams)
|
||||
{
|
||||
parent::__construct($sCode, $aParams);
|
||||
}
|
||||
|
||||
public static function ListExpectedParams()
|
||||
{
|
||||
return parent::ListExpectedParams();
|
||||
//return array_merge(parent::ListExpectedParams(), array());
|
||||
}
|
||||
|
||||
public function GetEditClass()
|
||||
{
|
||||
return "Integer";
|
||||
}
|
||||
|
||||
protected function GetSQLCol($bFullSpec = false)
|
||||
{
|
||||
return "TINYINT(1)" . ($bFullSpec ? $this->GetSQLColSpec() : '');
|
||||
}
|
||||
|
||||
public function MakeRealValue($proposedValue, $oHostObj)
|
||||
{
|
||||
if (is_null($proposedValue)) {
|
||||
return null;
|
||||
}
|
||||
if ($proposedValue === '') {
|
||||
return null;
|
||||
}
|
||||
if ((int)$proposedValue) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function ScalarToSQL($value)
|
||||
{
|
||||
if ($value) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function GetValueLabel($bValue)
|
||||
{
|
||||
if (is_null($bValue)) {
|
||||
$sLabel = Dict::S('Core:' . get_class($this) . '/Value:null');
|
||||
} else {
|
||||
$sValue = $bValue ? 'yes' : 'no';
|
||||
$sDefault = Dict::S('Core:' . get_class($this) . '/Value:' . $sValue);
|
||||
$sLabel = $this->SearchLabel('/Attribute:' . $this->m_sCode . '/Value:' . $sValue, $sDefault, true /*user lang*/);
|
||||
}
|
||||
|
||||
return $sLabel;
|
||||
}
|
||||
|
||||
public function GetValueDescription($bValue)
|
||||
{
|
||||
if (is_null($bValue)) {
|
||||
$sDescription = Dict::S('Core:' . get_class($this) . '/Value:null+');
|
||||
} else {
|
||||
$sValue = $bValue ? 'yes' : 'no';
|
||||
$sDefault = Dict::S('Core:' . get_class($this) . '/Value:' . $sValue . '+');
|
||||
$sDescription = $this->SearchLabel('/Attribute:' . $this->m_sCode . '/Value:' . $sValue . '+', $sDefault,
|
||||
true /*user lang*/);
|
||||
}
|
||||
|
||||
return $sDescription;
|
||||
}
|
||||
|
||||
public function GetAsHTML($bValue, $oHostObject = null, $bLocalize = true)
|
||||
{
|
||||
if (is_null($bValue)) {
|
||||
$sRes = '';
|
||||
} elseif ($bLocalize) {
|
||||
$sLabel = $this->GetValueLabel($bValue);
|
||||
$sDescription = $this->GetValueDescription($bValue);
|
||||
// later, we could imagine a detailed description in the title
|
||||
$sRes = "<span title=\"$sDescription\">" . parent::GetAsHtml($sLabel) . "</span>";
|
||||
} else {
|
||||
$sRes = $bValue ? 'yes' : 'no';
|
||||
}
|
||||
|
||||
return $sRes;
|
||||
}
|
||||
|
||||
public function GetAsXML($bValue, $oHostObject = null, $bLocalize = true)
|
||||
{
|
||||
if (is_null($bValue)) {
|
||||
$sFinalValue = '';
|
||||
} elseif ($bLocalize) {
|
||||
$sFinalValue = $this->GetValueLabel($bValue);
|
||||
} else {
|
||||
$sFinalValue = $bValue ? 'yes' : 'no';
|
||||
}
|
||||
$sRes = parent::GetAsXML($sFinalValue, $oHostObject, $bLocalize);
|
||||
|
||||
return $sRes;
|
||||
}
|
||||
|
||||
public function GetAsCSV(
|
||||
$bValue, $sSeparator = ',', $sTextQualifier = '"', $oHostObject = null, $bLocalize = true,
|
||||
$bConvertToPlainText = false
|
||||
)
|
||||
{
|
||||
if (is_null($bValue)) {
|
||||
$sFinalValue = '';
|
||||
} elseif ($bLocalize) {
|
||||
$sFinalValue = $this->GetValueLabel($bValue);
|
||||
} else {
|
||||
$sFinalValue = $bValue ? 'yes' : 'no';
|
||||
}
|
||||
$sRes = parent::GetAsCSV($sFinalValue, $sSeparator, $sTextQualifier, $oHostObject, $bLocalize);
|
||||
|
||||
return $sRes;
|
||||
}
|
||||
|
||||
public static function GetFormFieldClass()
|
||||
{
|
||||
return '\\Combodo\\iTop\\Form\\Field\\SelectField';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \DBObject $oObject
|
||||
* @param \Combodo\iTop\Form\Field\SelectField $oFormField
|
||||
*
|
||||
* @return \Combodo\iTop\Form\Field\SelectField
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public function MakeFormField(DBObject $oObject, $oFormField = null)
|
||||
{
|
||||
if ($oFormField === null) {
|
||||
$sFormFieldClass = static::GetFormFieldClass();
|
||||
$oFormField = new $sFormFieldClass($this->GetCode());
|
||||
}
|
||||
|
||||
$oFormField->SetChoices(array('yes' => $this->GetValueLabel(true), 'no' => $this->GetValueLabel(false)));
|
||||
parent::MakeFormField($oObject, $oFormField);
|
||||
|
||||
return $oFormField;
|
||||
}
|
||||
|
||||
public function GetEditValue($value, $oHostObj = null)
|
||||
{
|
||||
if (is_null($value)) {
|
||||
return '';
|
||||
} else {
|
||||
return $this->GetValueLabel($value);
|
||||
}
|
||||
}
|
||||
|
||||
public function GetForJSON($value)
|
||||
{
|
||||
return (bool)$value;
|
||||
}
|
||||
|
||||
public function MakeValueFromString(
|
||||
$sProposedValue, $bLocalizedValue = false, $sSepItem = null, $sSepAttribute = null, $sSepValue = null,
|
||||
$sAttributeQualifier = null
|
||||
)
|
||||
{
|
||||
$sInput = mb_strtolower(trim($sProposedValue));
|
||||
if ($bLocalizedValue) {
|
||||
switch ($sInput) {
|
||||
case '1': // backward compatibility
|
||||
case $this->GetValueLabel(true):
|
||||
$value = true;
|
||||
break;
|
||||
case '0': // backward compatibility
|
||||
case 'no':
|
||||
case $this->GetValueLabel(false):
|
||||
$value = false;
|
||||
break;
|
||||
default:
|
||||
$value = null;
|
||||
}
|
||||
} else {
|
||||
switch ($sInput) {
|
||||
case '1': // backward compatibility
|
||||
case 'yes':
|
||||
$value = true;
|
||||
break;
|
||||
case '0': // backward compatibility
|
||||
case 'no':
|
||||
$value = false;
|
||||
break;
|
||||
default:
|
||||
$value = null;
|
||||
}
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function RecordAttChange(DBObject $oObject, $original, $value): void
|
||||
{
|
||||
parent::RecordAttChange($oObject, $original ? 1 : 0, $value ? 1 : 0);
|
||||
}
|
||||
|
||||
protected function GetChangeRecordClassName(): string
|
||||
{
|
||||
return CMDBChangeOpSetAttributeScalar::class;
|
||||
}
|
||||
|
||||
public function GetAllowedValues($aArgs = array(), $sContains = ''): array
|
||||
{
|
||||
return [
|
||||
0 => $this->GetValueLabel(false),
|
||||
1 => $this->GetValueLabel(true)
|
||||
];
|
||||
}
|
||||
|
||||
public function GetDisplayStyle()
|
||||
{
|
||||
return $this->GetOptional('display_style', 'select');
|
||||
}
|
||||
}
|
||||
394
sources/Core/AttributeDefinition/AttributeCaseLog.php
Normal file
394
sources/Core/AttributeDefinition/AttributeCaseLog.php
Normal file
@@ -0,0 +1,394 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* An attibute that stores a case log (i.e journal)
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
class AttributeCaseLog extends AttributeLongText
|
||||
{
|
||||
const SEARCH_WIDGET_TYPE = self::SEARCH_WIDGET_TYPE_STRING;
|
||||
|
||||
/**
|
||||
* Useless constructor, but if not present PHP 7.4.0/7.4.1 is crashing :( (N°2329)
|
||||
*
|
||||
* @see https://www.php.net/manual/fr/language.oop5.decon.php states that child constructor can be ommited
|
||||
* @see https://bugs.php.net/bug.php?id=79010 bug solved in PHP 7.4.9
|
||||
*
|
||||
* @param string $sCode
|
||||
* @param array $aParams
|
||||
*
|
||||
* @throws \Exception
|
||||
* @noinspection SenselessProxyMethodInspection
|
||||
*/
|
||||
public function __construct($sCode, $aParams)
|
||||
{
|
||||
parent::__construct($sCode, $aParams);
|
||||
}
|
||||
|
||||
public function GetNullValue()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function IsNull($proposedValue)
|
||||
{
|
||||
if (!($proposedValue instanceof ormCaseLog)) {
|
||||
return ($proposedValue == '');
|
||||
}
|
||||
|
||||
return ($proposedValue->GetText() == '');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @param \ormCaseLog $proposedValue
|
||||
*/
|
||||
public function HasAValue($proposedValue): bool
|
||||
{
|
||||
// Protection against wrong value type
|
||||
if (false === ($proposedValue instanceof ormCaseLog)) {
|
||||
return parent::HasAValue($proposedValue);
|
||||
}
|
||||
|
||||
// We test if there is at least 1 entry in the log, not if the user is adding one
|
||||
return $proposedValue->GetEntryCount() > 0;
|
||||
}
|
||||
|
||||
|
||||
public function ScalarToSQL($value)
|
||||
{
|
||||
if (!is_string($value) && !is_null($value)) {
|
||||
throw new CoreWarning('Expected the attribute value to be a string', array(
|
||||
'found_type' => gettype($value),
|
||||
'value' => $value,
|
||||
'class' => $this->GetCode(),
|
||||
'attribute' => $this->GetHostClass()
|
||||
));
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function GetEditClass()
|
||||
{
|
||||
return "CaseLog";
|
||||
}
|
||||
|
||||
public function GetEditValue($sValue, $oHostObj = null)
|
||||
{
|
||||
if (!($sValue instanceof ormCaseLog)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return $sValue->GetModifiedEntry();
|
||||
}
|
||||
|
||||
/**
|
||||
* For fields containing a potential markup, return the value without this markup
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param \DBObject $oHostObj
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function GetAsPlainText($value, $oHostObj = null)
|
||||
{
|
||||
if ($value instanceof ormCaseLog) {
|
||||
/** ormCaseLog $value */
|
||||
return $value->GetAsPlainText();
|
||||
} else {
|
||||
return (string)$value;
|
||||
}
|
||||
}
|
||||
|
||||
public function GetDefaultValue(DBObject $oHostObject = null)
|
||||
{
|
||||
return new ormCaseLog();
|
||||
}
|
||||
|
||||
public function Equals($val1, $val2)
|
||||
{
|
||||
return ($val1->GetText() == $val2->GetText());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Facilitate things: allow the user to Set the value from a string
|
||||
*
|
||||
* @param $proposedValue
|
||||
* @param \DBObject $oHostObj
|
||||
*
|
||||
* @return mixed|null|\ormCaseLog|string
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function MakeRealValue($proposedValue, $oHostObj)
|
||||
{
|
||||
if ($proposedValue instanceof ormCaseLog) {
|
||||
// Passthrough
|
||||
$ret = clone $proposedValue;
|
||||
} else {
|
||||
// Append the new value if an instance of the object is supplied
|
||||
//
|
||||
$oPreviousLog = null;
|
||||
if ($oHostObj != null) {
|
||||
$oPreviousLog = $oHostObj->Get($this->GetCode());
|
||||
if (!is_object($oPreviousLog)) {
|
||||
$oPreviousLog = $oHostObj->GetOriginal($this->GetCode());;
|
||||
}
|
||||
|
||||
}
|
||||
if (is_object($oPreviousLog)) {
|
||||
$oCaseLog = clone($oPreviousLog);
|
||||
} else {
|
||||
$oCaseLog = new ormCaseLog();
|
||||
}
|
||||
|
||||
if ($proposedValue instanceof stdClass) {
|
||||
$oCaseLog->AddLogEntryFromJSON($proposedValue);
|
||||
} else {
|
||||
if (utils::StrLen($proposedValue) > 0) {
|
||||
//N°5135 - add impersonation information in caselog
|
||||
if (UserRights::IsImpersonated()) {
|
||||
$sOnBehalfOf = Dict::Format('UI:Archive_User_OnBehalfOf_User', UserRights::GetRealUserFriendlyName(), UserRights::GetUserFriendlyName());
|
||||
$oCaseLog->AddLogEntry($proposedValue, $sOnBehalfOf, UserRights::GetConnectedUserId());
|
||||
} else {
|
||||
$oCaseLog->AddLogEntry($proposedValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
$ret = $oCaseLog;
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
public function GetSQLExpressions($sPrefix = '')
|
||||
{
|
||||
if ($sPrefix == '') {
|
||||
$sPrefix = $this->Get('sql');
|
||||
}
|
||||
$aColumns = array();
|
||||
// Note: to optimize things, the existence of the attribute is determined by the existence of one column with an empty suffix
|
||||
$aColumns[''] = $sPrefix;
|
||||
$aColumns['_index'] = $sPrefix . '_index';
|
||||
|
||||
return $aColumns;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $aCols
|
||||
* @param string $sPrefix
|
||||
*
|
||||
* @return \ormCaseLog
|
||||
* @throws \MissingColumnException
|
||||
*/
|
||||
public function FromSQLToValue($aCols, $sPrefix = '')
|
||||
{
|
||||
if (!array_key_exists($sPrefix, $aCols)) {
|
||||
$sAvailable = implode(', ', array_keys($aCols));
|
||||
throw new MissingColumnException("Missing column '$sPrefix' from {$sAvailable}");
|
||||
}
|
||||
$sLog = $aCols[$sPrefix];
|
||||
|
||||
if (isset($aCols[$sPrefix . '_index'])) {
|
||||
$sIndex = $aCols[$sPrefix . '_index'];
|
||||
} else {
|
||||
// For backward compatibility, allow the current state to be: 1 log, no index
|
||||
$sIndex = '';
|
||||
}
|
||||
|
||||
if (strlen($sIndex) > 0) {
|
||||
$aIndex = unserialize($sIndex);
|
||||
$value = new ormCaseLog($sLog, $aIndex);
|
||||
} else {
|
||||
$value = new ormCaseLog($sLog);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function GetSQLValues($value)
|
||||
{
|
||||
if (!($value instanceof ormCaseLog)) {
|
||||
$value = new ormCaseLog('');
|
||||
}
|
||||
$aValues = array();
|
||||
$aValues[$this->GetCode()] = $value->GetText();
|
||||
$aValues[$this->GetCode() . '_index'] = serialize($value->GetIndex());
|
||||
|
||||
return $aValues;
|
||||
}
|
||||
|
||||
public function GetSQLColumns($bFullSpec = false)
|
||||
{
|
||||
$aColumns = array();
|
||||
$aColumns[$this->GetCode()] = 'LONGTEXT' // 2^32 (4 Gb)
|
||||
. CMDBSource::GetSqlStringColumnDefinition();
|
||||
$aColumns[$this->GetCode() . '_index'] = 'BLOB';
|
||||
|
||||
return $aColumns;
|
||||
}
|
||||
|
||||
public function GetAsHTML($value, $oHostObject = null, $bLocalize = true)
|
||||
{
|
||||
if ($value instanceof ormCaseLog) {
|
||||
$sContent = $value->GetAsHTML(null, false, array(__class__, 'RenderWikiHtml'));
|
||||
} else {
|
||||
$sContent = '';
|
||||
}
|
||||
$aStyles = array();
|
||||
if ($this->GetWidth() != '') {
|
||||
$aStyles[] = 'width:' . $this->GetWidth();
|
||||
}
|
||||
if ($this->GetHeight() != '') {
|
||||
$aStyles[] = 'height:' . $this->GetHeight();
|
||||
}
|
||||
$sStyle = '';
|
||||
if (count($aStyles) > 0) {
|
||||
$sStyle = 'style="' . implode(';', $aStyles) . '"';
|
||||
}
|
||||
|
||||
return "<div class=\"caselog\" $sStyle>" . $sContent . '</div>';
|
||||
}
|
||||
|
||||
|
||||
public function GetAsCSV(
|
||||
$value, $sSeparator = ',', $sTextQualifier = '"', $oHostObject = null, $bLocalize = true,
|
||||
$bConvertToPlainText = false
|
||||
)
|
||||
{
|
||||
if ($value instanceof ormCaseLog) {
|
||||
return parent::GetAsCSV($value->GetText($bConvertToPlainText), $sSeparator, $sTextQualifier, $oHostObject,
|
||||
$bLocalize, $bConvertToPlainText);
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
public function GetAsXML($value, $oHostObject = null, $bLocalize = true)
|
||||
{
|
||||
if ($value instanceof ormCaseLog) {
|
||||
return parent::GetAsXML($value->GetText(), $oHostObject, $bLocalize);
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* List the available verbs for 'GetForTemplate'
|
||||
*/
|
||||
public function EnumTemplateVerbs()
|
||||
{
|
||||
return array(
|
||||
'' => 'Plain text representation of all the log entries',
|
||||
'head' => 'Plain text representation of the latest entry',
|
||||
'head_html' => 'HTML representation of the latest entry',
|
||||
'html' => 'HTML representation of all the log entries',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get various representations of the value, for insertion into a template (e.g. in Notifications)
|
||||
*
|
||||
* @param $value mixed The current value of the field
|
||||
* @param $sVerb string The verb specifying the representation of the value
|
||||
* @param $oHostObject DBObject The object
|
||||
* @param $bLocalize bool Whether or not to localize the value
|
||||
*
|
||||
* @return mixed
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function GetForTemplate($value, $sVerb, $oHostObject = null, $bLocalize = true)
|
||||
{
|
||||
switch ($sVerb) {
|
||||
case '':
|
||||
return $value->GetText(true);
|
||||
|
||||
case 'head':
|
||||
return $value->GetLatestEntry('text');
|
||||
|
||||
case 'head_html':
|
||||
return $value->GetLatestEntry('html');
|
||||
|
||||
case 'html':
|
||||
return $value->GetAsEmailHtml();
|
||||
|
||||
default:
|
||||
throw new Exception("Unknown verb '$sVerb' for attribute " . $this->GetCode() . ' in class ' . get_class($oHostObject));
|
||||
}
|
||||
}
|
||||
|
||||
public function GetForJSON($value)
|
||||
{
|
||||
return $value->GetForJSON();
|
||||
}
|
||||
|
||||
public function FromJSONToValue($json)
|
||||
{
|
||||
if (is_string($json)) {
|
||||
// Will be correctly handled in MakeRealValue
|
||||
$ret = $json;
|
||||
} else {
|
||||
if (isset($json->add_item)) {
|
||||
// Will be correctly handled in MakeRealValue
|
||||
$ret = $json->add_item;
|
||||
if (!isset($ret->message)) {
|
||||
throw new Exception("Missing mandatory entry: 'message'");
|
||||
}
|
||||
} else {
|
||||
$ret = ormCaseLog::FromJSON($json);
|
||||
}
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
public function Fingerprint($value)
|
||||
{
|
||||
$sFingerprint = '';
|
||||
if ($value instanceof ormCaseLog) {
|
||||
$sFingerprint = $value->GetText();
|
||||
}
|
||||
|
||||
return $sFingerprint;
|
||||
}
|
||||
|
||||
/**
|
||||
* The actual formatting of the text: either text (=plain text) or html (= text with HTML markup)
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function GetFormat()
|
||||
{
|
||||
return $this->GetOptional('format', 'html'); // default format for case logs is now HTML
|
||||
}
|
||||
|
||||
public static function GetFormFieldClass()
|
||||
{
|
||||
return '\\Combodo\\iTop\\Form\\Field\\CaseLogField';
|
||||
}
|
||||
|
||||
public function MakeFormField(DBObject $oObject, $oFormField = null)
|
||||
{
|
||||
// First we call the parent so the field is build
|
||||
$oFormField = parent::MakeFormField($oObject, $oFormField);
|
||||
// Then only we set the value
|
||||
$oFormField->SetCurrentValue($this->GetEditValue($oObject->Get($this->GetCode())));
|
||||
// And we set the entries
|
||||
$oFormField->SetEntries($oObject->Get($this->GetCode())->GetAsArray());
|
||||
|
||||
return $oFormField;
|
||||
}
|
||||
|
||||
protected function GetChangeRecordAdditionalData(CMDBChangeOp $oMyChangeOp, DBObject $oObject, $original, $value): void
|
||||
{
|
||||
/** @var \ormCaseLog $value */
|
||||
$oMyChangeOp->Set("lastentry", $value->GetLatestEntryIndex());
|
||||
}
|
||||
|
||||
protected function GetChangeRecordClassName(): string
|
||||
{
|
||||
return CMDBChangeOpSetAttributeCaseLog::class;
|
||||
}
|
||||
}
|
||||
84
sources/Core/AttributeDefinition/AttributeClass.php
Normal file
84
sources/Core/AttributeDefinition/AttributeClass.php
Normal file
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* An attribute that matches an object class
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
class AttributeClass extends AttributeString
|
||||
{
|
||||
const SEARCH_WIDGET_TYPE = self::SEARCH_WIDGET_TYPE_ENUM;
|
||||
|
||||
public static function ListExpectedParams()
|
||||
{
|
||||
return array_merge(parent::ListExpectedParams(), array('class_category', 'more_values'));
|
||||
}
|
||||
|
||||
public function __construct($sCode, $aParams)
|
||||
{
|
||||
$this->m_sCode = $sCode;
|
||||
$aParams["allowed_values"] = new ValueSetEnumClasses($aParams['class_category'], $aParams['more_values']);
|
||||
parent::__construct($sCode, $aParams);
|
||||
}
|
||||
|
||||
public function GetDefaultValue(DBObject $oHostObject = null)
|
||||
{
|
||||
$sDefault = parent::GetDefaultValue($oHostObject);
|
||||
if (!$this->IsNullAllowed() && $this->IsNull($sDefault)) {
|
||||
// For this kind of attribute specifying null as default value
|
||||
// is authorized even if null is not allowed
|
||||
|
||||
// Pick the first one...
|
||||
$aClasses = $this->GetAllowedValues();
|
||||
$sDefault = key($aClasses);
|
||||
}
|
||||
|
||||
return $sDefault;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $aArgs
|
||||
* @param string $sContains
|
||||
*
|
||||
* @return array|null
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public function GetAllowedValues($aArgs = array(), $sContains = '')
|
||||
{
|
||||
$oValSetDef = $this->GetValuesDef();
|
||||
if (!$oValSetDef) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$aListClass = $oValSetDef->GetValues($aArgs, $sContains);
|
||||
/* @since 3.3.0 remove elements in class_exclusion_list */
|
||||
$sClassExclusionList = $this->GetOptional('class_exclusion_list', null);
|
||||
if (!empty($sClassExclusionList)) {
|
||||
foreach (explode(',', $sClassExclusionList) as $sClassName) {
|
||||
unset($aListClass[trim($sClassName)]);
|
||||
}
|
||||
}
|
||||
|
||||
return $aListClass;
|
||||
}
|
||||
|
||||
public function GetAsHTML($sValue, $oHostObject = null, $bLocalize = true)
|
||||
{
|
||||
if (empty($sValue)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return MetaModel::GetName($sValue);
|
||||
}
|
||||
|
||||
public function RequiresIndex()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function GetBasicFilterLooseOperator()
|
||||
{
|
||||
return '=';
|
||||
}
|
||||
|
||||
}
|
||||
214
sources/Core/AttributeDefinition/AttributeClassAttCodeSet.php
Normal file
214
sources/Core/AttributeDefinition/AttributeClassAttCodeSet.php
Normal file
@@ -0,0 +1,214 @@
|
||||
<?php
|
||||
|
||||
class AttributeClassAttCodeSet extends AttributeSet
|
||||
{
|
||||
const SEARCH_WIDGET_TYPE = self::SEARCH_WIDGET_TYPE_STRING;
|
||||
|
||||
const DEFAULT_PARAM_INCLUDE_CHILD_CLASSES_ATTRIBUTES = false;
|
||||
|
||||
public function __construct($sCode, array $aParams)
|
||||
{
|
||||
parent::__construct($sCode, $aParams);
|
||||
$this->aCSSClasses[] = 'attribute-class-attcode-set';
|
||||
}
|
||||
|
||||
public static function ListExpectedParams()
|
||||
{
|
||||
return array_merge(parent::ListExpectedParams(), array('class_field', 'attribute_definition_list', 'attribute_definition_exclusion_list'));
|
||||
}
|
||||
|
||||
public function GetMaxSize()
|
||||
{
|
||||
return max(255, 15 * $this->GetMaxItems());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $aArgs
|
||||
* @param string $sContains
|
||||
*
|
||||
* @return array|null
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public function GetAllowedValues($aArgs = array(), $sContains = '')
|
||||
{
|
||||
if (!isset($aArgs['this'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$oHostObj = $aArgs['this'];
|
||||
$sTargetClass = $this->Get('class_field');
|
||||
$sRootClass = $oHostObj->Get($sTargetClass);
|
||||
$bIncludeChildClasses = $this->GetOptional('include_child_classes_attributes', static::DEFAULT_PARAM_INCLUDE_CHILD_CLASSES_ATTRIBUTES);
|
||||
|
||||
$aExcludeDefs = array();
|
||||
$sAttDefExclusionList = $this->Get('attribute_definition_exclusion_list');
|
||||
if (!empty($sAttDefExclusionList)) {
|
||||
foreach (explode(',', $sAttDefExclusionList) as $sAttDefName) {
|
||||
$sAttDefName = trim($sAttDefName);
|
||||
$aExcludeDefs[$sAttDefName] = $sAttDefName;
|
||||
}
|
||||
}
|
||||
|
||||
$aAllowedDefs = array();
|
||||
$sAttDefList = $this->Get('attribute_definition_list');
|
||||
if (!empty($sAttDefList)) {
|
||||
foreach (explode(',', $sAttDefList) as $sAttDefName) {
|
||||
$sAttDefName = trim($sAttDefName);
|
||||
$aAllowedDefs[$sAttDefName] = $sAttDefName;
|
||||
}
|
||||
}
|
||||
|
||||
$aAllAttributes = array();
|
||||
if (!empty($sRootClass)) {
|
||||
$aClasses = array($sRootClass);
|
||||
if ($bIncludeChildClasses === true) {
|
||||
$aClasses = $aClasses + MetaModel::EnumChildClasses($sRootClass, ENUM_CHILD_CLASSES_EXCLUDETOP);
|
||||
}
|
||||
|
||||
foreach ($aClasses as $sClass) {
|
||||
foreach (MetaModel::GetAttributesList($sClass) as $sAttCode) {
|
||||
// Add attribute only if not already there (can be in leaf classes but not the root)
|
||||
if (!array_key_exists($sAttCode, $aAllAttributes)) {
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
$sAttDefClass = get_class($oAttDef);
|
||||
|
||||
// Skip excluded attdefs
|
||||
if (isset($aExcludeDefs[$sAttDefClass])) {
|
||||
continue;
|
||||
}
|
||||
// Skip not allowed attdefs only if list specified
|
||||
if (!empty($aAllowedDefs) && !isset($aAllowedDefs[$sAttDefClass])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$aAllAttributes[$sAttCode] = array(
|
||||
'classes' => array($sClass),
|
||||
);
|
||||
} else {
|
||||
$aAllAttributes[$sAttCode]['classes'][] = $sClass;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$aAllowedAttributes = array();
|
||||
foreach ($aAllAttributes as $sAttCode => $aAttData) {
|
||||
$iAttClassesCount = count($aAttData['classes']);
|
||||
$sAttFirstClass = $aAttData['classes'][0];
|
||||
$sAttLabel = MetaModel::GetLabel($sAttFirstClass, $sAttCode);
|
||||
|
||||
if ($sAttFirstClass === $sRootClass) {
|
||||
$sLabel = Dict::Format('Core:AttributeClassAttCodeSet:ItemLabel:AttributeFromClass', $sAttCode, $sAttLabel);
|
||||
} elseif ($iAttClassesCount === 1) {
|
||||
$sLabel = Dict::Format('Core:AttributeClassAttCodeSet:ItemLabel:AttributeFromOneChildClass', $sAttCode, $sAttLabel, MetaModel::GetName($sAttFirstClass));
|
||||
} else {
|
||||
$sLabel = Dict::Format('Core:AttributeClassAttCodeSet:ItemLabel:AttributeFromSeveralChildClasses', $sAttCode, $sAttLabel);
|
||||
}
|
||||
$aAllowedAttributes[$sAttCode] = $sLabel;
|
||||
}
|
||||
// N°6460 Always sort on the labels, not on the datamodel definition order
|
||||
natcasesort($aAllowedAttributes);
|
||||
|
||||
return $aAllowedAttributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* force an allowed value (type conversion and possibly forces a value as mySQL would do upon writing!
|
||||
*
|
||||
* @param $proposedValue
|
||||
* @param \DBObject $oHostObj
|
||||
*
|
||||
* @param bool $bIgnoreErrors
|
||||
*
|
||||
* @return mixed
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function MakeRealValue($proposedValue, $oHostObj, $bIgnoreErrors = false)
|
||||
{
|
||||
$oSet = new ormSet(MetaModel::GetAttributeOrigin($this->GetHostClass(), $this->GetCode()), $this->GetCode(), $this->GetMaxItems());
|
||||
$aArgs = array();
|
||||
if (!empty($oHostObj)) {
|
||||
$aArgs['this'] = $oHostObj;
|
||||
}
|
||||
$aAllowedAttributes = $this->GetAllowedValues($aArgs);
|
||||
$aInvalidAttCodes = array();
|
||||
if (is_string($proposedValue) && !empty($proposedValue)) {
|
||||
$aJsonFromWidget = json_decode($proposedValue, true);
|
||||
if (is_null($aJsonFromWidget)) {
|
||||
$proposedValue = trim($proposedValue);
|
||||
$aProposedValues = $this->FromStringToArray($proposedValue);
|
||||
$aValues = array();
|
||||
foreach ($aProposedValues as $sValue) {
|
||||
$sAttCode = trim($sValue);
|
||||
if (empty($aAllowedAttributes) || isset($aAllowedAttributes[$sAttCode])) {
|
||||
$aValues[$sAttCode] = $sAttCode;
|
||||
} else {
|
||||
$aInvalidAttCodes[] = $sAttCode;
|
||||
}
|
||||
}
|
||||
$oSet->SetValues($aValues);
|
||||
}
|
||||
} elseif ($proposedValue instanceof ormSet) {
|
||||
$oSet = $proposedValue;
|
||||
}
|
||||
if (!empty($aInvalidAttCodes) && !$bIgnoreErrors) {
|
||||
$sTargetClass = $this->Get('class_field');
|
||||
$sClass = $oHostObj->Get($sTargetClass);
|
||||
throw new CoreUnexpectedValue("The attribute(s) " . implode(', ', $aInvalidAttCodes) . " are invalid for class {$sClass}");
|
||||
}
|
||||
|
||||
return $oSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $value
|
||||
* @param \DBObject $oHostObject
|
||||
* @param bool $bLocalize
|
||||
*
|
||||
* @return string|null
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function GetAsHTML($value, $oHostObject = null, $bLocalize = true)
|
||||
{
|
||||
if ($value instanceof ormSet) {
|
||||
$value = $value->GetValues();
|
||||
}
|
||||
if (is_array($value)) {
|
||||
if (!empty($oHostObject) && $bLocalize) {
|
||||
$sTargetClass = $this->Get('class_field');
|
||||
$sClass = $oHostObject->Get($sTargetClass);
|
||||
|
||||
$aLocalizedValues = array();
|
||||
foreach ($value as $sAttCode) {
|
||||
try {
|
||||
$sAttClass = $sClass;
|
||||
|
||||
// Look for the first class (current or children) that have this attcode
|
||||
foreach (MetaModel::EnumChildClasses($sClass, ENUM_CHILD_CLASSES_ALL) as $sChildClass) {
|
||||
if (MetaModel::IsValidAttCode($sChildClass, $sAttCode)) {
|
||||
$sAttClass = $sChildClass;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$sLabelForHtmlAttribute = utils::HtmlEntities(MetaModel::GetLabel($sAttClass, $sAttCode) . " ($sAttCode)");
|
||||
$aLocalizedValues[] = '<span class="attribute-set-item" data-code="' . $sAttCode . '" data-label="' . $sLabelForHtmlAttribute . '" data-description="" data-tooltip-content="' . $sLabelForHtmlAttribute . '">' . $sAttCode . '</span>';
|
||||
} catch (Exception $e) {
|
||||
// Ignore bad values
|
||||
}
|
||||
}
|
||||
$value = $aLocalizedValues;
|
||||
}
|
||||
$value = implode('', $value);
|
||||
}
|
||||
return '<span class="' . implode(' ', $this->aCSSClasses) . '">' . $value . '</span>';
|
||||
}
|
||||
|
||||
public function IsNull($proposedValue)
|
||||
{
|
||||
return (empty($proposedValue));
|
||||
}
|
||||
}
|
||||
77
sources/Core/AttributeDefinition/AttributeClassState.php
Normal file
77
sources/Core/AttributeDefinition/AttributeClassState.php
Normal file
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* An attribute that matches a class state
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
class AttributeClassState extends AttributeString
|
||||
{
|
||||
const SEARCH_WIDGET_TYPE = self::SEARCH_WIDGET_TYPE_STRING;
|
||||
|
||||
/**
|
||||
* Useless constructor, but if not present PHP 7.4.0/7.4.1 is crashing :( (N°2329)
|
||||
*
|
||||
* @see https://www.php.net/manual/fr/language.oop5.decon.php states that child constructor can be ommited
|
||||
* @see https://bugs.php.net/bug.php?id=79010 bug solved in PHP 7.4.9
|
||||
*
|
||||
* @param string $sCode
|
||||
* @param array $aParams
|
||||
*
|
||||
* @throws \Exception
|
||||
* @noinspection SenselessProxyMethodInspection
|
||||
*/
|
||||
public function __construct($sCode, $aParams)
|
||||
{
|
||||
parent::__construct($sCode, $aParams);
|
||||
}
|
||||
|
||||
public static function ListExpectedParams()
|
||||
{
|
||||
return array_merge(parent::ListExpectedParams(), array('class_field'));
|
||||
}
|
||||
|
||||
public function GetAllowedValues($aArgs = array(), $sContains = '')
|
||||
{
|
||||
if (isset($aArgs['this'])) {
|
||||
$oHostObj = $aArgs['this'];
|
||||
$sTargetClass = $this->Get('class_field');
|
||||
$sClass = $oHostObj->Get($sTargetClass);
|
||||
|
||||
$aAllowedStates = array();
|
||||
foreach (MetaModel::EnumChildClasses($sClass, ENUM_CHILD_CLASSES_ALL) as $sChildClass) {
|
||||
$aValues = MetaModel::EnumStates($sChildClass);
|
||||
foreach (array_keys($aValues) as $sState) {
|
||||
$aAllowedStates[$sState] = $sState . ' (' . MetaModel::GetStateLabel($sChildClass, $sState) . ')';
|
||||
}
|
||||
}
|
||||
return $aAllowedStates;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function GetAsHTML($sValue, $oHostObject = null, $bLocalize = true)
|
||||
{
|
||||
if (empty($sValue)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (!empty($oHostObject)) {
|
||||
$sTargetClass = $this->Get('class_field');
|
||||
$sClass = $oHostObject->Get($sTargetClass);
|
||||
foreach (MetaModel::EnumChildClasses($sClass, ENUM_CHILD_CLASSES_ALL) as $sChildClass) {
|
||||
$aValues = MetaModel::EnumStates($sChildClass);
|
||||
if (in_array($sValue, $aValues)) {
|
||||
$sLabelForHtmlAttribute = utils::EscapeHtml($sValue . ' (' . MetaModel::GetStateLabel($sChildClass, $sValue) . ')');
|
||||
$sHTML = '<span class="attribute-set-item" data-code="' . $sValue . '" data-label="' . $sLabelForHtmlAttribute . '" data-description="" data-tooltip-content="' . $sLabelForHtmlAttribute . '">' . $sValue . '</span>';
|
||||
|
||||
return $sHTML;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $sValue;
|
||||
}
|
||||
|
||||
}
|
||||
449
sources/Core/AttributeDefinition/AttributeCustomFields.php
Normal file
449
sources/Core/AttributeDefinition/AttributeCustomFields.php
Normal file
@@ -0,0 +1,449 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Custom fields managed by an external implementation
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
class AttributeCustomFields extends AttributeDefinition
|
||||
{
|
||||
const SEARCH_WIDGET_TYPE = self::SEARCH_WIDGET_TYPE_RAW;
|
||||
|
||||
/**
|
||||
* Useless constructor, but if not present PHP 7.4.0/7.4.1 is crashing :( (N°2329)
|
||||
*
|
||||
* @see https://www.php.net/manual/fr/language.oop5.decon.php states that child constructor can be ommited
|
||||
* @see https://bugs.php.net/bug.php?id=79010 bug solved in PHP 7.4.9
|
||||
*
|
||||
* @param string $sCode
|
||||
* @param array $aParams
|
||||
*
|
||||
* @throws \Exception
|
||||
* @noinspection SenselessProxyMethodInspection
|
||||
*/
|
||||
public function __construct($sCode, $aParams)
|
||||
{
|
||||
parent::__construct($sCode, $aParams);
|
||||
}
|
||||
|
||||
public static function ListExpectedParams()
|
||||
{
|
||||
return array_merge(parent::ListExpectedParams(), array("handler_class"));
|
||||
}
|
||||
|
||||
public function GetEditClass()
|
||||
{
|
||||
return "CustomFields";
|
||||
}
|
||||
|
||||
public function IsWritable()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function LoadFromClassTables()
|
||||
{
|
||||
return false;
|
||||
} // See ReadValue...
|
||||
|
||||
public function GetDefaultValue(DBObject $oHostObject = null)
|
||||
{
|
||||
return new ormCustomFieldsValue($oHostObject, $this->GetCode());
|
||||
}
|
||||
|
||||
public function GetBasicFilterOperators()
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
public function GetBasicFilterLooseOperator()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function GetBasicFilterSQLExpr($sOpCode, $value)
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DBObject $oHostObject
|
||||
* @param array|null $aValues
|
||||
*
|
||||
* @return CustomFieldsHandler
|
||||
*/
|
||||
public function GetHandler($aValues = null)
|
||||
{
|
||||
$sHandlerClass = $this->Get('handler_class');
|
||||
/** @var \TemplateFieldsHandler $oHandler */
|
||||
$oHandler = new $sHandlerClass($this->GetCode());
|
||||
if (!is_null($aValues)) {
|
||||
$oHandler->SetCurrentValues($aValues);
|
||||
}
|
||||
|
||||
return $oHandler;
|
||||
}
|
||||
|
||||
public function GetPrerequisiteAttributes($sClass = null)
|
||||
{
|
||||
$sHandlerClass = $this->Get('handler_class');
|
||||
|
||||
return $sHandlerClass::GetPrerequisiteAttributes($sClass);
|
||||
}
|
||||
|
||||
public function GetEditValue($sValue, $oHostObj = null)
|
||||
{
|
||||
return $this->GetForTemplate($sValue, '', $oHostObj, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes the string representation out of the values given by the form defined in GetDisplayForm
|
||||
*/
|
||||
public function ReadValueFromPostedForm($oHostObject, $sFormPrefix)
|
||||
{
|
||||
$aRawData = json_decode(utils::ReadPostedParam("attr_{$sFormPrefix}{$this->GetCode()}", '{}', 'raw_data'), true);
|
||||
if ($aRawData != null) {
|
||||
return new ormCustomFieldsValue($oHostObject, $this->GetCode(), $aRawData);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public function MakeRealValue($proposedValue, $oHostObject)
|
||||
{
|
||||
if (is_object($proposedValue) && ($proposedValue instanceof ormCustomFieldsValue)) {
|
||||
if (false === $oHostObject->IsNew()) {
|
||||
// In that case we need additional keys : see \TemplateFieldsHandler::DoBuildForm
|
||||
$aRequestTemplateValues = $proposedValue->GetValues();
|
||||
if (false === array_key_exists('current_template_id', $aRequestTemplateValues)) {
|
||||
$aRequestTemplateValues['current_template_id'] = $aRequestTemplateValues['template_id'];
|
||||
$aRequestTemplateValues['current_template_data'] = $aRequestTemplateValues['template_data'];
|
||||
$proposedValue = new ormCustomFieldsValue($oHostObject, $this->GetCode(), $aRequestTemplateValues);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_null($proposedValue->GetHostObject())) {
|
||||
// the object might not be set : for example in \AttributeCustomFields::FromJSONToValue we don't have the object available :(
|
||||
$proposedValue->SetHostObject($oHostObject);
|
||||
}
|
||||
|
||||
return $proposedValue;
|
||||
}
|
||||
|
||||
if (is_string($proposedValue)) {
|
||||
$aValues = json_decode($proposedValue, true);
|
||||
|
||||
return new ormCustomFieldsValue($oHostObject, $this->GetCode(), $aValues);
|
||||
}
|
||||
|
||||
if (is_array($proposedValue)) {
|
||||
return new ormCustomFieldsValue($oHostObject, $this->GetCode(), $proposedValue);
|
||||
}
|
||||
|
||||
if (is_null($proposedValue)) {
|
||||
return new ormCustomFieldsValue($oHostObject, $this->GetCode());
|
||||
}
|
||||
|
||||
throw new Exception('Unexpected type for the value of a custom fields attribute: ' . gettype($proposedValue));
|
||||
}
|
||||
|
||||
public static function GetFormFieldClass()
|
||||
{
|
||||
return '\\Combodo\\iTop\\Form\\Field\\SubFormField';
|
||||
}
|
||||
|
||||
/**
|
||||
* Override to build the relevant form field
|
||||
*
|
||||
* When called first, $oFormField is null and will be created (eg. Make). Then when the ::parent is called and the
|
||||
* $oFormField is passed, MakeFormField behaves more like a Prepare.
|
||||
*/
|
||||
public function MakeFormField(DBObject $oObject, $oFormField = null)
|
||||
{
|
||||
if ($oFormField === null) {
|
||||
$sFormFieldClass = static::GetFormFieldClass();
|
||||
$oFormField = new $sFormFieldClass($this->GetCode());
|
||||
$oFormField->SetForm($this->GetForm($oObject));
|
||||
}
|
||||
parent::MakeFormField($oObject, $oFormField);
|
||||
|
||||
return $oFormField;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DBObject $oHostObject
|
||||
* @param null $sFormPrefix
|
||||
*
|
||||
* @return Combodo\iTop\Form\Form
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function GetForm(DBObject $oHostObject, $sFormPrefix = null)
|
||||
{
|
||||
try {
|
||||
$oValue = $oHostObject->Get($this->GetCode());
|
||||
$oHandler = $this->GetHandler($oValue->GetValues());
|
||||
$sFormId = utils::IsNullOrEmptyString($sFormPrefix) ? 'cf_' . $this->GetCode() : $sFormPrefix . '_cf_' . $this->GetCode();
|
||||
$oHandler->BuildForm($oHostObject, $sFormId);
|
||||
$oForm = $oHandler->GetForm();
|
||||
} catch (Exception $e) {
|
||||
$oForm = new \Combodo\iTop\Form\Form('');
|
||||
$oField = new \Combodo\iTop\Form\Field\LabelField('');
|
||||
$oField->SetLabel('Custom field error: ' . $e->getMessage());
|
||||
$oForm->AddField($oField);
|
||||
$oForm->Finalize();
|
||||
}
|
||||
|
||||
return $oForm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the data from where it has been stored. This verb must be implemented as soon as LoadFromClassTables returns false
|
||||
* and LoadInObject returns true
|
||||
*
|
||||
* @param DBObject $oHostObject
|
||||
*
|
||||
* @return mixed|null
|
||||
* @since 3.1.0
|
||||
*/
|
||||
public function ReadExternalValues(DBObject $oHostObject)
|
||||
{
|
||||
try {
|
||||
$oHandler = $this->GetHandler();
|
||||
$aValues = $oHandler->ReadValues($oHostObject);
|
||||
$oRet = new ormCustomFieldsValue($oHostObject, $this->GetCode(), $aValues);
|
||||
} catch (Exception $e) {
|
||||
$oRet = new ormCustomFieldsValue($oHostObject, $this->GetCode());
|
||||
}
|
||||
|
||||
return $oRet;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*
|
||||
* @since 3.1.0 N°6043 Move code contained in \AttributeCustomFields::WriteValue to this generic method
|
||||
*/
|
||||
public function WriteExternalValues(DBObject $oHostObject): void
|
||||
{
|
||||
$oValue = $oHostObject->Get($this->GetCode());
|
||||
if (!($oValue instanceof ormCustomFieldsValue)) {
|
||||
$oHandler = $this->GetHandler();
|
||||
$aValues = array();
|
||||
} else {
|
||||
// Pass the values through the form to make sure that they are correct
|
||||
$oHandler = $this->GetHandler($oValue->GetValues());
|
||||
$oHandler->BuildForm($oHostObject, '');
|
||||
$oForm = $oHandler->GetForm();
|
||||
$aValues = $oForm->GetCurrentValues();
|
||||
}
|
||||
|
||||
$oHandler->WriteValues($oHostObject, $aValues);
|
||||
}
|
||||
|
||||
/**
|
||||
* The part of the current attribute in the object's signature, for the supplied value
|
||||
*
|
||||
* @param ormCustomFieldsValue $value The value of this attribute for the object
|
||||
*
|
||||
* @return string The "signature" for this field/attribute
|
||||
*/
|
||||
public function Fingerprint($value)
|
||||
{
|
||||
$oHandler = $this->GetHandler($value->GetValues());
|
||||
|
||||
return $oHandler->GetValueFingerprint();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the validity of the data
|
||||
*
|
||||
* @param DBObject $oHostObject
|
||||
* @param $value
|
||||
*
|
||||
* @return bool|string true or error message
|
||||
*/
|
||||
public function CheckValue(DBObject $oHostObject, $value)
|
||||
{
|
||||
try {
|
||||
$oHandler = $this->GetHandler($value->GetValues());
|
||||
$oHandler->BuildForm($oHostObject, '');
|
||||
$ret = $oHandler->Validate($oHostObject);
|
||||
} catch (Exception $e) {
|
||||
$ret = $e->getMessage();
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup data upon object deletion (object id still available here)
|
||||
*
|
||||
* @param DBObject $oHostObject
|
||||
*
|
||||
* @throws \CoreException
|
||||
* @since 3.1.0
|
||||
*/
|
||||
public function DeleteExternalValues(DBObject $oHostObject): void
|
||||
{
|
||||
$oValue = $oHostObject->Get($this->GetCode());
|
||||
$oHandler = $this->GetHandler($oValue->GetValues());
|
||||
|
||||
$oHandler->DeleteValues($oHostObject);
|
||||
}
|
||||
|
||||
public function GetAsHTML($value, $oHostObject = null, $bLocalize = true)
|
||||
{
|
||||
try {
|
||||
/** @var \ormCustomFieldsValue $value */
|
||||
$sRet = $value->GetAsHTML($bLocalize);
|
||||
} catch (Exception $e) {
|
||||
$sRet = 'Custom field error: ' . utils::EscapeHtml($e->getMessage());
|
||||
}
|
||||
|
||||
return $sRet;
|
||||
}
|
||||
|
||||
public function GetAsXML($value, $oHostObject = null, $bLocalize = true)
|
||||
{
|
||||
try {
|
||||
$sRet = $value->GetAsXML($bLocalize);
|
||||
} catch (Exception $e) {
|
||||
$sRet = Str::pure2xml('Custom field error: ' . $e->getMessage());
|
||||
}
|
||||
|
||||
return $sRet;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \ormCustomFieldsValue $value
|
||||
* @param string $sSeparator
|
||||
* @param string $sTextQualifier
|
||||
* @param \DBObject $oHostObject
|
||||
* @param bool $bLocalize
|
||||
* @param bool $bConvertToPlainText
|
||||
*
|
||||
* @return string
|
||||
* @noinspection PhpParameterNameChangedDuringInheritanceInspection
|
||||
*/
|
||||
public function GetAsCSV(
|
||||
$value, $sSeparator = ',', $sTextQualifier = '"', $oHostObject = null, $bLocalize = true,
|
||||
$bConvertToPlainText = false
|
||||
)
|
||||
{
|
||||
try {
|
||||
$sRet = $value->GetAsCSV($sSeparator, $sTextQualifier, $bLocalize, $bConvertToPlainText);
|
||||
} catch (Exception $e) {
|
||||
$sFrom = array("\r\n", $sTextQualifier);
|
||||
$sTo = array("\n", $sTextQualifier . $sTextQualifier);
|
||||
$sEscaped = str_replace($sFrom, $sTo, 'Custom field error: ' . $e->getMessage());
|
||||
$sRet = $sTextQualifier . $sEscaped . $sTextQualifier;
|
||||
}
|
||||
|
||||
return $sRet;
|
||||
}
|
||||
|
||||
/**
|
||||
* List the available verbs for 'GetForTemplate'
|
||||
*/
|
||||
public function EnumTemplateVerbs()
|
||||
{
|
||||
$sHandlerClass = $this->Get('handler_class');
|
||||
|
||||
return $sHandlerClass::EnumTemplateVerbs();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get various representations of the value, for insertion into a template (e.g. in Notifications)
|
||||
*
|
||||
* @param $value mixed The current value of the field
|
||||
* @param $sVerb string The verb specifying the representation of the value
|
||||
* @param $oHostObject DBObject The object
|
||||
* @param $bLocalize bool Whether or not to localize the value
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function GetForTemplate($value, $sVerb, $oHostObject = null, $bLocalize = true)
|
||||
{
|
||||
try {
|
||||
$sRet = $value->GetForTemplate($sVerb, $bLocalize);
|
||||
} catch (Exception $e) {
|
||||
$sRet = 'Custom field error: ' . $e->getMessage();
|
||||
}
|
||||
|
||||
return $sRet;
|
||||
}
|
||||
|
||||
public function MakeValueFromString(
|
||||
$sProposedValue, $bLocalizedValue = false, $sSepItem = null, $sSepAttribute = null, $sSepValue = null,
|
||||
$sAttributeQualifier = null
|
||||
)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*
|
||||
* @param \ormCustomFieldsValue $value
|
||||
*
|
||||
* @return string|array
|
||||
*
|
||||
* @since 3.1.0 N°1150 now returns the value (was always returning null before)
|
||||
*/
|
||||
public function GetForJSON($value)
|
||||
{
|
||||
try {
|
||||
$sRet = $value->GetForJSON();
|
||||
} catch (Exception $e) {
|
||||
$sRet = 'Custom field error: ' . $e->getMessage();
|
||||
}
|
||||
|
||||
return $sRet;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*
|
||||
* @return ?\ormCustomFieldsValue with empty host object as we don't have it here (most consumers don't have an object in their context, for example in \RestUtils::GetObjectSetFromKey)
|
||||
* The host object will be set in {@see MakeRealValue}
|
||||
* All the necessary checks will be done in {@see CheckValue}
|
||||
*/
|
||||
public function FromJSONToValue($json)
|
||||
{
|
||||
return ormCustomFieldsValue::FromJSONToValue($json, $this);
|
||||
}
|
||||
|
||||
public function Equals($val1, $val2)
|
||||
{
|
||||
try {
|
||||
$bEquals = $val1->Equals($val2);
|
||||
} catch (Exception $e) {
|
||||
$bEquals = false;
|
||||
}
|
||||
|
||||
return $bEquals;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function HasAValue($proposedValue): bool
|
||||
{
|
||||
// Protection against wrong value type
|
||||
if (false === ($proposedValue instanceof ormCustomFieldsValue)) {
|
||||
return parent::HasAValue($proposedValue);
|
||||
}
|
||||
|
||||
return count($proposedValue->GetValues()) > 0;
|
||||
}
|
||||
|
||||
protected function GetChangeRecordAdditionalData(CMDBChangeOp $oMyChangeOp, DBObject $oObject, $original, $value): void
|
||||
{
|
||||
$oMyChangeOp->Set("prevdata", json_encode($original->GetValues()));
|
||||
}
|
||||
|
||||
protected function GetChangeRecordClassName(): string
|
||||
{
|
||||
return CMDBChangeOpSetAttributeCustomFields::class;
|
||||
}
|
||||
}
|
||||
24
sources/Core/AttributeDefinition/AttributeDBField.php
Normal file
24
sources/Core/AttributeDefinition/AttributeDBField.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Base class for all kind of DB attributes, with the exception of external keys
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
class AttributeDBField extends AttributeDBFieldVoid
|
||||
{
|
||||
public static function ListExpectedParams()
|
||||
{
|
||||
return array_merge(parent::ListExpectedParams(), array("default_value", "is_null_allowed"));
|
||||
}
|
||||
|
||||
public function GetDefaultValue(DBObject $oHostObject = null)
|
||||
{
|
||||
return $this->MakeRealValue($this->Get("default_value"), $oHostObject);
|
||||
}
|
||||
|
||||
public function IsNullAllowed()
|
||||
{
|
||||
return $this->Get("is_null_allowed");
|
||||
}
|
||||
}
|
||||
146
sources/Core/AttributeDefinition/AttributeDBFieldVoid.php
Normal file
146
sources/Core/AttributeDefinition/AttributeDBFieldVoid.php
Normal file
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Abstract class implementing default filters for a DB column
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
class AttributeDBFieldVoid extends AttributeDefinition
|
||||
{
|
||||
public static function ListExpectedParams()
|
||||
{
|
||||
return array_merge(parent::ListExpectedParams(), array("allowed_values", "depends_on", "sql"));
|
||||
}
|
||||
|
||||
// To be overriden, used in GetSQLColumns
|
||||
protected function GetSQLCol($bFullSpec = false)
|
||||
{
|
||||
return 'VARCHAR(255)'
|
||||
. CMDBSource::GetSqlStringColumnDefinition()
|
||||
. ($bFullSpec ? $this->GetSQLColSpec() : '');
|
||||
}
|
||||
|
||||
protected function GetSQLColSpec()
|
||||
{
|
||||
$default = $this->ScalarToSQL($this->GetDefaultValue());
|
||||
if (is_null($default)) {
|
||||
$sRet = '';
|
||||
} else {
|
||||
if (is_numeric($default)) {
|
||||
// Though it is a string in PHP, it will be considered as a numeric value in MySQL
|
||||
// Then it must not be quoted here, to preserve the compatibility with the value returned by CMDBSource::GetFieldSpec
|
||||
$sRet = " DEFAULT $default";
|
||||
} else {
|
||||
$sRet = " DEFAULT " . CMDBSource::Quote($default);
|
||||
}
|
||||
}
|
||||
|
||||
return $sRet;
|
||||
}
|
||||
|
||||
public function GetEditClass()
|
||||
{
|
||||
return "String";
|
||||
}
|
||||
|
||||
public function GetValuesDef()
|
||||
{
|
||||
return $this->Get("allowed_values");
|
||||
}
|
||||
|
||||
public function GetPrerequisiteAttributes($sClass = null)
|
||||
{
|
||||
return $this->Get("depends_on");
|
||||
}
|
||||
|
||||
public static function IsBasedOnDBColumns()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function IsScalar()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function IsWritable()
|
||||
{
|
||||
return !$this->IsMagic();
|
||||
}
|
||||
|
||||
public function GetSQLExpr()
|
||||
{
|
||||
return $this->Get("sql");
|
||||
}
|
||||
|
||||
public function GetDefaultValue(DBObject $oHostObject = null)
|
||||
{
|
||||
return $this->MakeRealValue("", $oHostObject);
|
||||
}
|
||||
|
||||
public function IsNullAllowed()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
protected function ScalarToSQL($value)
|
||||
{
|
||||
return $value;
|
||||
} // format value as a valuable SQL literal (quoted outside)
|
||||
|
||||
public function GetSQLExpressions($sPrefix = '')
|
||||
{
|
||||
$aColumns = array();
|
||||
// Note: to optimize things, the existence of the attribute is determined by the existence of one column with an empty suffix
|
||||
$aColumns[''] = $this->Get("sql");
|
||||
|
||||
return $aColumns;
|
||||
}
|
||||
|
||||
public function FromSQLToValue($aCols, $sPrefix = '')
|
||||
{
|
||||
$value = $this->MakeRealValue($aCols[$sPrefix . ''], null);
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function GetSQLValues($value)
|
||||
{
|
||||
$aValues = array();
|
||||
$aValues[$this->Get("sql")] = $this->ScalarToSQL($value);
|
||||
|
||||
return $aValues;
|
||||
}
|
||||
|
||||
public function GetSQLColumns($bFullSpec = false)
|
||||
{
|
||||
$aColumns = array();
|
||||
$aColumns[$this->Get("sql")] = $this->GetSQLCol($bFullSpec);
|
||||
|
||||
return $aColumns;
|
||||
}
|
||||
|
||||
public function GetBasicFilterOperators()
|
||||
{
|
||||
return array("=" => "equals", "!=" => "differs from");
|
||||
}
|
||||
|
||||
public function GetBasicFilterLooseOperator()
|
||||
{
|
||||
return "=";
|
||||
}
|
||||
|
||||
public function GetBasicFilterSQLExpr($sOpCode, $value)
|
||||
{
|
||||
$sQValue = CMDBSource::Quote($value);
|
||||
switch ($sOpCode) {
|
||||
case '!=':
|
||||
return $this->GetSQLExpr() . " != $sQValue";
|
||||
break;
|
||||
case '=':
|
||||
default:
|
||||
return $this->GetSQLExpr() . " = $sQValue";
|
||||
}
|
||||
}
|
||||
}
|
||||
98
sources/Core/AttributeDefinition/AttributeDashboard.php
Normal file
98
sources/Core/AttributeDefinition/AttributeDashboard.php
Normal file
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
class AttributeDashboard extends AttributeDefinition
|
||||
{
|
||||
/**
|
||||
* Useless constructor, but if not present PHP 7.4.0/7.4.1 is crashing :( (N°2329)
|
||||
*
|
||||
* @see https://www.php.net/manual/fr/language.oop5.decon.php states that child constructor can be ommited
|
||||
* @see https://bugs.php.net/bug.php?id=79010 bug solved in PHP 7.4.9
|
||||
*
|
||||
* @param string $sCode
|
||||
* @param array $aParams
|
||||
*
|
||||
* @throws \Exception
|
||||
* @noinspection SenselessProxyMethodInspection
|
||||
*/
|
||||
public function __construct($sCode, $aParams)
|
||||
{
|
||||
parent::__construct($sCode, $aParams);
|
||||
}
|
||||
|
||||
public static function ListExpectedParams()
|
||||
{
|
||||
return array_merge(parent::ListExpectedParams(),
|
||||
array("definition_file", "is_user_editable"));
|
||||
}
|
||||
|
||||
public function GetDashboard()
|
||||
{
|
||||
$sAttCode = $this->GetCode();
|
||||
$sClass = MetaModel::GetAttributeOrigin($this->GetHostClass(), $sAttCode);
|
||||
$sFilePath = APPROOT . 'env-' . utils::GetCurrentEnvironment() . '/' . $this->Get('definition_file');
|
||||
return RuntimeDashboard::GetDashboard($sFilePath, $sClass . '__' . $sAttCode);
|
||||
}
|
||||
|
||||
public function IsUserEditable()
|
||||
{
|
||||
return $this->Get('is_user_editable');
|
||||
}
|
||||
|
||||
public function IsWritable()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function GetEditClass()
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
public function GetDefaultValue(DBObject $oHostObject = null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function GetBasicFilterOperators()
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
public function GetBasicFilterLooseOperator()
|
||||
{
|
||||
return '=';
|
||||
}
|
||||
|
||||
public function GetBasicFilterSQLExpr($sOpCode, $value)
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function MakeFormField(DBObject $oObject, $oFormField = null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// if this verb returns false, then GetValue must be implemented
|
||||
public static function LoadInObject()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function GetValue($oHostObject)
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function HasAValue($proposedValue): bool
|
||||
{
|
||||
// Always return false for now, we don't consider a custom version of a dashboard
|
||||
return false;
|
||||
}
|
||||
}
|
||||
105
sources/Core/AttributeDefinition/AttributeDate.php
Normal file
105
sources/Core/AttributeDefinition/AttributeDate.php
Normal file
@@ -0,0 +1,105 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Map a date+time column to an attribute
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
class AttributeDate extends AttributeDateTime
|
||||
{
|
||||
const SEARCH_WIDGET_TYPE = self::SEARCH_WIDGET_TYPE_DATE;
|
||||
|
||||
public static $oDateFormat = null;
|
||||
|
||||
/**
|
||||
* Useless constructor, but if not present PHP 7.4.0/7.4.1 is crashing :( (N°2329)
|
||||
*
|
||||
* @see https://www.php.net/manual/fr/language.oop5.decon.php states that child constructor can be ommited
|
||||
* @see https://bugs.php.net/bug.php?id=79010 bug solved in PHP 7.4.9
|
||||
*
|
||||
* @param string $sCode
|
||||
* @param array $aParams
|
||||
*
|
||||
* @throws \Exception
|
||||
* @noinspection SenselessProxyMethodInspection
|
||||
*/
|
||||
public function __construct($sCode, $aParams)
|
||||
{
|
||||
parent::__construct($sCode, $aParams);
|
||||
}
|
||||
|
||||
public static function GetFormat()
|
||||
{
|
||||
if (self::$oDateFormat == null) {
|
||||
AttributeDateTime::LoadFormatFromConfig();
|
||||
}
|
||||
|
||||
return self::$oDateFormat;
|
||||
}
|
||||
|
||||
public static function SetFormat(DateTimeFormat $oDateFormat)
|
||||
{
|
||||
self::$oDateFormat = $oDateFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the format string used for the date & time stored in memory
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function GetInternalFormat()
|
||||
{
|
||||
return 'Y-m-d';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the format string used for the date & time written to MySQL
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function GetSQLFormat()
|
||||
{
|
||||
return 'Y-m-d';
|
||||
}
|
||||
|
||||
public static function ListExpectedParams()
|
||||
{
|
||||
return parent::ListExpectedParams();
|
||||
//return array_merge(parent::ListExpectedParams(), array());
|
||||
}
|
||||
|
||||
public function GetEditClass()
|
||||
{
|
||||
return "Date";
|
||||
}
|
||||
|
||||
protected function GetSQLCol($bFullSpec = false)
|
||||
{
|
||||
return "DATE";
|
||||
}
|
||||
|
||||
public function GetImportColumns()
|
||||
{
|
||||
// Allow an empty string to be a valid value (synonym for "reset")
|
||||
$aColumns = array();
|
||||
$aColumns[$this->GetCode()] = 'VARCHAR(10)' . CMDBSource::GetSqlStringColumnDefinition();
|
||||
|
||||
return $aColumns;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Override to specify Field class
|
||||
*
|
||||
* When called first, $oFormField is null and will be created (eg. Make). Then when the ::parent is called and the
|
||||
* $oFormField is passed, MakeFormField behave more like a Prepare.
|
||||
*/
|
||||
public function MakeFormField(DBObject $oObject, $oFormField = null)
|
||||
{
|
||||
$oFormField = parent::MakeFormField($oObject, $oFormField);
|
||||
$oFormField->SetDateOnly(true);
|
||||
|
||||
return $oFormField;
|
||||
}
|
||||
|
||||
}
|
||||
488
sources/Core/AttributeDefinition/AttributeDateTime.php
Normal file
488
sources/Core/AttributeDefinition/AttributeDateTime.php
Normal file
@@ -0,0 +1,488 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Map a date+time column to an attribute
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
class AttributeDateTime extends AttributeDBField
|
||||
{
|
||||
const SEARCH_WIDGET_TYPE = self::SEARCH_WIDGET_TYPE_DATE_TIME;
|
||||
|
||||
public static $oFormat = null;
|
||||
|
||||
/**
|
||||
* Useless constructor, but if not present PHP 7.4.0/7.4.1 is crashing :( (N°2329)
|
||||
*
|
||||
* @see https://www.php.net/manual/fr/language.oop5.decon.php states that child constructor can be ommited
|
||||
* @see https://bugs.php.net/bug.php?id=79010 bug solved in PHP 7.4.9
|
||||
*
|
||||
* @param string $sCode
|
||||
* @param array $aParams
|
||||
*
|
||||
* @throws \Exception
|
||||
* @noinspection SenselessProxyMethodInspection
|
||||
*/
|
||||
public function __construct($sCode, $aParams)
|
||||
{
|
||||
parent::__construct($sCode, $aParams);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return DateTimeFormat
|
||||
*/
|
||||
public static function GetFormat()
|
||||
{
|
||||
if (self::$oFormat == null) {
|
||||
static::LoadFormatFromConfig();
|
||||
}
|
||||
|
||||
return self::$oFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the 3 settings: date format, time format and data_time format from the configuration
|
||||
*/
|
||||
public static function LoadFormatFromConfig()
|
||||
{
|
||||
$aFormats = MetaModel::GetConfig()->Get('date_and_time_format');
|
||||
$sLang = Dict::GetUserLanguage();
|
||||
$sDateFormat = isset($aFormats[$sLang]['date']) ? $aFormats[$sLang]['date'] : (isset($aFormats['default']['date']) ? $aFormats['default']['date'] : 'Y-m-d');
|
||||
$sTimeFormat = isset($aFormats[$sLang]['time']) ? $aFormats[$sLang]['time'] : (isset($aFormats['default']['time']) ? $aFormats['default']['time'] : 'H:i:s');
|
||||
$sDateAndTimeFormat = isset($aFormats[$sLang]['date_time']) ? $aFormats[$sLang]['date_time'] : (isset($aFormats['default']['date_time']) ? $aFormats['default']['date_time'] : '$date $time');
|
||||
|
||||
$sFullFormat = str_replace(array('$date', '$time'), array($sDateFormat, $sTimeFormat), $sDateAndTimeFormat);
|
||||
|
||||
self::SetFormat(new DateTimeFormat($sFullFormat));
|
||||
AttributeDate::SetFormat(new DateTimeFormat($sDateFormat));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the format string used for the date & time stored in memory
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function GetInternalFormat()
|
||||
{
|
||||
return 'Y-m-d H:i:s';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the format string used for the date & time written to MySQL
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function GetSQLFormat()
|
||||
{
|
||||
return 'Y-m-d H:i:s';
|
||||
}
|
||||
|
||||
public static function SetFormat(DateTimeFormat $oDateTimeFormat)
|
||||
{
|
||||
self::$oFormat = $oDateTimeFormat;
|
||||
}
|
||||
|
||||
public static function GetSQLTimeFormat()
|
||||
{
|
||||
return 'H:i:s';
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a search string coming from user input
|
||||
*
|
||||
* @param string $sSearchString
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function ParseSearchString($sSearchString)
|
||||
{
|
||||
try {
|
||||
$oDateTime = $this->GetFormat()->Parse($sSearchString);
|
||||
$sSearchString = $oDateTime->format($this->GetInternalFormat());
|
||||
} catch (Exception $e) {
|
||||
$sFormatString = '!' . (string)AttributeDate::GetFormat(); // BEWARE: ! is needed to set non-parsed fields to zero !!!
|
||||
$oDateTime = DateTime::createFromFormat($sFormatString, $sSearchString);
|
||||
if ($oDateTime !== false) {
|
||||
$sSearchString = $oDateTime->format($this->GetInternalFormat());
|
||||
}
|
||||
}
|
||||
|
||||
return $sSearchString;
|
||||
}
|
||||
|
||||
public static function GetFormFieldClass()
|
||||
{
|
||||
return '\\Combodo\\iTop\\Form\\Field\\DateTimeField';
|
||||
}
|
||||
|
||||
/**
|
||||
* Override to specify Field class
|
||||
*
|
||||
* When called first, $oFormField is null and will be created (eg. Make). Then when the ::parent is called and the
|
||||
* $oFormField is passed, MakeFormField behave more like a Prepare.
|
||||
*/
|
||||
public function MakeFormField(DBObject $oObject, $oFormField = null)
|
||||
{
|
||||
if ($oFormField === null) {
|
||||
$sFormFieldClass = static::GetFormFieldClass();
|
||||
$oFormField = new $sFormFieldClass($this->GetCode());
|
||||
}
|
||||
$oFormField->SetPHPDateTimeFormat((string)$this->GetFormat());
|
||||
$oFormField->SetJSDateTimeFormat($this->GetFormat()->ToMomentJS());
|
||||
|
||||
$oFormField = parent::MakeFormField($oObject, $oFormField);
|
||||
|
||||
// After call to the parent as it sets the current value
|
||||
$oValue = $oObject->Get($this->GetCode());
|
||||
if ($oValue === $this->GetNullValue()) {
|
||||
$oValue = $this->GetDefaultValue($oObject);
|
||||
}
|
||||
$oFormField->SetCurrentValue($this->GetFormat()->Format($oValue));
|
||||
|
||||
|
||||
return $oFormField;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function EnumTemplateVerbs()
|
||||
{
|
||||
return array(
|
||||
'' => 'Formatted representation',
|
||||
'raw' => 'Not formatted representation',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function GetForTemplate($value, $sVerb, $oHostObject = null, $bLocalize = true)
|
||||
{
|
||||
switch ($sVerb) {
|
||||
case '':
|
||||
case 'text':
|
||||
return static::GetFormat()->format($value);
|
||||
break;
|
||||
case 'html':
|
||||
// Note: Not passing formatted value as the method will format it.
|
||||
return $this->GetAsHTML($value);
|
||||
break;
|
||||
case 'raw':
|
||||
return $value;
|
||||
break;
|
||||
default:
|
||||
return parent::GetForTemplate($value, $sVerb, $oHostObject, $bLocalize);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public static function ListExpectedParams()
|
||||
{
|
||||
return parent::ListExpectedParams();
|
||||
//return array_merge(parent::ListExpectedParams(), array());
|
||||
}
|
||||
|
||||
public function GetEditClass()
|
||||
{
|
||||
return "DateTime";
|
||||
}
|
||||
|
||||
|
||||
public function GetEditValue($sValue, $oHostObj = null)
|
||||
{
|
||||
return (string)static::GetFormat()->format($sValue);
|
||||
}
|
||||
|
||||
public function GetValueLabel($sValue, $oHostObj = null)
|
||||
{
|
||||
return (string)static::GetFormat()->format($sValue);
|
||||
}
|
||||
|
||||
protected function GetSQLCol($bFullSpec = false)
|
||||
{
|
||||
return "DATETIME";
|
||||
}
|
||||
|
||||
public function GetImportColumns()
|
||||
{
|
||||
// Allow an empty string to be a valid value (synonym for "reset")
|
||||
$aColumns = array();
|
||||
$aColumns[$this->GetCode()] = 'VARCHAR(19)' . CMDBSource::GetSqlStringColumnDefinition();
|
||||
|
||||
return $aColumns;
|
||||
}
|
||||
|
||||
public static function GetAsUnixSeconds($value)
|
||||
{
|
||||
$oDeadlineDateTime = new DateTime($value);
|
||||
$iUnixSeconds = $oDeadlineDateTime->format('U');
|
||||
|
||||
return $iUnixSeconds;
|
||||
}
|
||||
|
||||
public function GetDefaultValue(DBObject $oHostObject = null)
|
||||
{
|
||||
$sDefaultValue = $this->Get('default_value');
|
||||
if (utils::IsNotNullOrEmptyString($sDefaultValue)) {
|
||||
try {
|
||||
$sDefaultDate = Expression::FromOQL($sDefaultValue)->Evaluate([]);
|
||||
} catch (Exception $e) {
|
||||
try {
|
||||
$sDefaultDate = Expression::FromOQL('"' . $sDefaultValue . '"')->Evaluate([]);
|
||||
} catch (Exception $e) {
|
||||
IssueLog::Error("Invalid default value '$sDefaultValue' for field '{$this->GetCode()}' on class '{$this->GetHostClass()}', defaulting to null");
|
||||
|
||||
return $this->GetNullValue();
|
||||
}
|
||||
}
|
||||
try {
|
||||
$oDate = new DateTimeImmutable($sDefaultDate);
|
||||
} catch (Exception $e) {
|
||||
IssueLog::Error("Invalid default value '$sDefaultValue' for field '{$this->GetCode()}' on class '{$this->GetHostClass()}', defaulting to null");
|
||||
return $this->GetNullValue();
|
||||
}
|
||||
return $oDate->format($this->GetInternalFormat());
|
||||
}
|
||||
return $this->GetNullValue();
|
||||
}
|
||||
|
||||
public function GetValidationPattern()
|
||||
{
|
||||
return static::GetFormat()->ToRegExpr();
|
||||
}
|
||||
|
||||
public function GetBasicFilterOperators()
|
||||
{
|
||||
return array(
|
||||
"=" => "equals",
|
||||
"!=" => "differs from",
|
||||
"<" => "before",
|
||||
"<=" => "before",
|
||||
">" => "after (strictly)",
|
||||
">=" => "after",
|
||||
"SameDay" => "same day (strip time)",
|
||||
"SameMonth" => "same year/month",
|
||||
"SameYear" => "same year",
|
||||
"Today" => "today",
|
||||
">|" => "after today + N days",
|
||||
"<|" => "before today + N days",
|
||||
"=|" => "equals today + N days",
|
||||
);
|
||||
}
|
||||
|
||||
public function GetBasicFilterLooseOperator()
|
||||
{
|
||||
// Unless we implement a "same xxx, depending on given precision" !
|
||||
return "=";
|
||||
}
|
||||
|
||||
public function GetBasicFilterSQLExpr($sOpCode, $value)
|
||||
{
|
||||
$sQValue = CMDBSource::Quote($value);
|
||||
|
||||
switch ($sOpCode) {
|
||||
case '=':
|
||||
case '!=':
|
||||
case '<':
|
||||
case '<=':
|
||||
case '>':
|
||||
case '>=':
|
||||
return $this->GetSQLExpr() . " $sOpCode $sQValue";
|
||||
case 'SameDay':
|
||||
return "DATE(" . $this->GetSQLExpr() . ") = DATE($sQValue)";
|
||||
case 'SameMonth':
|
||||
return "DATE_FORMAT(" . $this->GetSQLExpr() . ", '%Y-%m') = DATE_FORMAT($sQValue, '%Y-%m')";
|
||||
case 'SameYear':
|
||||
return "MONTH(" . $this->GetSQLExpr() . ") = MONTH($sQValue)";
|
||||
case 'Today':
|
||||
return "DATE(" . $this->GetSQLExpr() . ") = CURRENT_DATE()";
|
||||
case '>|':
|
||||
return "DATE(" . $this->GetSQLExpr() . ") > DATE_ADD(CURRENT_DATE(), INTERVAL $sQValue DAY)";
|
||||
case '<|':
|
||||
return "DATE(" . $this->GetSQLExpr() . ") < DATE_ADD(CURRENT_DATE(), INTERVAL $sQValue DAY)";
|
||||
case '=|':
|
||||
return "DATE(" . $this->GetSQLExpr() . ") = DATE_ADD(CURRENT_DATE(), INTERVAL $sQValue DAY)";
|
||||
default:
|
||||
return $this->GetSQLExpr() . " = $sQValue";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*
|
||||
* @param int|DateTime|string $proposedValue possible values :
|
||||
* - timestamp ({@see DateTime::getTimestamp())
|
||||
* - {@see \DateTime} PHP object
|
||||
* - string, following the {@see GetInternalFormat} format.
|
||||
*
|
||||
* @throws \CoreUnexpectedValue if invalid value type or the string passed cannot be converted
|
||||
*/
|
||||
public function MakeRealValue($proposedValue, $oHostObj)
|
||||
{
|
||||
if (is_null($proposedValue)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (is_numeric($proposedValue)) {
|
||||
return date(static::GetInternalFormat(), $proposedValue);
|
||||
}
|
||||
|
||||
if (is_object($proposedValue) && ($proposedValue instanceof DateTime)) {
|
||||
return $proposedValue->format(static::GetInternalFormat());
|
||||
}
|
||||
|
||||
if (is_string($proposedValue)) {
|
||||
if (($proposedValue === '') && $this->IsNullAllowed()) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
$oFormat = new DateTimeFormat(static::GetInternalFormat());
|
||||
$oFormat->Parse($proposedValue);
|
||||
} catch (Exception $e) {
|
||||
throw new CoreUnexpectedValue('Wrong format for date attribute ' . $this->GetCode() . ', expecting "' . $this->GetInternalFormat() . '" and got "' . $proposedValue . '"');
|
||||
}
|
||||
|
||||
return $proposedValue;
|
||||
}
|
||||
|
||||
throw new CoreUnexpectedValue('Wrong format for date attribute ' . $this->GetCode());
|
||||
}
|
||||
|
||||
public function ScalarToSQL($value)
|
||||
{
|
||||
if (empty($value)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function GetAsHTML($value, $oHostObject = null, $bLocalize = true)
|
||||
{
|
||||
return Str::pure2html(static::GetFormat()->format($value));
|
||||
}
|
||||
|
||||
public function GetAsXML($value, $oHostObject = null, $bLocalize = true)
|
||||
{
|
||||
return Str::pure2xml($value);
|
||||
}
|
||||
|
||||
public function GetAsCSV(
|
||||
$sValue, $sSeparator = ',', $sTextQualifier = '"', $oHostObject = null, $bLocalize = true,
|
||||
$bConvertToPlainText = false
|
||||
)
|
||||
{
|
||||
if (empty($sValue) || ($sValue === '0000-00-00 00:00:00') || ($sValue === '0000-00-00')) {
|
||||
return '';
|
||||
} else {
|
||||
if ((string)static::GetFormat() !== static::GetInternalFormat()) {
|
||||
// Format conversion
|
||||
$oDate = new DateTime($sValue);
|
||||
if ($oDate !== false) {
|
||||
$sValue = static::GetFormat()->format($oDate);
|
||||
}
|
||||
}
|
||||
}
|
||||
$sFrom = array("\r\n", $sTextQualifier);
|
||||
$sTo = array("\n", $sTextQualifier . $sTextQualifier);
|
||||
$sEscaped = str_replace($sFrom, $sTo, (string)$sValue);
|
||||
|
||||
return $sTextQualifier . $sEscaped . $sTextQualifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a string to find some smart search patterns and build the corresponding search/OQL condition
|
||||
* Each derived class is reponsible for defining and processing their own smart patterns, the base class
|
||||
* does nothing special, and just calls the default (loose) operator
|
||||
*
|
||||
* @param string $sSearchText The search string to analyze for smart patterns
|
||||
* @param FieldExpression $oField The FieldExpression representing the atttribute code in this OQL query
|
||||
* @param array $aParams Values of the query parameters
|
||||
* @param bool $bParseSearchString
|
||||
*
|
||||
* @return Expression The search condition to be added (AND) to the current search
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public function GetSmartConditionExpression(
|
||||
$sSearchText, FieldExpression $oField, &$aParams, $bParseSearchString = false
|
||||
)
|
||||
{
|
||||
// Possible smart patterns
|
||||
$aPatterns = array(
|
||||
'between' => array('pattern' => '/^\[(.*),(.*)\]$/', 'operator' => 'n/a'),
|
||||
'greater than or equal' => array('pattern' => '/^>=(.*)$/', 'operator' => '>='),
|
||||
'greater than' => array('pattern' => '/^>(.*)$/', 'operator' => '>'),
|
||||
'less than or equal' => array('pattern' => '/^<=(.*)$/', 'operator' => '<='),
|
||||
'less than' => array('pattern' => '/^<(.*)$/', 'operator' => '<'),
|
||||
);
|
||||
|
||||
$sPatternFound = '';
|
||||
$aMatches = array();
|
||||
foreach ($aPatterns as $sPatName => $sPattern) {
|
||||
if (preg_match($sPattern['pattern'], $sSearchText, $aMatches)) {
|
||||
$sPatternFound = $sPatName;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch ($sPatternFound) {
|
||||
case 'between':
|
||||
|
||||
$sParamName1 = $oField->GetParent() . '_' . $oField->GetName() . '_1';
|
||||
$oRightExpr = new VariableExpression($sParamName1);
|
||||
if ($bParseSearchString) {
|
||||
$aParams[$sParamName1] = $this->ParseSearchString($aMatches[1]);
|
||||
} else {
|
||||
$aParams[$sParamName1] = $aMatches[1];
|
||||
}
|
||||
$oCondition1 = new BinaryExpression($oField, '>=', $oRightExpr);
|
||||
|
||||
$sParamName2 = $oField->GetParent() . '_' . $oField->GetName() . '_2';
|
||||
$oRightExpr = new VariableExpression($sParamName2);
|
||||
if ($bParseSearchString) {
|
||||
$aParams[$sParamName2] = $this->ParseSearchString($aMatches[2]);
|
||||
} else {
|
||||
$aParams[$sParamName2] = $aMatches[2];
|
||||
}
|
||||
$oCondition2 = new BinaryExpression($oField, '<=', $oRightExpr);
|
||||
|
||||
$oNewCondition = new BinaryExpression($oCondition1, 'AND', $oCondition2);
|
||||
break;
|
||||
|
||||
case 'greater than':
|
||||
case 'greater than or equal':
|
||||
case 'less than':
|
||||
case 'less than or equal':
|
||||
$sSQLOperator = $aPatterns[$sPatternFound]['operator'];
|
||||
$sParamName = $oField->GetParent() . '_' . $oField->GetName();
|
||||
$oRightExpr = new VariableExpression($sParamName);
|
||||
if ($bParseSearchString) {
|
||||
$aParams[$sParamName] = $this->ParseSearchString($aMatches[1]);
|
||||
} else {
|
||||
$aParams[$sParamName] = $aMatches[1];
|
||||
}
|
||||
$oNewCondition = new BinaryExpression($oField, $sSQLOperator, $oRightExpr);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
$oNewCondition = parent::GetSmartConditionExpression($sSearchText, $oField, $aParams);
|
||||
|
||||
}
|
||||
|
||||
return $oNewCondition;
|
||||
}
|
||||
|
||||
|
||||
public function GetHelpOnSmartSearch()
|
||||
{
|
||||
$sDict = parent::GetHelpOnSmartSearch();
|
||||
|
||||
$oFormat = static::GetFormat();
|
||||
$sExample = $oFormat->Format(new DateTime('2015-07-19 18:40:00'));
|
||||
|
||||
return vsprintf($sDict, array($oFormat->ToPlaceholder(), $sExample));
|
||||
}
|
||||
}
|
||||
80
sources/Core/AttributeDefinition/AttributeDeadline.php
Normal file
80
sources/Core/AttributeDefinition/AttributeDeadline.php
Normal file
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* A dead line stored as a date & time
|
||||
* The only difference with the DateTime attribute is the display:
|
||||
* relative to the current time
|
||||
*/
|
||||
class AttributeDeadline extends AttributeDateTime
|
||||
{
|
||||
/**
|
||||
* Useless constructor, but if not present PHP 7.4.0/7.4.1 is crashing :( (N°2329)
|
||||
*
|
||||
* @see https://www.php.net/manual/fr/language.oop5.decon.php states that child constructor can be ommited
|
||||
* @see https://bugs.php.net/bug.php?id=79010 bug solved in PHP 7.4.9
|
||||
*
|
||||
* @param string $sCode
|
||||
* @param array $aParams
|
||||
*
|
||||
* @throws \Exception
|
||||
* @noinspection SenselessProxyMethodInspection
|
||||
*/
|
||||
public function __construct($sCode, $aParams)
|
||||
{
|
||||
parent::__construct($sCode, $aParams);
|
||||
}
|
||||
|
||||
public function GetAsHTML($value, $oHostObject = null, $bLocalize = true)
|
||||
{
|
||||
$sResult = self::FormatDeadline($value);
|
||||
|
||||
return $sResult;
|
||||
}
|
||||
|
||||
public static function FormatDeadline($value)
|
||||
{
|
||||
$sResult = '';
|
||||
if ($value !== null) {
|
||||
$iValue = AttributeDateTime::GetAsUnixSeconds($value);
|
||||
$sDate = AttributeDateTime::GetFormat()->Format($value);
|
||||
$difference = $iValue - time();
|
||||
|
||||
if ($difference >= 0) {
|
||||
$sDifference = self::FormatDuration($difference);
|
||||
} else {
|
||||
$sDifference = Dict::Format('UI:DeadlineMissedBy_duration', self::FormatDuration(-$difference));
|
||||
}
|
||||
$sFormat = MetaModel::GetConfig()->Get('deadline_format');
|
||||
$sResult = str_replace(array('$date$', '$difference$'), array($sDate, $sDifference), $sFormat);
|
||||
}
|
||||
|
||||
return $sResult;
|
||||
}
|
||||
|
||||
static function FormatDuration($duration)
|
||||
{
|
||||
$days = floor($duration / 86400);
|
||||
$hours = floor(($duration - (86400 * $days)) / 3600);
|
||||
$minutes = floor(($duration - (86400 * $days + 3600 * $hours)) / 60);
|
||||
|
||||
if ($duration < 60) {
|
||||
// Less than 1 min
|
||||
$sResult = Dict::S('UI:Deadline_LessThan1Min');
|
||||
} else {
|
||||
if ($duration < 3600) {
|
||||
// less than 1 hour, display it in minutes
|
||||
$sResult = Dict::Format('UI:Deadline_Minutes', $minutes);
|
||||
} else {
|
||||
if ($duration < 86400) {
|
||||
// Less that 1 day, display it in hours/minutes
|
||||
$sResult = Dict::Format('UI:Deadline_Hours_Minutes', $hours, $minutes);
|
||||
} else {
|
||||
// Less that 1 day, display it in hours/minutes
|
||||
$sResult = Dict::Format('UI:Deadline_Days_Hours_Minutes', $days, $hours, $minutes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $sResult;
|
||||
}
|
||||
}
|
||||
157
sources/Core/AttributeDefinition/AttributeDecimal.php
Normal file
157
sources/Core/AttributeDefinition/AttributeDecimal.php
Normal file
@@ -0,0 +1,157 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Map a decimal value column (suitable for financial computations) to an attribute
|
||||
* internally in PHP such numbers are represented as string. Should you want to perform
|
||||
* a calculation on them, it is recommended to use the BC Math functions in order to
|
||||
* retain the precision
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
class AttributeDecimal extends AttributeDBField
|
||||
{
|
||||
const SEARCH_WIDGET_TYPE = self::SEARCH_WIDGET_TYPE_NUMERIC;
|
||||
|
||||
/**
|
||||
* Useless constructor, but if not present PHP 7.4.0/7.4.1 is crashing :( (N°2329)
|
||||
*
|
||||
* @see https://www.php.net/manual/fr/language.oop5.decon.php states that child constructor can be ommited
|
||||
* @see https://bugs.php.net/bug.php?id=79010 bug solved in PHP 7.4.9
|
||||
*
|
||||
* @param string $sCode
|
||||
* @param array $aParams
|
||||
*
|
||||
* @throws \Exception
|
||||
* @noinspection SenselessProxyMethodInspection
|
||||
*/
|
||||
public function __construct($sCode, $aParams)
|
||||
{
|
||||
parent::__construct($sCode, $aParams);
|
||||
}
|
||||
|
||||
public static function ListExpectedParams()
|
||||
{
|
||||
return array_merge(parent::ListExpectedParams(), array('digits', 'decimals' /* including precision */));
|
||||
}
|
||||
|
||||
public function GetEditClass()
|
||||
{
|
||||
return "String";
|
||||
}
|
||||
|
||||
protected function GetSQLCol($bFullSpec = false)
|
||||
{
|
||||
return "DECIMAL(" . $this->Get('digits') . "," . $this->Get('decimals') . ")" . ($bFullSpec ? $this->GetSQLColSpec() : '');
|
||||
}
|
||||
|
||||
public function GetValidationPattern()
|
||||
{
|
||||
$iNbDigits = $this->Get('digits');
|
||||
$iPrecision = $this->Get('decimals');
|
||||
$iNbIntegerDigits = $iNbDigits - $iPrecision;
|
||||
|
||||
return "^[\-\+]?\d{1,$iNbIntegerDigits}(\.\d{0,$iPrecision})?$";
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function CheckFormat($value)
|
||||
{
|
||||
$sRegExp = $this->GetValidationPattern();
|
||||
return preg_match("/$sRegExp/", $value);
|
||||
}
|
||||
|
||||
public function GetBasicFilterOperators()
|
||||
{
|
||||
return array(
|
||||
"!=" => "differs from",
|
||||
"=" => "equals",
|
||||
">" => "greater (strict) than",
|
||||
">=" => "greater than",
|
||||
"<" => "less (strict) than",
|
||||
"<=" => "less than",
|
||||
"in" => "in"
|
||||
);
|
||||
}
|
||||
|
||||
public function GetBasicFilterLooseOperator()
|
||||
{
|
||||
// Unless we implement an "equals approximately..." or "same order of magnitude"
|
||||
return "=";
|
||||
}
|
||||
|
||||
public function GetBasicFilterSQLExpr($sOpCode, $value)
|
||||
{
|
||||
$sQValue = CMDBSource::Quote($value);
|
||||
switch ($sOpCode) {
|
||||
case '!=':
|
||||
return $this->GetSQLExpr() . " != $sQValue";
|
||||
break;
|
||||
case '>':
|
||||
return $this->GetSQLExpr() . " > $sQValue";
|
||||
break;
|
||||
case '>=':
|
||||
return $this->GetSQLExpr() . " >= $sQValue";
|
||||
break;
|
||||
case '<':
|
||||
return $this->GetSQLExpr() . " < $sQValue";
|
||||
break;
|
||||
case '<=':
|
||||
return $this->GetSQLExpr() . " <= $sQValue";
|
||||
break;
|
||||
case 'in':
|
||||
if (!is_array($value)) {
|
||||
throw new CoreException("Expected an array for argument value (sOpCode='$sOpCode')");
|
||||
}
|
||||
|
||||
return $this->GetSQLExpr() . " IN ('" . implode("', '", $value) . "')";
|
||||
break;
|
||||
|
||||
case '=':
|
||||
default:
|
||||
return $this->GetSQLExpr() . " = \"$value\"";
|
||||
}
|
||||
}
|
||||
|
||||
public function GetNullValue()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function IsNull($proposedValue)
|
||||
{
|
||||
return is_null($proposedValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function HasAValue($proposedValue): bool
|
||||
{
|
||||
return utils::IsNotNullOrEmptyString($proposedValue);
|
||||
}
|
||||
|
||||
public function MakeRealValue($proposedValue, $oHostObj)
|
||||
{
|
||||
if (is_null($proposedValue)) {
|
||||
return null;
|
||||
}
|
||||
if ($proposedValue === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->ScalarToSQL($proposedValue);
|
||||
}
|
||||
|
||||
public function ScalarToSQL($value)
|
||||
{
|
||||
assert(is_null($value) || preg_match('/' . $this->GetValidationPattern() . '/', $value));
|
||||
|
||||
if (!is_null($value) && ($value !== '')) {
|
||||
$value = sprintf("%1." . $this->Get('decimals') . "F", $value);
|
||||
}
|
||||
return $value; // null or string
|
||||
}
|
||||
}
|
||||
1384
sources/Core/AttributeDefinition/AttributeDefinition.php
Normal file
1384
sources/Core/AttributeDefinition/AttributeDefinition.php
Normal file
File diff suppressed because it is too large
Load Diff
130
sources/Core/AttributeDefinition/AttributeDuration.php
Normal file
130
sources/Core/AttributeDefinition/AttributeDuration.php
Normal file
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Store a duration as a number of seconds
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
class AttributeDuration extends AttributeInteger
|
||||
{
|
||||
/**
|
||||
* Useless constructor, but if not present PHP 7.4.0/7.4.1 is crashing :( (N°2329)
|
||||
*
|
||||
* @see https://www.php.net/manual/fr/language.oop5.decon.php states that child constructor can be ommited
|
||||
* @see https://bugs.php.net/bug.php?id=79010 bug solved in PHP 7.4.9
|
||||
*
|
||||
* @param string $sCode
|
||||
* @param array $aParams
|
||||
*
|
||||
* @throws \Exception
|
||||
* @noinspection SenselessProxyMethodInspection
|
||||
*/
|
||||
public function __construct($sCode, $aParams)
|
||||
{
|
||||
parent::__construct($sCode, $aParams);
|
||||
}
|
||||
|
||||
public function GetEditClass()
|
||||
{
|
||||
return "Duration";
|
||||
}
|
||||
|
||||
protected function GetSQLCol($bFullSpec = false)
|
||||
{
|
||||
return "INT(11) UNSIGNED";
|
||||
}
|
||||
|
||||
public function GetNullValue()
|
||||
{
|
||||
return '0';
|
||||
}
|
||||
|
||||
public function MakeRealValue($proposedValue, $oHostObj)
|
||||
{
|
||||
if (is_null($proposedValue)) {
|
||||
return null;
|
||||
}
|
||||
if (!is_numeric($proposedValue)) {
|
||||
return null;
|
||||
}
|
||||
if (((int)$proposedValue) < 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (int)$proposedValue;
|
||||
}
|
||||
|
||||
public function ScalarToSQL($value)
|
||||
{
|
||||
if (is_null($value)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function GetAsHTML($value, $oHostObject = null, $bLocalize = true)
|
||||
{
|
||||
return Str::pure2html(self::FormatDuration($value));
|
||||
}
|
||||
|
||||
public static function FormatDuration($duration)
|
||||
{
|
||||
$aDuration = self::SplitDuration($duration);
|
||||
|
||||
if ($duration < 60) {
|
||||
// Less than 1 min
|
||||
$sResult = Dict::Format('Core:Duration_Seconds', $aDuration['seconds']);
|
||||
} else {
|
||||
if ($duration < 3600) {
|
||||
// less than 1 hour, display it in minutes/seconds
|
||||
$sResult = Dict::Format('Core:Duration_Minutes_Seconds', $aDuration['minutes'], $aDuration['seconds']);
|
||||
} else {
|
||||
if ($duration < 86400) {
|
||||
// Less than 1 day, display it in hours/minutes/seconds
|
||||
$sResult = Dict::Format('Core:Duration_Hours_Minutes_Seconds', $aDuration['hours'],
|
||||
$aDuration['minutes'], $aDuration['seconds']);
|
||||
} else {
|
||||
// more than 1 day, display it in days/hours/minutes/seconds
|
||||
$sResult = Dict::Format('Core:Duration_Days_Hours_Minutes_Seconds', $aDuration['days'],
|
||||
$aDuration['hours'], $aDuration['minutes'], $aDuration['seconds']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $sResult;
|
||||
}
|
||||
|
||||
static function SplitDuration($duration)
|
||||
{
|
||||
$duration = (int)$duration;
|
||||
$days = floor($duration / 86400);
|
||||
$hours = floor(($duration - (86400 * $days)) / 3600);
|
||||
$minutes = floor(($duration - (86400 * $days + 3600 * $hours)) / 60);
|
||||
$seconds = ($duration % 60); // modulo
|
||||
|
||||
return array('days' => $days, 'hours' => $hours, 'minutes' => $minutes, 'seconds' => $seconds);
|
||||
}
|
||||
|
||||
public static function GetFormFieldClass()
|
||||
{
|
||||
return '\\Combodo\\iTop\\Form\\Field\\DurationField';
|
||||
}
|
||||
|
||||
public function MakeFormField(DBObject $oObject, $oFormField = null)
|
||||
{
|
||||
if ($oFormField === null) {
|
||||
$sFormFieldClass = static::GetFormFieldClass();
|
||||
$oFormField = new $sFormFieldClass($this->GetCode());
|
||||
}
|
||||
parent::MakeFormField($oObject, $oFormField);
|
||||
|
||||
// Note : As of today, this attribute is -by nature- only supported in readonly mode, not edition
|
||||
$sAttCode = $this->GetCode();
|
||||
$oFormField->SetCurrentValue($oObject->Get($sAttCode));
|
||||
$oFormField->SetReadOnly(true);
|
||||
|
||||
return $oFormField;
|
||||
}
|
||||
|
||||
}
|
||||
47
sources/Core/AttributeDefinition/AttributeEmailAddress.php
Normal file
47
sources/Core/AttributeDefinition/AttributeEmailAddress.php
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Specialization of a string: email
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
class AttributeEmailAddress extends AttributeString
|
||||
{
|
||||
/**
|
||||
* Useless constructor, but if not present PHP 7.4.0/7.4.1 is crashing :( (N°2329)
|
||||
*
|
||||
* @see https://www.php.net/manual/fr/language.oop5.decon.php states that child constructor can be ommited
|
||||
* @see https://bugs.php.net/bug.php?id=79010 bug solved in PHP 7.4.9
|
||||
*
|
||||
* @param string $sCode
|
||||
* @param array $aParams
|
||||
*
|
||||
* @throws \Exception
|
||||
* @noinspection SenselessProxyMethodInspection
|
||||
*/
|
||||
public function __construct($sCode, $aParams)
|
||||
{
|
||||
parent::__construct($sCode, $aParams);
|
||||
}
|
||||
|
||||
public function GetValidationPattern()
|
||||
{
|
||||
return $this->GetOptional('validation_pattern', '^' . utils::GetConfig()->Get('email_validation_pattern') . '$');
|
||||
}
|
||||
|
||||
public static function GetFormFieldClass()
|
||||
{
|
||||
return '\\Combodo\\iTop\\Form\\Field\\EmailField';
|
||||
}
|
||||
|
||||
public function GetAsHTML($sValue, $oHostObject = null, $bLocalize = true)
|
||||
{
|
||||
if (empty($sValue)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$sUrlDecorationClass = utils::GetConfig()->Get('email_decoration_class');
|
||||
|
||||
return '<a class="mailto" href="mailto:' . $sValue . '"><span class="text_decoration ' . $sUrlDecorationClass . '"></span>' . parent::GetAsHTML($sValue) . '</a>';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Map a text column (size < 255) to an attribute that is encrypted in the database
|
||||
* The encryption is based on a key set per iTop instance. Thus if you export your
|
||||
* database (in SQL) to someone else without providing the key at the same time
|
||||
* the encrypted fields will remain encrypted
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
class AttributeEncryptedString extends AttributeString implements iAttributeNoGroupBy
|
||||
{
|
||||
const SEARCH_WIDGET_TYPE = self::SEARCH_WIDGET_TYPE_RAW;
|
||||
|
||||
protected function GetSQLCol($bFullSpec = false)
|
||||
{
|
||||
return "TINYBLOB";
|
||||
}
|
||||
|
||||
public function GetMaxSize()
|
||||
{
|
||||
return 255;
|
||||
}
|
||||
|
||||
public function MakeRealValue($proposedValue, $oHostObj)
|
||||
{
|
||||
if (is_null($proposedValue)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (string)$proposedValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypt the value when reading from the database
|
||||
*
|
||||
* @param array $aCols
|
||||
* @param string $sPrefix
|
||||
*
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function FromSQLToValue($aCols, $sPrefix = '')
|
||||
{
|
||||
$oSimpleCrypt = new SimpleCrypt(MetaModel::GetConfig()->GetEncryptionLibrary());
|
||||
$sValue = $oSimpleCrypt->Decrypt(MetaModel::GetConfig()->GetEncryptionKey(), $aCols[$sPrefix]);
|
||||
|
||||
return $sValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypt the value before storing it in the database
|
||||
*
|
||||
* @param $value
|
||||
*
|
||||
* @return array
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function GetSQLValues($value)
|
||||
{
|
||||
$oSimpleCrypt = new SimpleCrypt(MetaModel::GetConfig()->GetEncryptionLibrary());
|
||||
$encryptedValue = $oSimpleCrypt->Encrypt(MetaModel::GetConfig()->GetEncryptionKey(), $value);
|
||||
|
||||
$aValues = array();
|
||||
$aValues[$this->Get("sql")] = $encryptedValue;
|
||||
|
||||
return $aValues;
|
||||
}
|
||||
|
||||
protected function GetChangeRecordAdditionalData(CMDBChangeOp $oMyChangeOp, DBObject $oObject, $original, $value): void
|
||||
{
|
||||
if (is_null($original)) {
|
||||
$original = '';
|
||||
}
|
||||
$oMyChangeOp->Set("prevstring", $original);
|
||||
}
|
||||
|
||||
protected function GetChangeRecordClassName(): string
|
||||
{
|
||||
return CMDBChangeOpSetAttributeEncrypted::class;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
399
sources/Core/AttributeDefinition/AttributeEnum.php
Normal file
399
sources/Core/AttributeDefinition/AttributeEnum.php
Normal file
@@ -0,0 +1,399 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Map a enum column to an attribute
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
class AttributeEnum extends AttributeString
|
||||
{
|
||||
const SEARCH_WIDGET_TYPE = self::SEARCH_WIDGET_TYPE_ENUM;
|
||||
|
||||
/**
|
||||
* Useless constructor, but if not present PHP 7.4.0/7.4.1 is crashing :( (N°2329)
|
||||
*
|
||||
* @see https://www.php.net/manual/fr/language.oop5.decon.php states that child constructor can be ommited
|
||||
* @see https://bugs.php.net/bug.php?id=79010 bug solved in PHP 7.4.9
|
||||
*
|
||||
* @param string $sCode
|
||||
* @param array $aParams
|
||||
*
|
||||
* @throws \Exception
|
||||
* @noinspection SenselessProxyMethodInspection
|
||||
*/
|
||||
public function __construct($sCode, $aParams)
|
||||
{
|
||||
parent::__construct($sCode, $aParams);
|
||||
}
|
||||
|
||||
public static function ListExpectedParams()
|
||||
{
|
||||
return parent::ListExpectedParams();
|
||||
//return array_merge(parent::ListExpectedParams(), array('styled_values'));
|
||||
}
|
||||
|
||||
public function GetEditClass()
|
||||
{
|
||||
return "String";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|null $sValue
|
||||
*
|
||||
* @return \ormStyle|null
|
||||
*/
|
||||
public function GetStyle(?string $sValue): ?ormStyle
|
||||
{
|
||||
if ($this->IsParam('styled_values')) {
|
||||
$aStyles = $this->Get('styled_values');
|
||||
if (array_key_exists($sValue, $aStyles)) {
|
||||
return $aStyles[$sValue];
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->IsParam('default_style')) {
|
||||
return $this->Get('default_style');
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function GetSQLCol($bFullSpec = false)
|
||||
{
|
||||
// Get the definition of the column, including the actual values present in the table
|
||||
return $this->GetSQLColHelper($bFullSpec, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* A more versatile version of GetSQLCol
|
||||
* @param bool $bFullSpec
|
||||
* @param bool $bIncludeActualValues
|
||||
* @param string $sSQLTableName The table where to look for the actual values (may be useful for data synchro tables)
|
||||
* @return string
|
||||
* @since 3.0.0
|
||||
*/
|
||||
protected function GetSQLColHelper($bFullSpec = false, $bIncludeActualValues = false, $sSQLTableName = null)
|
||||
{
|
||||
$oValDef = $this->GetValuesDef();
|
||||
if ($oValDef) {
|
||||
$aValues = CMDBSource::Quote(array_keys($oValDef->GetValues(array(), "")), true);
|
||||
} else {
|
||||
$aValues = array();
|
||||
}
|
||||
|
||||
// Preserve the values already present in the database to ease migrations
|
||||
if ($bIncludeActualValues) {
|
||||
if ($sSQLTableName == null) {
|
||||
// No SQL table given, use the one of the attribute
|
||||
$sHostClass = $this->GetHostClass();
|
||||
$sSQLTableName = MetaModel::DBGetTable($sHostClass, $this->GetCode());
|
||||
}
|
||||
$aValues = array_unique(array_merge($aValues, $this->GetActualValuesInDB($sSQLTableName)));
|
||||
}
|
||||
|
||||
if (count($aValues) > 0) {
|
||||
// The syntax used here do matters
|
||||
// In particular, I had to remove unnecessary spaces to
|
||||
// make sure that this string will match the field type returned by the DB
|
||||
// (used to perform a comparison between the current DB format and the data model)
|
||||
return "ENUM(" . implode(",", $aValues) . ")"
|
||||
. CMDBSource::GetSqlStringColumnDefinition()
|
||||
. ($bFullSpec ? $this->GetSQLColSpec() : '');
|
||||
} else {
|
||||
return "VARCHAR(255)"
|
||||
. CMDBSource::GetSqlStringColumnDefinition()
|
||||
. ($bFullSpec ? " DEFAULT ''" : ""); // ENUM() is not an allowed syntax!
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 3.0.0
|
||||
* {@inheritDoc}
|
||||
* @see AttributeDefinition::GetImportColumns()
|
||||
*/
|
||||
public function GetImportColumns()
|
||||
{
|
||||
// Note: this is used by the Data Synchro to build the "data" table
|
||||
// Right now the function is not passed the "target" SQL table, but if we improve this in the future
|
||||
// we may call $this->GetSQLColHelper(true, true, $sDBTable); to take into account the actual 'enum' values
|
||||
// in this table
|
||||
return array($this->GetCode() => $this->GetSQLColHelper(false, false));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of the actual 'enum' values present in the database
|
||||
* @return string[]
|
||||
* @since 3.0.0
|
||||
*/
|
||||
protected function GetActualValuesInDB(string $sDBTable)
|
||||
{
|
||||
$aValues = array();
|
||||
try {
|
||||
$sSQL = "SELECT DISTINCT `" . $this->GetSQLExpr() . "` AS value FROM `$sDBTable`;";
|
||||
$aValuesInDB = CMDBSource::QueryToArray($sSQL);
|
||||
foreach ($aValuesInDB as $aRow) {
|
||||
if ($aRow['value'] !== null) {
|
||||
$aValues[] = $aRow['value'];
|
||||
}
|
||||
}
|
||||
} catch (MySQLException $e) {
|
||||
// Never mind, maybe the table does not exist yet (new installation from scratch)
|
||||
// It seems more efficient to try and ignore errors than to test if the table & column really exists
|
||||
}
|
||||
return CMDBSource::Quote($aValues);
|
||||
}
|
||||
|
||||
protected function GetSQLColSpec()
|
||||
{
|
||||
$default = $this->ScalarToSQL($this->GetDefaultValue());
|
||||
if (is_null($default)) {
|
||||
$sRet = '';
|
||||
} else {
|
||||
// ENUMs values are strings so the default value must be a string as well,
|
||||
// otherwise MySQL interprets the number as the zero-based index of the value in the list (i.e. the nth value in the list)
|
||||
$sRet = " DEFAULT " . CMDBSource::Quote($default);
|
||||
}
|
||||
|
||||
return $sRet;
|
||||
}
|
||||
|
||||
public function ScalarToSQL($value)
|
||||
{
|
||||
// Note: for strings, the null value is an empty string and it is recorded as such in the DB
|
||||
// but that wasn't working for enums, because '' is NOT one of the allowed values
|
||||
// that's why a null value must be forced to a real null
|
||||
$value = parent::ScalarToSQL($value);
|
||||
if ($this->IsNull($value)) {
|
||||
return null;
|
||||
} else {
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
public function RequiresIndex()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function GetBasicFilterOperators()
|
||||
{
|
||||
return parent::GetBasicFilterOperators();
|
||||
}
|
||||
|
||||
public function GetBasicFilterLooseOperator()
|
||||
{
|
||||
return '=';
|
||||
}
|
||||
|
||||
public function GetBasicFilterSQLExpr($sOpCode, $value)
|
||||
{
|
||||
return parent::GetBasicFilterSQLExpr($sOpCode, $value);
|
||||
}
|
||||
|
||||
public function GetValueLabel($sValue)
|
||||
{
|
||||
if (is_null($sValue)) {
|
||||
// Unless a specific label is defined for the null value of this enum, use a generic "undefined" label
|
||||
$sLabel = Dict::S('Class:' . $this->GetHostClass() . '/Attribute:' . $this->GetCode() . '/Value:' . $sValue,
|
||||
Dict::S('Enum:Undefined'));
|
||||
} else {
|
||||
$sLabel = $this->SearchLabel('/Attribute:' . $this->m_sCode . '/Value:' . $sValue, null, true /*user lang*/);
|
||||
if (is_null($sLabel)) {
|
||||
$sDefault = str_replace('_', ' ', $sValue);
|
||||
// Browse the hierarchy again, accepting default (english) translations
|
||||
$sLabel = $this->SearchLabel('/Attribute:' . $this->m_sCode . '/Value:' . $sValue, $sDefault, false);
|
||||
}
|
||||
}
|
||||
|
||||
return $sLabel;
|
||||
}
|
||||
|
||||
public function GetValueDescription($sValue)
|
||||
{
|
||||
if (is_null($sValue)) {
|
||||
// Unless a specific label is defined for the null value of this enum, use a generic "undefined" label
|
||||
$sDescription = Dict::S('Class:' . $this->GetHostClass() . '/Attribute:' . $this->GetCode() . '/Value:' . $sValue . '+',
|
||||
Dict::S('Enum:Undefined'));
|
||||
} else {
|
||||
$sDescription = Dict::S('Class:' . $this->GetHostClass() . '/Attribute:' . $this->GetCode() . '/Value:' . $sValue . '+',
|
||||
'', true /* user language only */);
|
||||
if (strlen($sDescription) == 0) {
|
||||
$sParentClass = MetaModel::GetParentClass($this->m_sHostClass);
|
||||
if ($sParentClass) {
|
||||
if (MetaModel::IsValidAttCode($sParentClass, $this->m_sCode)) {
|
||||
$oAttDef = MetaModel::GetAttributeDef($sParentClass, $this->m_sCode);
|
||||
$sDescription = $oAttDef->GetValueDescription($sValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $sDescription;
|
||||
}
|
||||
|
||||
public function GetAsHTML($sValue, $oHostObject = null, $bLocalize = true)
|
||||
{
|
||||
if ($bLocalize) {
|
||||
$sLabel = $this->GetValueLabel($sValue);
|
||||
// $sDescription = $this->GetValueDescription($sValue);
|
||||
$oStyle = $this->GetStyle($sValue);
|
||||
// later, we could imagine a detailed description in the title
|
||||
// $sRes = "<span title=\"$sDescription\">".parent::GetAsHtml($sLabel)."</span>";
|
||||
$oBadge = \Combodo\iTop\Application\UI\Base\Component\FieldBadge\FieldBadgeUIBlockFactory::MakeForField($sLabel, $oStyle);
|
||||
$oRenderer = new \Combodo\iTop\Renderer\BlockRenderer($oBadge);
|
||||
$sRes = $oRenderer->RenderHtml();
|
||||
} else {
|
||||
$sRes = parent::GetAsHtml($sValue, $oHostObject, $bLocalize);
|
||||
}
|
||||
|
||||
return $sRes;
|
||||
}
|
||||
|
||||
public function GetAsXML($value, $oHostObject = null, $bLocalize = true)
|
||||
{
|
||||
if (is_null($value)) {
|
||||
$sFinalValue = '';
|
||||
} elseif ($bLocalize) {
|
||||
$sFinalValue = $this->GetValueLabel($value);
|
||||
} else {
|
||||
$sFinalValue = $value;
|
||||
}
|
||||
$sRes = parent::GetAsXML($sFinalValue, $oHostObject, $bLocalize);
|
||||
|
||||
return $sRes;
|
||||
}
|
||||
|
||||
public function GetAsCSV(
|
||||
$sValue, $sSeparator = ',', $sTextQualifier = '"', $oHostObject = null, $bLocalize = true,
|
||||
$bConvertToPlainText = false
|
||||
)
|
||||
{
|
||||
if (is_null($sValue)) {
|
||||
$sFinalValue = '';
|
||||
} elseif ($bLocalize) {
|
||||
$sFinalValue = $this->GetValueLabel($sValue);
|
||||
} else {
|
||||
$sFinalValue = $sValue;
|
||||
}
|
||||
$sRes = parent::GetAsCSV($sFinalValue, $sSeparator, $sTextQualifier, $oHostObject, $bLocalize);
|
||||
|
||||
return $sRes;
|
||||
}
|
||||
|
||||
public static function GetFormFieldClass()
|
||||
{
|
||||
return '\\Combodo\\iTop\\Form\\Field\\SelectField';
|
||||
}
|
||||
|
||||
public function MakeFormField(DBObject $oObject, $oFormField = null)
|
||||
{
|
||||
if ($oFormField === null) {
|
||||
// Later : We should check $this->Get('display_style') and create a Radio / Select / ... regarding its value
|
||||
$sFormFieldClass = static::GetFormFieldClass();
|
||||
$oFormField = new $sFormFieldClass($this->GetCode());
|
||||
}
|
||||
|
||||
$oFormField->SetChoices($this->GetAllowedValues($oObject->ToArgsForQuery()));
|
||||
parent::MakeFormField($oObject, $oFormField);
|
||||
|
||||
return $oFormField;
|
||||
}
|
||||
|
||||
public function GetEditValue($sValue, $oHostObj = null)
|
||||
{
|
||||
if (is_null($sValue)) {
|
||||
return '';
|
||||
} else {
|
||||
return $this->GetValueLabel($sValue);
|
||||
}
|
||||
}
|
||||
|
||||
public function GetForJSON($value)
|
||||
{
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function GetAllowedValues($aArgs = array(), $sContains = '')
|
||||
{
|
||||
$aRawValues = parent::GetAllowedValues($aArgs, $sContains);
|
||||
if (is_null($aRawValues)) {
|
||||
return null;
|
||||
}
|
||||
$aLocalizedValues = array();
|
||||
foreach ($aRawValues as $sKey => $sValue) {
|
||||
$aLocalizedValues[$sKey] = $this->GetValueLabel($sKey);
|
||||
}
|
||||
|
||||
// Sort by label only if necessary
|
||||
// See N°1646 and {@see \MFCompiler::CompileAttributeEnumValues()} for complete information as for why sort on labels is done at runtime while other sorting are done at compile time
|
||||
/** @var \ValueSetEnum $oValueSetDef */
|
||||
$oValueSetDef = $this->GetValuesDef();
|
||||
if ($oValueSetDef->IsSortedByValues()) {
|
||||
asort($aLocalizedValues);
|
||||
}
|
||||
|
||||
return $aLocalizedValues;
|
||||
}
|
||||
|
||||
public function GetMaxSize()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* An enum can be localized
|
||||
*/
|
||||
public function MakeValueFromString(
|
||||
$sProposedValue, $bLocalizedValue = false, $sSepItem = null, $sSepAttribute = null, $sSepValue = null,
|
||||
$sAttributeQualifier = null
|
||||
)
|
||||
{
|
||||
if ($bLocalizedValue) {
|
||||
// Lookup for the value matching the input
|
||||
//
|
||||
$sFoundValue = null;
|
||||
$aRawValues = parent::GetAllowedValues();
|
||||
if (!is_null($aRawValues)) {
|
||||
foreach ($aRawValues as $sKey => $sValue) {
|
||||
$sRefValue = $this->GetValueLabel($sKey);
|
||||
if ($sProposedValue == $sRefValue) {
|
||||
$sFoundValue = $sKey;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (is_null($sFoundValue)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->MakeRealValue($sFoundValue, null);
|
||||
} else {
|
||||
return parent::MakeValueFromString($sProposedValue, $bLocalizedValue, $sSepItem, $sSepAttribute, $sSepValue,
|
||||
$sAttributeQualifier);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the input value to align it with the values supported
|
||||
* by this type of attribute. In this case: turns empty strings into nulls
|
||||
*
|
||||
* @param mixed $proposedValue The value to be set for the attribute
|
||||
*
|
||||
* @return mixed The actual value that will be set
|
||||
*/
|
||||
public function MakeRealValue($proposedValue, $oHostObj)
|
||||
{
|
||||
if ($proposedValue == '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
return parent::MakeRealValue($proposedValue, $oHostObj);
|
||||
}
|
||||
|
||||
public function GetOrderByHint()
|
||||
{
|
||||
$aValues = $this->GetAllowedValues();
|
||||
|
||||
return Dict::Format('UI:OrderByHint_Values', implode(', ', $aValues));
|
||||
}
|
||||
}
|
||||
230
sources/Core/AttributeDefinition/AttributeEnumSet.php
Normal file
230
sources/Core/AttributeDefinition/AttributeEnumSet.php
Normal file
@@ -0,0 +1,230 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @since 2.7.0 N°985
|
||||
*/
|
||||
class AttributeEnumSet extends AttributeSet
|
||||
{
|
||||
const SEARCH_WIDGET_TYPE = self::SEARCH_WIDGET_TYPE_TAG_SET;
|
||||
|
||||
public static function ListExpectedParams()
|
||||
{
|
||||
return array_merge(parent::ListExpectedParams(), array('possible_values', 'is_null_allowed', 'max_items'));
|
||||
}
|
||||
|
||||
public function GetMaxSize()
|
||||
{
|
||||
$aRawValues = $this->GetRawPossibleValues();
|
||||
$iMaxItems = $this->GetMaxItems();
|
||||
$aLengths = array();
|
||||
foreach (array_keys($aRawValues) as $sKey) {
|
||||
$aLengths[] = strlen($sKey);
|
||||
}
|
||||
rsort($aLengths, SORT_NUMERIC);
|
||||
$iMaxSize = 2;
|
||||
for ($i = 0; $i < min($iMaxItems, count($aLengths)); $i++) {
|
||||
$iMaxSize += $aLengths[$i] + 1;
|
||||
}
|
||||
return max(255, $iMaxSize);
|
||||
}
|
||||
|
||||
private function GetRawPossibleValues($aArgs = array(), $sContains = '')
|
||||
{
|
||||
/** @var ValueSetEnumPadded $oValSetDef */
|
||||
$oValSetDef = $this->Get('possible_values');
|
||||
if (!$oValSetDef) {
|
||||
return array();
|
||||
}
|
||||
|
||||
return $oValSetDef->GetValues($aArgs, $sContains);
|
||||
}
|
||||
|
||||
public function GetPossibleValues($aArgs = array(), $sContains = '')
|
||||
{
|
||||
$aRawValues = $this->GetRawPossibleValues($aArgs, $sContains);
|
||||
$aLocalizedValues = array();
|
||||
foreach ($aRawValues as $sKey => $sValue) {
|
||||
$aLocalizedValues[$sKey] = $this->GetValueLabel($sKey);
|
||||
}
|
||||
|
||||
return $aLocalizedValues;
|
||||
}
|
||||
|
||||
public function GetValueLabel($sValue)
|
||||
{
|
||||
if ($sValue instanceof ormSet) {
|
||||
$sValue = implode(', ', $sValue->GetValues());
|
||||
}
|
||||
|
||||
$aValues = $this->GetRawPossibleValues();
|
||||
if (is_array($aValues) && is_string($sValue) && isset($aValues[$sValue])) {
|
||||
$sValue = $aValues[$sValue];
|
||||
}
|
||||
|
||||
if (is_null($sValue)) {
|
||||
// Unless a specific label is defined for the null value of this enum, use a generic "undefined" label
|
||||
$sLabel = Dict::S('Class:' . $this->GetHostClass() . '/Attribute:' . $this->GetCode() . '/Value:' . $sValue,
|
||||
Dict::S('Enum:Undefined'));
|
||||
} else {
|
||||
$sLabel = $this->SearchLabel('/Attribute:' . $this->m_sCode . '/Value:' . $sValue, null, true /*user lang*/);
|
||||
if (is_null($sLabel)) {
|
||||
// Browse the hierarchy again, accepting default (english) translations
|
||||
$sLabel = $this->SearchLabel('/Attribute:' . $this->m_sCode . '/Value:' . $sValue, null, false);
|
||||
if (is_null($sLabel)) {
|
||||
$sDefault = trim(str_replace('_', ' ', $sValue));
|
||||
// Browse the hierarchy again, accepting default (english) translations
|
||||
$sLabel = $this->SearchLabel('/Attribute:' . $this->m_sCode . '/Value:' . $sDefault, $sDefault, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $sLabel;
|
||||
}
|
||||
|
||||
public function GetValueDescription($sValue)
|
||||
{
|
||||
if (is_null($sValue)) {
|
||||
// Unless a specific label is defined for the null value of this enum, use a generic "undefined" label
|
||||
$sDescription = Dict::S('Class:' . $this->GetHostClass() . '/Attribute:' . $this->GetCode() . '/Value:' . $sValue . '+',
|
||||
Dict::S('Enum:Undefined'));
|
||||
} else {
|
||||
$sDescription = Dict::S('Class:' . $this->GetHostClass() . '/Attribute:' . $this->GetCode() . '/Value:' . $sValue . '+',
|
||||
'', true /* user language only */);
|
||||
if (strlen($sDescription) == 0) {
|
||||
$sParentClass = MetaModel::GetParentClass($this->m_sHostClass);
|
||||
if ($sParentClass) {
|
||||
if (MetaModel::IsValidAttCode($sParentClass, $this->m_sCode)) {
|
||||
$oAttDef = MetaModel::GetAttributeDef($sParentClass, $this->m_sCode);
|
||||
$sDescription = $oAttDef->GetValueDescription($sValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $sDescription;
|
||||
}
|
||||
|
||||
public function GetAsHTML($value, $oHostObject = null, $bLocalize = true)
|
||||
{
|
||||
if ($bLocalize) {
|
||||
if ($value instanceof ormSet) {
|
||||
$sRes = $this->GenerateViewHtmlForValues($value->GetValues());
|
||||
} else {
|
||||
$sLabel = $this->GetValueLabel($value);
|
||||
$sDescription = $this->GetValueDescription($value);
|
||||
$sRes = "<span title=\"$sDescription\">" . parent::GetAsHtml($sLabel) . "</span>";
|
||||
}
|
||||
} else {
|
||||
$sRes = parent::GetAsHtml($value, $oHostObject, $bLocalize);
|
||||
}
|
||||
|
||||
return $sRes;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param ormSet $value
|
||||
* @param string $sSeparator
|
||||
* @param string $sTextQualifier
|
||||
* @param \DBObject $oHostObject
|
||||
* @param bool $bLocalize
|
||||
* @param bool $bConvertToPlainText
|
||||
*
|
||||
* @return mixed|string
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function GetAsCSV($value, $sSeparator = ',', $sTextQualifier = '"', $oHostObject = null, $bLocalize = true, $bConvertToPlainText = false)
|
||||
{
|
||||
$sSepItem = MetaModel::GetConfig()->Get('tag_set_item_separator');
|
||||
if (is_object($value) && ($value instanceof ormSet)) {
|
||||
$aValues = $value->GetValues();
|
||||
if ($bLocalize) {
|
||||
$aLocalizedValues = array();
|
||||
foreach ($aValues as $sValue) {
|
||||
$aLocalizedValues[] = $this->GetValueLabel($sValue);
|
||||
}
|
||||
$aValues = $aLocalizedValues;
|
||||
}
|
||||
$sRes = implode($sSepItem, $aValues);
|
||||
} else {
|
||||
$sRes = '';
|
||||
}
|
||||
|
||||
return "{$sTextQualifier}{$sRes}{$sTextQualifier}";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value from a given string (plain text, CSV import)
|
||||
*
|
||||
* @param string $sProposedValue
|
||||
* @param bool $bLocalizedValue
|
||||
* @param string $sSepItem
|
||||
* @param string $sSepAttribute
|
||||
* @param string $sSepValue
|
||||
* @param string $sAttributeQualifier
|
||||
*
|
||||
* @return mixed null if no match could be found
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function MakeValueFromString($sProposedValue, $bLocalizedValue = false, $sSepItem = null, $sSepAttribute = null, $sSepValue = null, $sAttributeQualifier = null)
|
||||
{
|
||||
if ($bLocalizedValue) {
|
||||
// Lookup for the values matching the input
|
||||
//
|
||||
$aValues = $this->FromStringToArray($sProposedValue);
|
||||
$aFoundValues = array();
|
||||
$aRawValues = $this->GetPossibleValues();
|
||||
foreach ($aValues as $sValue) {
|
||||
$bFound = false;
|
||||
foreach ($aRawValues as $sCode => $sRawValue) {
|
||||
if ($sValue == $sRawValue) {
|
||||
$aFoundValues[] = $sCode;
|
||||
$bFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$bFound) {
|
||||
// Not found, break the import
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->MakeRealValue(implode(',', $aFoundValues), null);
|
||||
} else {
|
||||
return $this->MakeRealValue($sProposedValue, null, false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $proposedValue Search string used for MATCHES
|
||||
*
|
||||
* @param string $sDefaultSepItem word separator to extract items
|
||||
*
|
||||
* @return array of EnumSet codes
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function FromStringToArray($proposedValue, $sDefaultSepItem = ',')
|
||||
{
|
||||
$aValues = array();
|
||||
if (!empty($proposedValue)) {
|
||||
$sSepItem = MetaModel::GetConfig()->Get('tag_set_item_separator');
|
||||
// convert also other separators
|
||||
if ($sSepItem !== $sDefaultSepItem) {
|
||||
$proposedValue = str_replace($sDefaultSepItem, $sSepItem, $proposedValue);
|
||||
}
|
||||
foreach (explode($sSepItem, $proposedValue) as $sCode) {
|
||||
$sValue = trim($sCode);
|
||||
if (strlen($sValue) > 2) {
|
||||
$sLabel = $this->GetValueLabel($sValue);
|
||||
$aValues[$sLabel] = $sValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $aValues;
|
||||
}
|
||||
|
||||
public function Equals($val1, $val2)
|
||||
{
|
||||
return $val1->Equals($val2);
|
||||
}
|
||||
}
|
||||
511
sources/Core/AttributeDefinition/AttributeExternalField.php
Normal file
511
sources/Core/AttributeDefinition/AttributeExternalField.php
Normal file
@@ -0,0 +1,511 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* An attribute which corresponds to an external key (direct or indirect)
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
class AttributeExternalField extends AttributeDefinition
|
||||
{
|
||||
/**
|
||||
* Useless constructor, but if not present PHP 7.4.0/7.4.1 is crashing :( (N°2329)
|
||||
*
|
||||
* @see https://www.php.net/manual/fr/language.oop5.decon.php states that child constructor can be ommited
|
||||
* @see https://bugs.php.net/bug.php?id=79010 bug solved in PHP 7.4.9
|
||||
*
|
||||
* @param string $sCode
|
||||
* @param array $aParams
|
||||
*
|
||||
* @throws \Exception
|
||||
* @noinspection SenselessProxyMethodInspection
|
||||
*/
|
||||
public function __construct($sCode, $aParams)
|
||||
{
|
||||
parent::__construct($sCode, $aParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the search widget type corresponding to this attribute
|
||||
*
|
||||
* @return string
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public function GetSearchType()
|
||||
{
|
||||
// Not necessary the external key is already present
|
||||
if ($this->IsFriendlyName()) {
|
||||
return self::SEARCH_WIDGET_TYPE_RAW;
|
||||
}
|
||||
|
||||
try {
|
||||
$oRemoteAtt = $this->GetFinalAttDef();
|
||||
switch (true) {
|
||||
case ($oRemoteAtt instanceof AttributeString):
|
||||
return self::SEARCH_WIDGET_TYPE_EXTERNAL_FIELD;
|
||||
case ($oRemoteAtt instanceof AttributeExternalKey):
|
||||
return self::SEARCH_WIDGET_TYPE_EXTERNAL_KEY;
|
||||
}
|
||||
} catch (CoreException $e) {
|
||||
}
|
||||
|
||||
return self::SEARCH_WIDGET_TYPE_RAW;
|
||||
}
|
||||
|
||||
function IsSearchable()
|
||||
{
|
||||
if ($this->IsFriendlyName()) {
|
||||
return true;
|
||||
}
|
||||
return parent::IsSearchable();
|
||||
}
|
||||
|
||||
public static function ListExpectedParams()
|
||||
{
|
||||
return array_merge(parent::ListExpectedParams(), array("extkey_attcode", "target_attcode"));
|
||||
}
|
||||
|
||||
public function GetEditClass()
|
||||
{
|
||||
return "ExtField";
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \AttributeDefinition
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public function GetFinalAttDef()
|
||||
{
|
||||
$oExtAttDef = $this->GetExtAttDef();
|
||||
|
||||
return $oExtAttDef->GetFinalAttDef();
|
||||
}
|
||||
|
||||
protected function GetSQLCol($bFullSpec = false)
|
||||
{
|
||||
// throw new CoreException("external attribute: does it make any sense to request its type ?");
|
||||
$oExtAttDef = $this->GetExtAttDef();
|
||||
|
||||
return $oExtAttDef->GetSQLCol($bFullSpec);
|
||||
}
|
||||
|
||||
public function GetSQLExpressions($sPrefix = '')
|
||||
{
|
||||
if ($sPrefix == '') {
|
||||
return array('' => $this->GetCode()); // Warning: Use GetCode() since AttributeExternalField does not have any 'sql' property
|
||||
} else {
|
||||
return $sPrefix;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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->Get("target_attcode") === "friendlyname")) {
|
||||
// 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;
|
||||
}
|
||||
|
||||
$oRemoteAtt = $this->GetExtAttDef();
|
||||
$sLabel = $oRemoteAtt->GetLabel($this->m_sCode);
|
||||
$oKeyAtt = $this->GetKeyAttDef();
|
||||
$sKeyLabel = $oKeyAtt->GetLabel($this->GetKeyAttCode());
|
||||
$sLabel = "{$sKeyLabel}->{$sLabel}";
|
||||
|
||||
return $sLabel;
|
||||
}
|
||||
|
||||
public function GetLabelForSearchField()
|
||||
{
|
||||
$sLabel = parent::GetLabel('');
|
||||
if (strlen($sLabel) == 0) {
|
||||
$sKeyAttCode = $this->Get("extkey_attcode");
|
||||
$oExtKeyAttDef = MetaModel::GetAttributeDef($this->GetHostClass(), $sKeyAttCode);
|
||||
$sLabel = $oExtKeyAttDef->GetLabel($this->m_sCode);
|
||||
|
||||
$oRemoteAtt = $this->GetExtAttDef();
|
||||
$sLabel .= '->' . $oRemoteAtt->GetLabel($this->m_sCode);
|
||||
}
|
||||
|
||||
return $sLabel;
|
||||
}
|
||||
|
||||
public function GetDescription($sDefault = null)
|
||||
{
|
||||
$sLabel = parent::GetDescription('');
|
||||
if (strlen($sLabel) == 0) {
|
||||
$oRemoteAtt = $this->GetExtAttDef();
|
||||
$sLabel = $oRemoteAtt->GetDescription('');
|
||||
}
|
||||
|
||||
return $sLabel;
|
||||
}
|
||||
|
||||
public function GetHelpOnEdition($sDefault = null)
|
||||
{
|
||||
$sLabel = parent::GetHelpOnEdition('');
|
||||
if (strlen($sLabel) == 0) {
|
||||
$oRemoteAtt = $this->GetExtAttDef();
|
||||
$sLabel = $oRemoteAtt->GetHelpOnEdition('');
|
||||
}
|
||||
|
||||
return $sLabel;
|
||||
}
|
||||
|
||||
public function IsExternalKey($iType = EXTKEY_RELATIVE)
|
||||
{
|
||||
switch ($iType) {
|
||||
case EXTKEY_ABSOLUTE:
|
||||
// see further
|
||||
$oRemoteAtt = $this->GetExtAttDef();
|
||||
|
||||
return $oRemoteAtt->IsExternalKey($iType);
|
||||
|
||||
case EXTKEY_RELATIVE:
|
||||
return false;
|
||||
|
||||
default:
|
||||
throw new CoreException("Unexpected value for argument iType: '$iType'");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public function IsFriendlyName()
|
||||
{
|
||||
$oRemoteAtt = $this->GetExtAttDef();
|
||||
if ($oRemoteAtt instanceof AttributeExternalField) {
|
||||
$bRet = $oRemoteAtt->IsFriendlyName();
|
||||
} elseif ($oRemoteAtt instanceof AttributeFriendlyName) {
|
||||
$bRet = true;
|
||||
} else {
|
||||
$bRet = false;
|
||||
}
|
||||
|
||||
return $bRet;
|
||||
}
|
||||
|
||||
public function GetTargetClass($iType = EXTKEY_RELATIVE)
|
||||
{
|
||||
return $this->GetKeyAttDef($iType)->GetTargetClass();
|
||||
}
|
||||
|
||||
public static function IsExternalField()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function GetKeyAttCode()
|
||||
{
|
||||
return $this->Get("extkey_attcode");
|
||||
}
|
||||
|
||||
public function GetExtAttCode()
|
||||
{
|
||||
return $this->Get("target_attcode");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $iType
|
||||
*
|
||||
* @return \AttributeExternalKey
|
||||
* @throws \CoreException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function GetKeyAttDef($iType = EXTKEY_RELATIVE)
|
||||
{
|
||||
switch ($iType) {
|
||||
case EXTKEY_ABSOLUTE:
|
||||
// see further
|
||||
/** @var \AttributeExternalKey $oRemoteAtt */
|
||||
$oRemoteAtt = $this->GetExtAttDef();
|
||||
if ($oRemoteAtt->IsExternalField()) {
|
||||
return $oRemoteAtt->GetKeyAttDef(EXTKEY_ABSOLUTE);
|
||||
} else {
|
||||
if ($oRemoteAtt->IsExternalKey()) {
|
||||
return $oRemoteAtt;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->GetKeyAttDef(EXTKEY_RELATIVE); // which corresponds to the code hereafter !
|
||||
|
||||
case EXTKEY_RELATIVE:
|
||||
/** @var \AttributeExternalKey $oAttDef */
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->GetHostClass(), $this->Get("extkey_attcode"));
|
||||
|
||||
return $oAttDef;
|
||||
|
||||
default:
|
||||
throw new CoreException("Unexpected value for argument iType: '$iType'");
|
||||
}
|
||||
}
|
||||
|
||||
public function GetPrerequisiteAttributes($sClass = null)
|
||||
{
|
||||
return array($this->Get("extkey_attcode"));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return \AttributeExternalField
|
||||
* @throws \CoreException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function GetExtAttDef()
|
||||
{
|
||||
$oKeyAttDef = $this->GetKeyAttDef();
|
||||
/** @var \AttributeExternalField $oExtAttDef */
|
||||
$oExtAttDef = MetaModel::GetAttributeDef($oKeyAttDef->GetTargetClass(), $this->Get("target_attcode"));
|
||||
if (!is_object($oExtAttDef)) {
|
||||
throw new CoreException("Invalid external field " . $this->GetCode() . " in class " . $this->GetHostClass() . ". The class " . $oKeyAttDef->GetTargetClass() . " has no attribute " . $this->Get("target_attcode"));
|
||||
}
|
||||
|
||||
return $oExtAttDef;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public function GetSQLExpr()
|
||||
{
|
||||
$oExtAttDef = $this->GetExtAttDef();
|
||||
|
||||
return $oExtAttDef->GetSQLExpr();
|
||||
}
|
||||
|
||||
public function GetDefaultValue(DBObject $oHostObject = null)
|
||||
{
|
||||
$oExtAttDef = $this->GetExtAttDef();
|
||||
|
||||
return $oExtAttDef->GetDefaultValue();
|
||||
}
|
||||
|
||||
public function IsNullAllowed()
|
||||
{
|
||||
$oExtAttDef = $this->GetExtAttDef();
|
||||
|
||||
return $oExtAttDef->IsNullAllowed();
|
||||
}
|
||||
|
||||
public static function IsScalar()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function GetBasicFilterOperators()
|
||||
{
|
||||
$oExtAttDef = $this->GetExtAttDef();
|
||||
|
||||
return $oExtAttDef->GetBasicFilterOperators();
|
||||
}
|
||||
|
||||
public function GetBasicFilterLooseOperator()
|
||||
{
|
||||
$oExtAttDef = $this->GetExtAttDef();
|
||||
|
||||
return $oExtAttDef->GetBasicFilterLooseOperator();
|
||||
}
|
||||
|
||||
public function GetBasicFilterSQLExpr($sOpCode, $value)
|
||||
{
|
||||
$oExtAttDef = $this->GetExtAttDef();
|
||||
|
||||
return $oExtAttDef->GetBasicFilterSQLExpr($sOpCode, $value);
|
||||
}
|
||||
|
||||
public function GetNullValue()
|
||||
{
|
||||
$oExtAttDef = $this->GetExtAttDef();
|
||||
|
||||
return $oExtAttDef->GetNullValue();
|
||||
}
|
||||
|
||||
public function IsNull($proposedValue)
|
||||
{
|
||||
$oExtAttDef = $this->GetExtAttDef();
|
||||
|
||||
return $oExtAttDef->IsNull($proposedValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function HasAValue($proposedValue): bool
|
||||
{
|
||||
$oExtAttDef = $this->GetExtAttDef();
|
||||
|
||||
return $oExtAttDef->HasAValue($proposedValue);
|
||||
}
|
||||
|
||||
public function MakeRealValue($proposedValue, $oHostObj)
|
||||
{
|
||||
$oExtAttDef = $this->GetExtAttDef();
|
||||
|
||||
return $oExtAttDef->MakeRealValue($proposedValue, $oHostObj);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @since 3.1.0 N°6271 Delegate to remote attribute to ensure cascading computed values
|
||||
*/
|
||||
public function GetSQLValues($value)
|
||||
{
|
||||
$oExtAttDef = $this->GetExtAttDef();
|
||||
|
||||
return $oExtAttDef->GetSQLValues($value);
|
||||
}
|
||||
|
||||
public function ScalarToSQL($value)
|
||||
{
|
||||
// This one could be used in case of filtering only
|
||||
$oExtAttDef = $this->GetExtAttDef();
|
||||
|
||||
return $oExtAttDef->ScalarToSQL($value);
|
||||
}
|
||||
|
||||
|
||||
// Do not overload GetSQLExpression here because this is handled in the joins
|
||||
//public function GetSQLExpressions($sPrefix = '') {return array();}
|
||||
|
||||
// Here, we get the data...
|
||||
public function FromSQLToValue($aCols, $sPrefix = '')
|
||||
{
|
||||
$oExtAttDef = $this->GetExtAttDef();
|
||||
|
||||
return $oExtAttDef->FromSQLToValue($aCols, $sPrefix);
|
||||
}
|
||||
|
||||
public function GetAsHTML($value, $oHostObject = null, $bLocalize = true)
|
||||
{
|
||||
$oExtAttDef = $this->GetExtAttDef();
|
||||
|
||||
return $oExtAttDef->GetAsHTML($value, null, $bLocalize);
|
||||
}
|
||||
|
||||
public function GetAsXML($value, $oHostObject = null, $bLocalize = true)
|
||||
{
|
||||
$oExtAttDef = $this->GetExtAttDef();
|
||||
|
||||
return $oExtAttDef->GetAsXML($value, null, $bLocalize);
|
||||
}
|
||||
|
||||
public function GetAsCSV(
|
||||
$value, $sSeparator = ',', $sTestQualifier = '"', $oHostObject = null, $bLocalize = true,
|
||||
$bConvertToPlainText = false
|
||||
)
|
||||
{
|
||||
$oExtAttDef = $this->GetExtAttDef();
|
||||
|
||||
return $oExtAttDef->GetAsCSV($value, $sSeparator, $sTestQualifier, null, $bLocalize, $bConvertToPlainText);
|
||||
}
|
||||
|
||||
public static function GetFormFieldClass()
|
||||
{
|
||||
return '\\Combodo\\iTop\\Form\\Field\\LabelField';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \DBObject $oObject
|
||||
* @param \Combodo\iTop\Form\Field\Field $oFormField
|
||||
*
|
||||
* @return null
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public function MakeFormField(DBObject $oObject, $oFormField = null)
|
||||
{
|
||||
// Retrieving AttDef from the remote attribute
|
||||
$oRemoteAttDef = $this->GetExtAttDef();
|
||||
|
||||
if ($oFormField === null) {
|
||||
// ExternalField's FormField are actually based on the FormField from the target attribute.
|
||||
// Except for the AttributeExternalKey because we have no OQL and stuff
|
||||
if ($oRemoteAttDef instanceof AttributeExternalKey) {
|
||||
$sFormFieldClass = static::GetFormFieldClass();
|
||||
} else {
|
||||
$sFormFieldClass = $oRemoteAttDef::GetFormFieldClass();
|
||||
}
|
||||
/** @var \Combodo\iTop\Form\Field\Field $oFormField */
|
||||
$oFormField = new $sFormFieldClass($this->GetCode());
|
||||
switch ($sFormFieldClass) {
|
||||
case '\Combodo\iTop\Form\Field\SelectField':
|
||||
$oFormField->SetChoices($oRemoteAttDef->GetAllowedValues($oObject->ToArgsForQuery()));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
parent::MakeFormField($oObject, $oFormField);
|
||||
if ($oFormField instanceof \Combodo\iTop\Form\Field\TextAreaField) {
|
||||
if (method_exists($oRemoteAttDef, 'GetFormat')) {
|
||||
/** @var \Combodo\iTop\Form\Field\TextAreaField $oFormField */
|
||||
$oFormField->SetFormat($oRemoteAttDef->GetFormat());
|
||||
}
|
||||
}
|
||||
|
||||
// Manually setting for remote ExternalKey, otherwise, the id would be displayed.
|
||||
if ($oRemoteAttDef instanceof AttributeExternalKey) {
|
||||
$oFormField->SetCurrentValue($oObject->Get($this->GetCode() . '_friendlyname'));
|
||||
}
|
||||
|
||||
// Readonly field because we can't update external fields
|
||||
$oFormField->SetReadOnly(true);
|
||||
|
||||
return $oFormField;
|
||||
}
|
||||
|
||||
public function IsPartOfFingerprint()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function GetFormat()
|
||||
{
|
||||
$oRemoteAttDef = $this->GetExtAttDef();
|
||||
if (method_exists($oRemoteAttDef, 'GetFormat')) {
|
||||
/** @var \Combodo\iTop\Form\Field\TextAreaField $oFormField */
|
||||
return $oRemoteAttDef->GetFormat();
|
||||
}
|
||||
return 'text';
|
||||
}
|
||||
}
|
||||
335
sources/Core/AttributeDefinition/AttributeExternalKey.php
Normal file
335
sources/Core/AttributeDefinition/AttributeExternalKey.php
Normal file
@@ -0,0 +1,335 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Map a foreign key to an attribute
|
||||
* AttributeExternalKey and AttributeExternalField may be an external key
|
||||
* the difference is that AttributeExternalKey corresponds to a column into the defined table
|
||||
* where an AttributeExternalField corresponds to a column into another table (class)
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
class AttributeExternalKey extends AttributeDBFieldVoid
|
||||
{
|
||||
const SEARCH_WIDGET_TYPE = self::SEARCH_WIDGET_TYPE_EXTERNAL_KEY;
|
||||
|
||||
/**
|
||||
* Useless constructor, but if not present PHP 7.4.0/7.4.1 is crashing :( (N°2329)
|
||||
*
|
||||
* @see https://www.php.net/manual/fr/language.oop5.decon.php states that child constructor can be ommited
|
||||
* @see https://bugs.php.net/bug.php?id=79010 bug solved in PHP 7.4.9
|
||||
*
|
||||
* @param string $sCode
|
||||
* @param array $aParams
|
||||
*
|
||||
* @throws \Exception
|
||||
* @noinspection SenselessProxyMethodInspection
|
||||
*/
|
||||
public function __construct($sCode, $aParams)
|
||||
{
|
||||
parent::__construct($sCode, $aParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the search widget type corresponding to this attribute
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function GetSearchType()
|
||||
{
|
||||
try {
|
||||
$oRemoteAtt = $this->GetFinalAttDef();
|
||||
$sTargetClass = $oRemoteAtt->GetTargetClass();
|
||||
if (MetaModel::IsHierarchicalClass($sTargetClass)) {
|
||||
return self::SEARCH_WIDGET_TYPE_HIERARCHICAL_KEY;
|
||||
}
|
||||
|
||||
return self::SEARCH_WIDGET_TYPE_EXTERNAL_KEY;
|
||||
} catch (CoreException $e) {
|
||||
}
|
||||
|
||||
return self::SEARCH_WIDGET_TYPE_RAW;
|
||||
}
|
||||
|
||||
public static function ListExpectedParams()
|
||||
{
|
||||
return array_merge(parent::ListExpectedParams(), array("targetclass", "is_null_allowed", "on_target_delete"));
|
||||
}
|
||||
|
||||
public function GetEditClass()
|
||||
{
|
||||
return "ExtKey";
|
||||
}
|
||||
|
||||
protected function GetSQLCol($bFullSpec = false)
|
||||
{
|
||||
return "INT(11)" . ($bFullSpec ? " DEFAULT 0" : "");
|
||||
}
|
||||
|
||||
public function RequiresIndex()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function IsExternalKey($iType = EXTKEY_RELATIVE)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function GetTargetClass($iType = EXTKEY_RELATIVE)
|
||||
{
|
||||
return $this->Get("targetclass");
|
||||
}
|
||||
|
||||
public function GetKeyAttDef($iType = EXTKEY_RELATIVE)
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function GetKeyAttCode()
|
||||
{
|
||||
return $this->GetCode();
|
||||
}
|
||||
|
||||
public function GetDisplayStyle()
|
||||
{
|
||||
return $this->GetOptional('display_style', 'select');
|
||||
}
|
||||
|
||||
|
||||
public function GetDefaultValue(DBObject $oHostObject = null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function IsNullAllowed()
|
||||
{
|
||||
if (MetaModel::GetConfig()->Get('disable_mandatory_ext_keys')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->Get("is_null_allowed");
|
||||
}
|
||||
|
||||
|
||||
public function GetBasicFilterOperators()
|
||||
{
|
||||
return parent::GetBasicFilterOperators();
|
||||
}
|
||||
|
||||
public function GetBasicFilterLooseOperator()
|
||||
{
|
||||
return parent::GetBasicFilterLooseOperator();
|
||||
}
|
||||
|
||||
public function GetBasicFilterSQLExpr($sOpCode, $value)
|
||||
{
|
||||
return parent::GetBasicFilterSQLExpr($sOpCode, $value);
|
||||
}
|
||||
|
||||
// overloaded here so that an ext key always have the answer to
|
||||
// "what are your possible values?"
|
||||
public function GetValuesDef()
|
||||
{
|
||||
$oValSetDef = $this->Get("allowed_values");
|
||||
if (!$oValSetDef) {
|
||||
// Let's propose every existing value
|
||||
$oValSetDef = new ValueSetObjects('SELECT ' . $this->GetTargetClass());
|
||||
}
|
||||
|
||||
return $oValSetDef;
|
||||
}
|
||||
|
||||
public function GetAllowedValues($aArgs = array(), $sContains = '')
|
||||
{
|
||||
//throw new Exception("GetAllowedValues on ext key has been deprecated");
|
||||
try {
|
||||
return parent::GetAllowedValues($aArgs, $sContains);
|
||||
} catch (Exception $e) {
|
||||
// Some required arguments could not be found, enlarge to any existing value
|
||||
$oValSetDef = new ValueSetObjects('SELECT ' . $this->GetTargetClass());
|
||||
|
||||
return $oValSetDef->GetValues($aArgs, $sContains);
|
||||
}
|
||||
}
|
||||
|
||||
public function GetAllowedValuesForSelect($aArgs = array(), $sContains = '')
|
||||
{
|
||||
//$this->GetValuesDef();
|
||||
$oValSetDef = new ValueSetObjects('SELECT ' . $this->GetTargetClass());
|
||||
return $oValSetDef->GetValuesForAutocomplete($aArgs, $sContains);
|
||||
}
|
||||
|
||||
|
||||
public function GetAllowedValuesAsObjectSet($aArgs = array(), $sContains = '', $iAdditionalValue = null)
|
||||
{
|
||||
$oValSetDef = $this->GetValuesDef();
|
||||
$oSet = $oValSetDef->ToObjectSet($aArgs, $sContains, $iAdditionalValue);
|
||||
|
||||
return $oSet;
|
||||
}
|
||||
|
||||
public function GetAllowedValuesAsFilter($aArgs = array(), $sContains = '', $iAdditionalValue = null)
|
||||
{
|
||||
return DBObjectSearch::FromOQL($this->GetValuesDef()->GetFilterExpression());
|
||||
}
|
||||
|
||||
public function GetDeletionPropagationOption()
|
||||
{
|
||||
return $this->Get("on_target_delete");
|
||||
}
|
||||
|
||||
public function GetNullValue()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function IsNull($proposedValue)
|
||||
{
|
||||
return ($proposedValue == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function HasAValue($proposedValue): bool
|
||||
{
|
||||
return ((int)$proposedValue) !== 0;
|
||||
}
|
||||
|
||||
public function MakeRealValue($proposedValue, $oHostObj)
|
||||
{
|
||||
if (is_null($proposedValue)) {
|
||||
return 0;
|
||||
}
|
||||
if ($proposedValue === '') {
|
||||
return 0;
|
||||
}
|
||||
if (MetaModel::IsValidObject($proposedValue)) {
|
||||
return $proposedValue->GetKey();
|
||||
}
|
||||
|
||||
return (int)$proposedValue;
|
||||
}
|
||||
|
||||
/** @inheritdoc @since 3.1 */
|
||||
public function WriteExternalValues(DBObject $oHostObject): void
|
||||
{
|
||||
$sTargetKey = $oHostObject->Get($this->GetCode());
|
||||
$oFilter = DBSearch::FromOQL('SELECT `' . TemporaryObjectDescriptor::class . '` WHERE item_class=:class AND item_id=:id');
|
||||
$oSet = new DBObjectSet($oFilter, [], ['class' => $this->GetTargetClass(), 'id' => $sTargetKey]);
|
||||
while ($oTemporaryObjectDescriptor = $oSet->Fetch()) {
|
||||
$oTemporaryObjectDescriptor->Set('host_class', get_class($oHostObject));
|
||||
$oTemporaryObjectDescriptor->Set('host_id', $oHostObject->GetKey());
|
||||
$oTemporaryObjectDescriptor->Set('host_att_code', $this->GetCode());
|
||||
$oTemporaryObjectDescriptor->DBUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
public function GetMaximumComboLength()
|
||||
{
|
||||
return $this->GetOptional('max_combo_length', MetaModel::GetConfig()->Get('max_combo_length'));
|
||||
}
|
||||
|
||||
public function GetMinAutoCompleteChars()
|
||||
{
|
||||
return $this->GetOptional('min_autocomplete_chars', MetaModel::GetConfig()->Get('min_autocomplete_chars'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public function GetMaxAutoCompleteResults(): int
|
||||
{
|
||||
return MetaModel::GetConfig()->Get('max_autocomplete_results');
|
||||
}
|
||||
|
||||
public function AllowTargetCreation()
|
||||
{
|
||||
return $this->GetOptional('allow_target_creation', MetaModel::GetConfig()->Get('allow_target_creation'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the corresponding "link" attribute on the target class, if any
|
||||
*
|
||||
* @return null | AttributeDefinition
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public function GetMirrorLinkAttribute()
|
||||
{
|
||||
$oRet = null;
|
||||
$sRemoteClass = $this->GetTargetClass();
|
||||
foreach (MetaModel::ListAttributeDefs($sRemoteClass) as $sRemoteAttCode => $oRemoteAttDef) {
|
||||
if (!$oRemoteAttDef->IsLinkSet()) {
|
||||
continue;
|
||||
}
|
||||
if (!is_subclass_of($this->GetHostClass(),
|
||||
$oRemoteAttDef->GetLinkedClass()) && $oRemoteAttDef->GetLinkedClass() != $this->GetHostClass()) {
|
||||
continue;
|
||||
}
|
||||
if ($oRemoteAttDef->GetExtKeyToMe() != $this->GetCode()) {
|
||||
continue;
|
||||
}
|
||||
$oRet = $oRemoteAttDef;
|
||||
break;
|
||||
}
|
||||
|
||||
return $oRet;
|
||||
}
|
||||
|
||||
public static function GetFormFieldClass()
|
||||
{
|
||||
return '\\Combodo\\iTop\\Form\\Field\\SelectObjectField';
|
||||
}
|
||||
|
||||
public function MakeFormField(DBObject $oObject, $oFormField = null)
|
||||
{
|
||||
/** @var \Combodo\iTop\Form\Field\Field $oFormField */
|
||||
if ($oFormField === null) {
|
||||
// Later : We should check $this->Get('display_style') and create a Radio / Select / ... regarding its value
|
||||
$sFormFieldClass = static::GetFormFieldClass();
|
||||
$oFormField = new $sFormFieldClass($this->GetCode());
|
||||
}
|
||||
|
||||
// Setting params
|
||||
$oFormField->SetMaximumComboLength($this->GetMaximumComboLength());
|
||||
$oFormField->SetMinAutoCompleteChars($this->GetMinAutoCompleteChars());
|
||||
$oFormField->SetMaxAutoCompleteResults($this->GetMaxAutoCompleteResults());
|
||||
$oFormField->SetHierarchical(MetaModel::IsHierarchicalClass($this->GetTargetClass()));
|
||||
// Setting choices regarding the field dependencies
|
||||
$aFieldDependencies = $this->GetPrerequisiteAttributes();
|
||||
if (!empty($aFieldDependencies)) {
|
||||
$oTmpAttDef = $this;
|
||||
$oTmpField = $oFormField;
|
||||
$oFormField->SetOnFinalizeCallback(function () use ($oTmpField, $oTmpAttDef, $oObject) {
|
||||
/** @var $oTmpField \Combodo\iTop\Form\Field\Field */
|
||||
/** @var $oTmpAttDef \AttributeDefinition */
|
||||
/** @var $oObject \DBObject */
|
||||
|
||||
// We set search object only if it has not already been set (overrided)
|
||||
if ($oTmpField->GetSearch() === null) {
|
||||
$oSearch = DBSearch::FromOQL($oTmpAttDef->GetValuesDef()->GetFilterExpression());
|
||||
$oSearch->SetInternalParams(array('this' => $oObject));
|
||||
$oTmpField->SetSearch($oSearch);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
$oSearch = DBSearch::FromOQL($this->GetValuesDef()->GetFilterExpression());
|
||||
$oSearch->SetInternalParams(array('this' => $oObject));
|
||||
$oFormField->SetSearch($oSearch);
|
||||
}
|
||||
|
||||
parent::MakeFormField($oObject, $oFormField);
|
||||
|
||||
return $oFormField;
|
||||
}
|
||||
|
||||
public function GetAsHTML($sValue, $oHostObject = null, $bLocalize = true)
|
||||
{
|
||||
if (!is_null($oHostObject)) {
|
||||
return $oHostObject->GetAsHTML($this->GetCode(), $oHostObject);
|
||||
}
|
||||
|
||||
return DBObject::MakeHyperLink($this->GetTargetClass(), $sValue);
|
||||
}
|
||||
}
|
||||
197
sources/Core/AttributeDefinition/AttributeFinalClass.php
Normal file
197
sources/Core/AttributeDefinition/AttributeFinalClass.php
Normal file
@@ -0,0 +1,197 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* The attribute dedicated to the finalclass automatic attribute
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
class AttributeFinalClass extends AttributeString
|
||||
{
|
||||
const SEARCH_WIDGET_TYPE = self::SEARCH_WIDGET_TYPE_STRING;
|
||||
public $m_sValue;
|
||||
|
||||
public function __construct($sCode, $aParams)
|
||||
{
|
||||
$this->m_sCode = $sCode;
|
||||
$aParams["allowed_values"] = null;
|
||||
parent::__construct($sCode, $aParams);
|
||||
|
||||
$this->m_sValue = $this->Get("default_value");
|
||||
}
|
||||
|
||||
public function IsWritable()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function IsMagic()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function RequiresIndex()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function SetFixedValue($sValue)
|
||||
{
|
||||
$this->m_sValue = $sValue;
|
||||
}
|
||||
|
||||
public function GetDefaultValue(DBObject $oHostObject = null)
|
||||
{
|
||||
return $this->m_sValue;
|
||||
}
|
||||
|
||||
public function GetAsHTML($sValue, $oHostObject = null, $bLocalize = true)
|
||||
{
|
||||
if (empty($sValue)) {
|
||||
return '';
|
||||
}
|
||||
if ($bLocalize) {
|
||||
return MetaModel::GetName($sValue);
|
||||
} else {
|
||||
return $sValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An enum can be localized
|
||||
*
|
||||
* @param string $sProposedValue
|
||||
* @param bool $bLocalizedValue
|
||||
* @param string $sSepItem
|
||||
* @param string $sSepAttribute
|
||||
* @param string $sSepValue
|
||||
* @param string $sAttributeQualifier
|
||||
*
|
||||
* @return mixed|null|string
|
||||
* @throws \CoreException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public function MakeValueFromString(
|
||||
$sProposedValue, $bLocalizedValue = false, $sSepItem = null, $sSepAttribute = null, $sSepValue = null,
|
||||
$sAttributeQualifier = null
|
||||
)
|
||||
{
|
||||
if ($bLocalizedValue) {
|
||||
// Lookup for the value matching the input
|
||||
//
|
||||
$sFoundValue = null;
|
||||
$aRawValues = self::GetAllowedValues();
|
||||
if (!is_null($aRawValues)) {
|
||||
foreach ($aRawValues as $sKey => $sValue) {
|
||||
if ($sProposedValue == $sValue) {
|
||||
$sFoundValue = $sKey;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (is_null($sFoundValue)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->MakeRealValue($sFoundValue, null);
|
||||
} else {
|
||||
return parent::MakeValueFromString($sProposedValue, $bLocalizedValue, $sSepItem, $sSepAttribute, $sSepValue,
|
||||
$sAttributeQualifier);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Because this is sometimes used to get a localized/string version of an attribute...
|
||||
public function GetEditValue($sValue, $oHostObj = null)
|
||||
{
|
||||
if (empty($sValue)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return MetaModel::GetName($sValue);
|
||||
}
|
||||
|
||||
public function GetForJSON($value)
|
||||
{
|
||||
// JSON values are NOT localized
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $value
|
||||
* @param string $sSeparator
|
||||
* @param string $sTextQualifier
|
||||
* @param \DBObject $oHostObject
|
||||
* @param bool $bLocalize
|
||||
* @param bool $bConvertToPlainText
|
||||
*
|
||||
* @return string
|
||||
* @throws \CoreException
|
||||
* @throws \DictExceptionMissingString
|
||||
*/
|
||||
public function GetAsCSV(
|
||||
$value, $sSeparator = ',', $sTextQualifier = '"', $oHostObject = null, $bLocalize = true,
|
||||
$bConvertToPlainText = false
|
||||
)
|
||||
{
|
||||
if ($bLocalize && $value != '') {
|
||||
$sRawValue = MetaModel::GetName($value);
|
||||
} else {
|
||||
$sRawValue = $value;
|
||||
}
|
||||
|
||||
return parent::GetAsCSV($sRawValue, $sSeparator, $sTextQualifier, null, false, $bConvertToPlainText);
|
||||
}
|
||||
|
||||
public function GetAsXML($value, $oHostObject = null, $bLocalize = true)
|
||||
{
|
||||
if (empty($value)) {
|
||||
return '';
|
||||
}
|
||||
if ($bLocalize) {
|
||||
$sRawValue = MetaModel::GetName($value);
|
||||
} else {
|
||||
$sRawValue = $value;
|
||||
}
|
||||
|
||||
return Str::pure2xml($sRawValue);
|
||||
}
|
||||
|
||||
public function GetBasicFilterLooseOperator()
|
||||
{
|
||||
return '=';
|
||||
}
|
||||
|
||||
public function GetValueLabel($sValue)
|
||||
{
|
||||
if (empty($sValue)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return MetaModel::GetName($sValue);
|
||||
}
|
||||
|
||||
public function GetAllowedValues($aArgs = array(), $sContains = '')
|
||||
{
|
||||
$aRawValues = MetaModel::EnumChildClasses($this->GetHostClass(), ENUM_CHILD_CLASSES_ALL);
|
||||
$aLocalizedValues = array();
|
||||
foreach ($aRawValues as $sClass) {
|
||||
$aLocalizedValues[$sClass] = MetaModel::GetName($sClass);
|
||||
}
|
||||
|
||||
return $aLocalizedValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
* @since 2.7.0 N°2272 OQL perf finalclass in all intermediary tables
|
||||
*/
|
||||
public function CopyOnAllTables()
|
||||
{
|
||||
$sClass = self::GetHostClass();
|
||||
if (MetaModel::IsLeafClass($sClass)) {
|
||||
// Leaf class, no finalclass
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
199
sources/Core/AttributeDefinition/AttributeFriendlyName.php
Normal file
199
sources/Core/AttributeDefinition/AttributeFriendlyName.php
Normal file
@@ -0,0 +1,199 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* The attribute dedicated to the friendly name automatic attribute (not written)
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
class AttributeFriendlyName extends AttributeDefinition
|
||||
{
|
||||
const SEARCH_WIDGET_TYPE = self::SEARCH_WIDGET_TYPE_STRING;
|
||||
public $m_sValue;
|
||||
|
||||
public function __construct($sCode)
|
||||
{
|
||||
$this->m_sCode = $sCode;
|
||||
$aParams = array();
|
||||
$aParams["default_value"] = '';
|
||||
parent::__construct($sCode, $aParams);
|
||||
|
||||
$this->m_sValue = $this->Get("default_value");
|
||||
}
|
||||
|
||||
public function GetEditClass()
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
public function GetValuesDef()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function GetPrerequisiteAttributes($sClass = null)
|
||||
{
|
||||
// Code duplicated with AttributeObsolescenceFlag
|
||||
$aAttributes = $this->GetOptional("depends_on", array());
|
||||
$oExpression = $this->GetOQLExpression();
|
||||
foreach ($oExpression->ListRequiredFields() as $sAttCode) {
|
||||
if (!in_array($sAttCode, $aAttributes)) {
|
||||
$aAttributes[] = $sAttCode;
|
||||
}
|
||||
}
|
||||
|
||||
return $aAttributes;
|
||||
}
|
||||
|
||||
public static function IsScalar()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function IsNullAllowed()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function GetSQLExpressions($sPrefix = '')
|
||||
{
|
||||
if ($sPrefix == '') {
|
||||
$sPrefix = $this->GetCode(); // Warning AttributeComputedFieldVoid does not have any sql property
|
||||
}
|
||||
|
||||
return array('' => $sPrefix);
|
||||
}
|
||||
|
||||
public static function IsBasedOnOQLExpression()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function GetOQLExpression()
|
||||
{
|
||||
return MetaModel::GetNameExpression($this->GetHostClass());
|
||||
}
|
||||
|
||||
public function GetLabel($sDefault = null)
|
||||
{
|
||||
$sLabel = parent::GetLabel('');
|
||||
if (strlen($sLabel) == 0) {
|
||||
$sLabel = Dict::S('Core:FriendlyName-Label');
|
||||
}
|
||||
|
||||
return $sLabel;
|
||||
}
|
||||
|
||||
public function GetDescription($sDefault = null)
|
||||
{
|
||||
$sLabel = parent::GetDescription('');
|
||||
if (strlen($sLabel) == 0) {
|
||||
$sLabel = Dict::S('Core:FriendlyName-Description');
|
||||
}
|
||||
|
||||
return $sLabel;
|
||||
}
|
||||
|
||||
public function FromSQLToValue($aCols, $sPrefix = '')
|
||||
{
|
||||
$sValue = $aCols[$sPrefix];
|
||||
|
||||
return $sValue;
|
||||
}
|
||||
|
||||
public function IsWritable()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function IsMagic()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function IsBasedOnDBColumns()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function SetFixedValue($sValue)
|
||||
{
|
||||
$this->m_sValue = $sValue;
|
||||
}
|
||||
|
||||
public function GetDefaultValue(DBObject $oHostObject = null)
|
||||
{
|
||||
return $this->m_sValue;
|
||||
}
|
||||
|
||||
public function GetAsHTML($sValue, $oHostObject = null, $bLocalize = true)
|
||||
{
|
||||
return Str::pure2html((string)$sValue);
|
||||
}
|
||||
|
||||
public function GetAsCSV(
|
||||
$sValue, $sSeparator = ',', $sTextQualifier = '"', $oHostObject = null, $bLocalize = true,
|
||||
$bConvertToPlainText = false
|
||||
)
|
||||
{
|
||||
$sFrom = array("\r\n", $sTextQualifier);
|
||||
$sTo = array("\n", $sTextQualifier . $sTextQualifier);
|
||||
$sEscaped = str_replace($sFrom, $sTo, (string)$sValue);
|
||||
|
||||
return $sTextQualifier . $sEscaped . $sTextQualifier;
|
||||
}
|
||||
|
||||
static function GetFormFieldClass()
|
||||
{
|
||||
return '\\Combodo\\iTop\\Form\\Field\\StringField';
|
||||
}
|
||||
|
||||
public function MakeFormField(DBObject $oObject, $oFormField = null)
|
||||
{
|
||||
if ($oFormField === null) {
|
||||
$sFormFieldClass = static::GetFormFieldClass();
|
||||
$oFormField = new $sFormFieldClass($this->GetCode());
|
||||
}
|
||||
$oFormField->SetReadOnly(true);
|
||||
parent::MakeFormField($oObject, $oFormField);
|
||||
|
||||
return $oFormField;
|
||||
}
|
||||
|
||||
// Do not display friendly names in the history of change
|
||||
public function DescribeChangeAsHTML($sOldValue, $sNewValue, $sLabel = null)
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function GetBasicFilterOperators()
|
||||
{
|
||||
return array("=" => "equals", "!=" => "differs from");
|
||||
}
|
||||
|
||||
public function GetBasicFilterLooseOperator()
|
||||
{
|
||||
return "Contains";
|
||||
}
|
||||
|
||||
public function GetBasicFilterSQLExpr($sOpCode, $value)
|
||||
{
|
||||
$sQValue = CMDBSource::Quote($value);
|
||||
switch ($sOpCode) {
|
||||
case '=':
|
||||
case '!=':
|
||||
return $this->GetSQLExpr() . " $sOpCode $sQValue";
|
||||
case 'Contains':
|
||||
return $this->GetSQLExpr() . " LIKE " . CMDBSource::Quote("%$value%");
|
||||
case 'NotLike':
|
||||
return $this->GetSQLExpr() . " NOT LIKE $sQValue";
|
||||
case 'Like':
|
||||
default:
|
||||
return $this->GetSQLExpr() . " LIKE $sQValue";
|
||||
}
|
||||
}
|
||||
|
||||
public function IsPartOfFingerprint()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
51
sources/Core/AttributeDefinition/AttributeHTML.php
Normal file
51
sources/Core/AttributeDefinition/AttributeHTML.php
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Map a text column (size > ?), containing HTML code, to an attribute
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
class AttributeHTML extends AttributeLongText
|
||||
{
|
||||
/**
|
||||
* Useless constructor, but if not present PHP 7.4.0/7.4.1 is crashing :( (N°2329)
|
||||
*
|
||||
* @see https://www.php.net/manual/fr/language.oop5.decon.php states that child constructor can be ommited
|
||||
* @see https://bugs.php.net/bug.php?id=79010 bug solved in PHP 7.4.9
|
||||
*
|
||||
* @param string $sCode
|
||||
* @param array $aParams
|
||||
*
|
||||
* @throws \Exception
|
||||
* @noinspection SenselessProxyMethodInspection
|
||||
*/
|
||||
public function __construct($sCode, $aParams)
|
||||
{
|
||||
parent::__construct($sCode, $aParams);
|
||||
}
|
||||
|
||||
public function GetSQLColumns($bFullSpec = false)
|
||||
{
|
||||
$aColumns = array();
|
||||
$aColumns[$this->Get('sql')] = $this->GetSQLCol();
|
||||
if ($this->GetOptional('format', null) != null) {
|
||||
// Add the extra column only if the property 'format' is specified for the attribute
|
||||
$aColumns[$this->Get('sql') . '_format'] = "ENUM('text','html')";
|
||||
if ($bFullSpec) {
|
||||
$aColumns[$this->Get('sql') . '_format'] .= " DEFAULT 'html'"; // default 'html' is for migrating old records
|
||||
}
|
||||
}
|
||||
|
||||
return $aColumns;
|
||||
}
|
||||
|
||||
/**
|
||||
* The actual formatting of the text: either text (=plain text) or html (= text with HTML markup)
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function GetFormat()
|
||||
{
|
||||
return $this->GetOptional('format', 'html'); // Defaults to HTML
|
||||
}
|
||||
}
|
||||
186
sources/Core/AttributeDefinition/AttributeHierarchicalKey.php
Normal file
186
sources/Core/AttributeDefinition/AttributeHierarchicalKey.php
Normal file
@@ -0,0 +1,186 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Special kind of External Key to manage a hierarchy of objects
|
||||
*/
|
||||
class AttributeHierarchicalKey extends AttributeExternalKey
|
||||
{
|
||||
const SEARCH_WIDGET_TYPE = self::SEARCH_WIDGET_TYPE_HIERARCHICAL_KEY;
|
||||
|
||||
protected $m_sTargetClass;
|
||||
|
||||
/**
|
||||
* Useless constructor, but if not present PHP 7.4.0/7.4.1 is crashing :( (N°2329)
|
||||
*
|
||||
* @see https://www.php.net/manual/fr/language.oop5.decon.php states that child constructor can be ommited
|
||||
* @see https://bugs.php.net/bug.php?id=79010 bug solved in PHP 7.4.9
|
||||
*
|
||||
* @param string $sCode
|
||||
* @param array $aParams
|
||||
*
|
||||
* @throws \Exception
|
||||
* @noinspection SenselessProxyMethodInspection
|
||||
*/
|
||||
public function __construct($sCode, $aParams)
|
||||
{
|
||||
parent::__construct($sCode, $aParams);
|
||||
}
|
||||
|
||||
public static function ListExpectedParams()
|
||||
{
|
||||
$aParams = parent::ListExpectedParams();
|
||||
$idx = array_search('targetclass', $aParams);
|
||||
unset($aParams[$idx]);
|
||||
$idx = array_search('jointype', $aParams);
|
||||
unset($aParams[$idx]);
|
||||
|
||||
return $aParams; // Later: mettre les bons parametres ici !!
|
||||
}
|
||||
|
||||
public function GetEditClass()
|
||||
{
|
||||
return "ExtKey";
|
||||
}
|
||||
|
||||
public function RequiresIndex()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* The target class is the class for which the attribute has been defined first
|
||||
*/
|
||||
public function SetHostClass($sHostClass)
|
||||
{
|
||||
if (!isset($this->m_sTargetClass)) {
|
||||
$this->m_sTargetClass = $sHostClass;
|
||||
}
|
||||
parent::SetHostClass($sHostClass);
|
||||
}
|
||||
|
||||
public static function IsHierarchicalKey()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function GetTargetClass($iType = EXTKEY_RELATIVE)
|
||||
{
|
||||
return $this->m_sTargetClass;
|
||||
}
|
||||
|
||||
public function GetKeyAttDef($iType = EXTKEY_RELATIVE)
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function GetKeyAttCode()
|
||||
{
|
||||
return $this->GetCode();
|
||||
}
|
||||
|
||||
public function GetBasicFilterOperators()
|
||||
{
|
||||
return parent::GetBasicFilterOperators();
|
||||
}
|
||||
|
||||
public function GetBasicFilterLooseOperator()
|
||||
{
|
||||
return parent::GetBasicFilterLooseOperator();
|
||||
}
|
||||
|
||||
public function GetSQLColumns($bFullSpec = false)
|
||||
{
|
||||
$aColumns = array();
|
||||
$aColumns[$this->GetCode()] = 'INT(11)' . ($bFullSpec ? ' DEFAULT 0' : '');
|
||||
$aColumns[$this->GetSQLLeft()] = 'INT(11)' . ($bFullSpec ? ' DEFAULT 0' : '');
|
||||
$aColumns[$this->GetSQLRight()] = 'INT(11)' . ($bFullSpec ? ' DEFAULT 0' : '');
|
||||
|
||||
return $aColumns;
|
||||
}
|
||||
|
||||
public function GetSQLRight()
|
||||
{
|
||||
return $this->GetCode() . '_right';
|
||||
}
|
||||
|
||||
public function GetSQLLeft()
|
||||
{
|
||||
return $this->GetCode() . '_left';
|
||||
}
|
||||
|
||||
public function GetSQLValues($value)
|
||||
{
|
||||
if (!is_array($value)) {
|
||||
$aValues[$this->GetCode()] = $value;
|
||||
} else {
|
||||
$aValues = array();
|
||||
$aValues[$this->GetCode()] = $value[$this->GetCode()];
|
||||
$aValues[$this->GetSQLRight()] = $value[$this->GetSQLRight()];
|
||||
$aValues[$this->GetSQLLeft()] = $value[$this->GetSQLLeft()];
|
||||
}
|
||||
|
||||
return $aValues;
|
||||
}
|
||||
|
||||
public function GetAllowedValues($aArgs = array(), $sContains = '')
|
||||
{
|
||||
$oFilter = $this->GetHierachicalFilter($aArgs, $sContains);
|
||||
if ($oFilter) {
|
||||
$oValSetDef = $this->GetValuesDef();
|
||||
$oValSetDef->SetCondition($oFilter);
|
||||
|
||||
return $oValSetDef->GetValues($aArgs, $sContains);
|
||||
} else {
|
||||
return parent::GetAllowedValues($aArgs, $sContains);
|
||||
}
|
||||
}
|
||||
|
||||
public function GetAllowedValuesAsObjectSet($aArgs = array(), $sContains = '', $iAdditionalValue = null)
|
||||
{
|
||||
$oValSetDef = $this->GetValuesDef();
|
||||
$oFilter = $this->GetHierachicalFilter($aArgs, $sContains, $iAdditionalValue);
|
||||
if ($oFilter) {
|
||||
$oValSetDef->SetCondition($oFilter);
|
||||
}
|
||||
$oSet = $oValSetDef->ToObjectSet($aArgs, $sContains, $iAdditionalValue);
|
||||
|
||||
return $oSet;
|
||||
}
|
||||
|
||||
public function GetAllowedValuesAsFilter($aArgs = array(), $sContains = '', $iAdditionalValue = null)
|
||||
{
|
||||
$oFilter = $this->GetHierachicalFilter($aArgs, $sContains, $iAdditionalValue);
|
||||
if ($oFilter) {
|
||||
return $oFilter;
|
||||
}
|
||||
|
||||
return parent::GetAllowedValuesAsFilter($aArgs, $sContains, $iAdditionalValue);
|
||||
}
|
||||
|
||||
private function GetHierachicalFilter($aArgs = array(), $sContains = '', $iAdditionalValue = null)
|
||||
{
|
||||
if (array_key_exists('this', $aArgs)) {
|
||||
// Hierarchical keys have one more constraint: the "parent value" cannot be
|
||||
// "under" themselves
|
||||
$iRootId = $aArgs['this']->GetKey();
|
||||
if ($iRootId > 0) // ignore objects that do no exist in the database...
|
||||
{
|
||||
$sClass = $this->m_sTargetClass;
|
||||
|
||||
return DBObjectSearch::FromOQL("SELECT $sClass AS node JOIN $sClass AS root ON node." . $this->GetCode() . " NOT BELOW root.id WHERE root.id = $iRootId");
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the corresponding "link" attribute on the target class, if any
|
||||
*
|
||||
* @return null | AttributeDefinition
|
||||
*/
|
||||
public function GetMirrorLinkAttribute()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
39
sources/Core/AttributeDefinition/AttributeIPAddress.php
Normal file
39
sources/Core/AttributeDefinition/AttributeIPAddress.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Specialization of a string: IP address
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
class AttributeIPAddress extends AttributeString
|
||||
{
|
||||
/**
|
||||
* Useless constructor, but if not present PHP 7.4.0/7.4.1 is crashing :( (N°2329)
|
||||
*
|
||||
* @see https://www.php.net/manual/fr/language.oop5.decon.php states that child constructor can be ommited
|
||||
* @see https://bugs.php.net/bug.php?id=79010 bug solved in PHP 7.4.9
|
||||
*
|
||||
* @param string $sCode
|
||||
* @param array $aParams
|
||||
*
|
||||
* @throws \Exception
|
||||
* @noinspection SenselessProxyMethodInspection
|
||||
*/
|
||||
public function __construct($sCode, $aParams)
|
||||
{
|
||||
parent::__construct($sCode, $aParams);
|
||||
}
|
||||
|
||||
public function GetValidationPattern()
|
||||
{
|
||||
$sNum = '(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])';
|
||||
|
||||
return "^($sNum\\.$sNum\\.$sNum\\.$sNum)$";
|
||||
}
|
||||
|
||||
public function GetOrderBySQLExpressions($sClassAlias)
|
||||
{
|
||||
// Note: This is the responsibility of this function to place backticks around column aliases
|
||||
return array('INET_ATON(`' . $sClassAlias . $this->GetCode() . '`)');
|
||||
}
|
||||
}
|
||||
194
sources/Core/AttributeDefinition/AttributeImage.php
Normal file
194
sources/Core/AttributeDefinition/AttributeImage.php
Normal file
@@ -0,0 +1,194 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* An image is a specific type of document, it is stored as several columns in the database
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
class AttributeImage extends AttributeBlob
|
||||
{
|
||||
/**
|
||||
* Useless constructor, but if not present PHP 7.4.0/7.4.1 is crashing :( (N°2329)
|
||||
*
|
||||
* @see https://www.php.net/manual/fr/language.oop5.decon.php states that child constructor can be ommited
|
||||
* @see https://bugs.php.net/bug.php?id=79010 bug solved in PHP 7.4.9
|
||||
*
|
||||
* @param string $sCode
|
||||
* @param array $aParams
|
||||
*
|
||||
* @throws \Exception
|
||||
* @noinspection SenselessProxyMethodInspection
|
||||
*/
|
||||
public function __construct($sCode, $aParams)
|
||||
{
|
||||
parent::__construct($sCode, $aParams);
|
||||
}
|
||||
|
||||
public function Get($sParamName)
|
||||
{
|
||||
$oParamValue = parent::Get($sParamName);
|
||||
|
||||
if ($sParamName === 'default_image') {
|
||||
/** @noinspection NestedPositiveIfStatementsInspection */
|
||||
if (!empty($oParamValue)) {
|
||||
return utils::GetAbsoluteUrlModulesRoot() . $oParamValue;
|
||||
}
|
||||
}
|
||||
|
||||
return $oParamValue;
|
||||
}
|
||||
|
||||
public function GetEditClass()
|
||||
{
|
||||
return "Image";
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see AttributeBlob::MakeRealValue()
|
||||
*/
|
||||
public function MakeRealValue($proposedValue, $oHostObj)
|
||||
{
|
||||
$oDoc = parent::MakeRealValue($proposedValue, $oHostObj);
|
||||
|
||||
if (($oDoc instanceof ormDocument)
|
||||
&& (false === $oDoc->IsEmpty())
|
||||
&& ($oDoc->GetMimeType() === 'image/svg+xml')) {
|
||||
$sCleanSvg = HTMLSanitizer::Sanitize($oDoc->GetData(), 'svg_sanitizer');
|
||||
$oDoc = new ormDocument($sCleanSvg, $oDoc->GetMimeType(), $oDoc->GetFileName());
|
||||
}
|
||||
|
||||
// The validation of the MIME Type is done by CheckFormat below
|
||||
return $oDoc;
|
||||
}
|
||||
|
||||
public function GetDefaultValue(DBObject $oHostObject = null)
|
||||
{
|
||||
return new ormDocument('', '', '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that the supplied ormDocument actually contains an image
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see AttributeDefinition::CheckFormat()
|
||||
*/
|
||||
public function CheckFormat($value)
|
||||
{
|
||||
if ($value instanceof ormDocument && !$value->IsEmpty()) {
|
||||
return ($value->GetMainMimeType() == 'image');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \ormDocument $value
|
||||
* @param \DBObject $oHostObject
|
||||
* @param bool $bLocalize
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @see edit_image.js for JS generated markup in form edition
|
||||
*/
|
||||
public function GetAsHTML($value, $oHostObject = null, $bLocalize = true)
|
||||
{
|
||||
$sRet = '';
|
||||
$bIsCustomImage = false;
|
||||
|
||||
$iMaxWidth = $this->Get('display_max_width');
|
||||
$sMaxWidthPx = $iMaxWidth . 'px';
|
||||
$iMaxHeight = $this->Get('display_max_height');
|
||||
$sMaxHeightPx = $iMaxHeight . 'px';
|
||||
|
||||
$sDefaultImageUrl = $this->Get('default_image');
|
||||
if ($sDefaultImageUrl !== null) {
|
||||
$sRet = $this->GetHtmlForImageUrl($sDefaultImageUrl, $sMaxWidthPx, $sMaxHeightPx);
|
||||
}
|
||||
|
||||
$sCustomImageUrl = $this->GetAttributeImageFileUrl($value, $oHostObject);
|
||||
if ($sCustomImageUrl !== null) {
|
||||
$bIsCustomImage = true;
|
||||
$sRet = $this->GetHtmlForImageUrl($sCustomImageUrl, $sMaxWidthPx, $sMaxHeightPx);
|
||||
}
|
||||
|
||||
$sCssClasses = 'ibo-input-image--image-view attribute-image';
|
||||
$sCssClasses .= ' ' . (($bIsCustomImage) ? 'attribute-image-custom' : 'attribute-image-default');
|
||||
|
||||
// Important: If you change this, mind updating edit_image.js as well
|
||||
return '<div class="' . $sCssClasses . '" style="max-width: min(' . $sMaxWidthPx . ',100%); max-height: min(' . $sMaxHeightPx . ',100%); aspect-ratio: ' . $iMaxWidth . ' / ' . $iMaxHeight . '">' . $sRet . '</div>';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sUrl
|
||||
* @param int $iMaxWidthPx
|
||||
* @param int $iMaxHeightPx
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @since 2.6.0 new private method
|
||||
* @since 2.7.0 change visibility to protected
|
||||
*/
|
||||
protected function GetHtmlForImageUrl($sUrl, $iMaxWidthPx, $iMaxHeightPx)
|
||||
{
|
||||
return '<img src="' . $sUrl . '" style="max-width: min(' . $iMaxWidthPx . ',100%); max-height: min(' . $iMaxHeightPx . ',100%)">';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \ormDocument $value
|
||||
* @param \DBObject $oHostObject
|
||||
*
|
||||
* @return null|string
|
||||
*
|
||||
* @since 2.6.0 new private method
|
||||
* @since 2.7.0 change visibility to protected
|
||||
*/
|
||||
protected function GetAttributeImageFileUrl($value, $oHostObject)
|
||||
{
|
||||
if (!is_object($value)) {
|
||||
return null;
|
||||
}
|
||||
if ($value->IsEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$bExistingImageModified = ($oHostObject->IsModified() && (array_key_exists($this->GetCode(), $oHostObject->ListChanges())));
|
||||
if ($oHostObject->IsNew() || ($bExistingImageModified)) {
|
||||
// If the object is modified (or not yet stored in the database) we must serve the content of the image directly inline
|
||||
// otherwise (if we just give an URL) the browser will be given the wrong content... and may cache it
|
||||
return 'data:' . $value->GetMimeType() . ';base64,' . base64_encode($value->GetData());
|
||||
}
|
||||
|
||||
return $value->GetDisplayURL(get_class($oHostObject), $oHostObject->GetKey(), $this->GetCode());
|
||||
}
|
||||
|
||||
public static function GetFormFieldClass()
|
||||
{
|
||||
return '\\Combodo\\iTop\\Form\\Field\\ImageField';
|
||||
}
|
||||
|
||||
public function MakeFormField(DBObject $oObject, $oFormField = null)
|
||||
{
|
||||
if ($oFormField === null) {
|
||||
$sFormFieldClass = static::GetFormFieldClass();
|
||||
$oFormField = new $sFormFieldClass($this->GetCode());
|
||||
}
|
||||
|
||||
parent::MakeFormField($oObject, $oFormField);
|
||||
|
||||
// Generating urls
|
||||
$value = $oObject->Get($this->GetCode());
|
||||
if (is_object($value) && !$value->IsEmpty()) {
|
||||
$oFormField->SetDownloadUrl($value->GetDownloadURL(get_class($oObject), $oObject->GetKey(), $this->GetCode()));
|
||||
$oFormField->SetDisplayUrl($value->GetDisplayURL(get_class($oObject), $oObject->GetKey(), $this->GetCode()));
|
||||
} else {
|
||||
$oDefaultImage = $this->Get('default_image');
|
||||
if (is_object($oDefaultImage) && !$oDefaultImage->IsEmpty()) {
|
||||
$oFormField->SetDownloadUrl($oDefaultImage);
|
||||
$oFormField->SetDisplayUrl($oDefaultImage);
|
||||
}
|
||||
}
|
||||
|
||||
return $oFormField;
|
||||
}
|
||||
}
|
||||
138
sources/Core/AttributeDefinition/AttributeInteger.php
Normal file
138
sources/Core/AttributeDefinition/AttributeInteger.php
Normal file
@@ -0,0 +1,138 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Map an integer column to an attribute
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
class AttributeInteger extends AttributeDBField
|
||||
{
|
||||
const SEARCH_WIDGET_TYPE = self::SEARCH_WIDGET_TYPE_NUMERIC;
|
||||
|
||||
/**
|
||||
* Useless constructor, but if not present PHP 7.4.0/7.4.1 is crashing :( (N°2329)
|
||||
*
|
||||
* @see https://www.php.net/manual/fr/language.oop5.decon.php states that child constructor can be ommited
|
||||
* @see https://bugs.php.net/bug.php?id=79010 bug solved in PHP 7.4.9
|
||||
*
|
||||
* @param string $sCode
|
||||
* @param array $aParams
|
||||
*
|
||||
* @throws \Exception
|
||||
* @noinspection SenselessProxyMethodInspection
|
||||
*/
|
||||
public function __construct($sCode, $aParams)
|
||||
{
|
||||
parent::__construct($sCode, $aParams);
|
||||
}
|
||||
|
||||
public static function ListExpectedParams()
|
||||
{
|
||||
return parent::ListExpectedParams();
|
||||
//return array_merge(parent::ListExpectedParams(), array());
|
||||
}
|
||||
|
||||
public function GetEditClass()
|
||||
{
|
||||
return "String";
|
||||
}
|
||||
|
||||
protected function GetSQLCol($bFullSpec = false)
|
||||
{
|
||||
return "INT(11)" . ($bFullSpec ? $this->GetSQLColSpec() : '');
|
||||
}
|
||||
|
||||
public function GetValidationPattern()
|
||||
{
|
||||
return "^[0-9]+$";
|
||||
}
|
||||
|
||||
public function GetBasicFilterOperators()
|
||||
{
|
||||
return array(
|
||||
"!=" => "differs from",
|
||||
"=" => "equals",
|
||||
">" => "greater (strict) than",
|
||||
">=" => "greater than",
|
||||
"<" => "less (strict) than",
|
||||
"<=" => "less than",
|
||||
"in" => "in"
|
||||
);
|
||||
}
|
||||
|
||||
public function GetBasicFilterLooseOperator()
|
||||
{
|
||||
// Unless we implement an "equals approximately..." or "same order of magnitude"
|
||||
return "=";
|
||||
}
|
||||
|
||||
public function GetBasicFilterSQLExpr($sOpCode, $value)
|
||||
{
|
||||
$sQValue = CMDBSource::Quote($value);
|
||||
switch ($sOpCode) {
|
||||
case '!=':
|
||||
return $this->GetSQLExpr() . " != $sQValue";
|
||||
break;
|
||||
case '>':
|
||||
return $this->GetSQLExpr() . " > $sQValue";
|
||||
break;
|
||||
case '>=':
|
||||
return $this->GetSQLExpr() . " >= $sQValue";
|
||||
break;
|
||||
case '<':
|
||||
return $this->GetSQLExpr() . " < $sQValue";
|
||||
break;
|
||||
case '<=':
|
||||
return $this->GetSQLExpr() . " <= $sQValue";
|
||||
break;
|
||||
case 'in':
|
||||
if (!is_array($value)) {
|
||||
throw new CoreException("Expected an array for argument value (sOpCode='$sOpCode')");
|
||||
}
|
||||
|
||||
return $this->GetSQLExpr() . " IN ('" . implode("', '", $value) . "')";
|
||||
break;
|
||||
|
||||
case '=':
|
||||
default:
|
||||
return $this->GetSQLExpr() . " = \"$value\"";
|
||||
}
|
||||
}
|
||||
|
||||
public function GetNullValue()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function IsNull($proposedValue)
|
||||
{
|
||||
return is_null($proposedValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function HasAValue($proposedValue): bool
|
||||
{
|
||||
return utils::IsNotNullOrEmptyString($proposedValue);
|
||||
}
|
||||
|
||||
public function MakeRealValue($proposedValue, $oHostObj)
|
||||
{
|
||||
if (is_null($proposedValue)) {
|
||||
return null;
|
||||
}
|
||||
if ($proposedValue === '') {
|
||||
return null;
|
||||
} // 0 is transformed into '' !
|
||||
|
||||
return (int)$proposedValue;
|
||||
}
|
||||
|
||||
public function ScalarToSQL($value)
|
||||
{
|
||||
assert(is_numeric($value) || is_null($value));
|
||||
|
||||
return $value; // supposed to be an int
|
||||
}
|
||||
}
|
||||
910
sources/Core/AttributeDefinition/AttributeLinkedSet.php
Normal file
910
sources/Core/AttributeDefinition/AttributeLinkedSet.php
Normal file
@@ -0,0 +1,910 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Set of objects directly linked to an object, and being part of its definition
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
class AttributeLinkedSet extends AttributeDefinition
|
||||
{
|
||||
/**
|
||||
* Useless constructor, but if not present PHP 7.4.0/7.4.1 is crashing :( (N°2329)
|
||||
*
|
||||
* @see https://www.php.net/manual/fr/language.oop5.decon.php states that child constructor can be ommited
|
||||
* @see https://bugs.php.net/bug.php?id=79010 bug solved in PHP 7.4.9
|
||||
*
|
||||
* @param string $sCode
|
||||
* @param array $aParams
|
||||
*
|
||||
* @throws \Exception
|
||||
* @noinspection SenselessProxyMethodInspection
|
||||
*/
|
||||
public function __construct($sCode, $aParams)
|
||||
{
|
||||
parent::__construct($sCode, $aParams);
|
||||
$this->aCSSClasses[] = 'attribute-set';
|
||||
}
|
||||
|
||||
public static function ListExpectedParams()
|
||||
{
|
||||
return array_merge(parent::ListExpectedParams(),
|
||||
array("allowed_values", "depends_on", "linked_class", "ext_key_to_me", "count_min", "count_max"));
|
||||
}
|
||||
|
||||
public function GetEditClass()
|
||||
{
|
||||
return "LinkedSet";
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
public static function IsBulkModifyCompatible(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function IsWritable()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function IsLinkSet()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function IsIndirect()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function GetValuesDef()
|
||||
{
|
||||
$oValSetDef = $this->Get("allowed_values");
|
||||
if (!$oValSetDef) {
|
||||
// Let's propose every existing value
|
||||
$oValSetDef = new ValueSetObjects('SELECT ' . \Combodo\iTop\Service\Links\LinkSetModel::GetTargetClass($this));
|
||||
}
|
||||
|
||||
return $oValSetDef;
|
||||
}
|
||||
|
||||
public function GetEditValue($value, $oHostObj = null)
|
||||
{
|
||||
/** @var ormLinkSet $value * */
|
||||
if ($value->Count() === 0) {
|
||||
return '';
|
||||
}
|
||||
|
||||
/** Return linked objects key as string **/
|
||||
$aValues = $value->GetValues();
|
||||
|
||||
return implode(' ', $aValues);
|
||||
}
|
||||
|
||||
public function GetPrerequisiteAttributes($sClass = null)
|
||||
{
|
||||
return $this->Get("depends_on");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \DBObject|null $oHostObject
|
||||
*
|
||||
* @return \ormLinkSet
|
||||
*
|
||||
* @throws \Exception
|
||||
* @throws \CoreException
|
||||
* @throws \CoreWarning
|
||||
*/
|
||||
public function GetDefaultValue(DBObject $oHostObject = null)
|
||||
{
|
||||
if ($oHostObject === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$sLinkClass = $this->GetLinkedClass();
|
||||
$sExtKeyToMe = $this->GetExtKeyToMe();
|
||||
|
||||
// The class to target is not the current class, because if this is a derived class,
|
||||
// it may differ from the target class, then things start to become confusing
|
||||
/** @var \AttributeExternalKey $oRemoteExtKeyAtt */
|
||||
$oRemoteExtKeyAtt = MetaModel::GetAttributeDef($sLinkClass, $sExtKeyToMe);
|
||||
$sMyClass = $oRemoteExtKeyAtt->GetTargetClass();
|
||||
|
||||
$oMyselfSearch = new DBObjectSearch($sMyClass);
|
||||
if ($oHostObject !== null) {
|
||||
$oMyselfSearch->AddCondition('id', $oHostObject->GetKey(), '=');
|
||||
}
|
||||
|
||||
$oLinkSearch = new DBObjectSearch($sLinkClass);
|
||||
$oLinkSearch->AddCondition_PointingTo($oMyselfSearch, $sExtKeyToMe);
|
||||
if ($this->IsIndirect()) {
|
||||
// Join the remote class so that the archive flag will be taken into account
|
||||
/** @var \AttributeLinkedSetIndirect $this */
|
||||
$sExtKeyToRemote = $this->GetExtKeyToRemote();
|
||||
/** @var \AttributeExternalKey $oExtKeyToRemote */
|
||||
$oExtKeyToRemote = MetaModel::GetAttributeDef($sLinkClass, $sExtKeyToRemote);
|
||||
$sRemoteClass = $oExtKeyToRemote->GetTargetClass();
|
||||
if (MetaModel::IsArchivable($sRemoteClass)) {
|
||||
$oRemoteSearch = new DBObjectSearch($sRemoteClass);
|
||||
/** @var \AttributeLinkedSetIndirect $this */
|
||||
$oLinkSearch->AddCondition_PointingTo($oRemoteSearch, $this->GetExtKeyToRemote());
|
||||
}
|
||||
}
|
||||
$oLinks = new DBObjectSet($oLinkSearch);
|
||||
$oLinkSet = new ormLinkSet($this->GetHostClass(), $this->GetCode(), $oLinks);
|
||||
|
||||
return $oLinkSet;
|
||||
}
|
||||
|
||||
public function GetTrackingLevel()
|
||||
{
|
||||
return $this->GetOptional('tracking_level', MetaModel::GetConfig()->Get('tracking_level_linked_set_default'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string see LINKSET_EDITMODE_* constants
|
||||
*/
|
||||
public function GetEditMode()
|
||||
{
|
||||
return $this->GetOptional('edit_mode', LINKSET_EDITMODE_ACTIONS);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int see LINKSET_EDITWHEN_* constants
|
||||
* @since 3.1.1 3.2.0 N°6385
|
||||
*/
|
||||
public function GetEditWhen(): int
|
||||
{
|
||||
return $this->GetOptional('edit_when', LINKSET_EDITWHEN_ALWAYS);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string see LINKSET_DISPLAY_STYLE_* constants
|
||||
* @since 3.1.0 N°3190
|
||||
*/
|
||||
public function GetDisplayStyle()
|
||||
{
|
||||
$sDisplayStyle = $this->GetOptional('display_style', LINKSET_DISPLAY_STYLE_TAB);
|
||||
if ($sDisplayStyle === '') {
|
||||
$sDisplayStyle = LINKSET_DISPLAY_STYLE_TAB;
|
||||
}
|
||||
|
||||
return $sDisplayStyle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the current Attribute has constraints (php constraints or datamodel constraints)
|
||||
* @return bool true if Attribute has constraints
|
||||
* @since 3.1.0 N°6228
|
||||
*/
|
||||
public function HasPHPConstraint(): bool
|
||||
{
|
||||
return $this->GetOptional('with_php_constraint', false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool true if Attribute has computation (DB_LINKS_CHANGED event propagation, `with_php_computation` attribute xml property), false otherwise
|
||||
* @since 3.1.1 3.2.0 N°6228
|
||||
*/
|
||||
public function HasPHPComputation(): bool
|
||||
{
|
||||
return $this->GetOptional('with_php_computation', false);
|
||||
}
|
||||
|
||||
public function GetLinkedClass()
|
||||
{
|
||||
return $this->Get('linked_class');
|
||||
}
|
||||
|
||||
public function GetExtKeyToMe()
|
||||
{
|
||||
return $this->Get('ext_key_to_me');
|
||||
}
|
||||
|
||||
public function GetBasicFilterOperators()
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
public function GetBasicFilterLooseOperator()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function GetBasicFilterSQLExpr($sOpCode, $value)
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
/** @inheritDoc * */
|
||||
public function GetAsHTML($sValue, $oHostObject = null, $bLocalize = true)
|
||||
{
|
||||
if ($this->GetDisplayStyle() === LINKSET_DISPLAY_STYLE_TAB) {
|
||||
return $this->GetAsHTMLForTab($sValue, $oHostObject, $bLocalize);
|
||||
} else {
|
||||
return $this->GetAsHTMLForProperty($sValue, $oHostObject, $bLocalize);
|
||||
}
|
||||
}
|
||||
|
||||
public function GetAsHTMLForTab($sValue, $oHostObject = null, $bLocalize = true)
|
||||
{
|
||||
if (is_object($sValue) && ($sValue instanceof ormLinkSet)) {
|
||||
$sValue->Rewind();
|
||||
$aItems = array();
|
||||
while ($oObj = $sValue->Fetch()) {
|
||||
// Show only relevant information (hide the external key to the current object)
|
||||
$aAttributes = array();
|
||||
foreach (MetaModel::ListAttributeDefs($this->GetLinkedClass()) as $sAttCode => $oAttDef) {
|
||||
if ($sAttCode == $this->GetExtKeyToMe()) {
|
||||
continue;
|
||||
}
|
||||
if ($oAttDef->IsExternalField()) {
|
||||
continue;
|
||||
}
|
||||
$sAttValue = $oObj->GetAsHTML($sAttCode);
|
||||
if (strlen($sAttValue) > 0) {
|
||||
$aAttributes[] = $sAttValue;
|
||||
}
|
||||
}
|
||||
$sAttributes = implode(', ', $aAttributes);
|
||||
$aItems[] = $sAttributes;
|
||||
}
|
||||
|
||||
return implode('<br/>', $aItems);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function GetAsHTMLForProperty($sValue, $oHostObject = null, $bLocalize = true): string
|
||||
{
|
||||
try {
|
||||
|
||||
/** @var ormLinkSet $sValue */
|
||||
if (is_null($sValue) || $sValue->Count() === 0) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$oLinkSetBlock = new \Combodo\iTop\Application\UI\Links\Set\BlockLinkSetDisplayAsProperty($this->GetCode(), $this, $sValue);
|
||||
|
||||
return \Combodo\iTop\Renderer\Console\ConsoleBlockRenderer::RenderBlockTemplates($oLinkSetBlock);
|
||||
} catch (Exception $e) {
|
||||
$sMessage = "Error while displaying attribute {$this->GetCode()}";
|
||||
IssueLog::Error($sMessage, IssueLog::CHANNEL_DEFAULT, [
|
||||
'host_object_class' => $this->GetHostClass(),
|
||||
'host_object_key' => $oHostObject->GetKey(),
|
||||
'attribute' => $this->GetCode(),
|
||||
]);
|
||||
|
||||
return $sMessage;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sValue
|
||||
* @param \DBObject $oHostObject
|
||||
* @param bool $bLocalize
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public function GetAsXML($sValue, $oHostObject = null, $bLocalize = true)
|
||||
{
|
||||
if (is_object($sValue) && ($sValue instanceof ormLinkSet)) {
|
||||
$sValue->Rewind();
|
||||
$sRes = "<Set>\n";
|
||||
while ($oObj = $sValue->Fetch()) {
|
||||
$sObjClass = get_class($oObj);
|
||||
$sRes .= "<$sObjClass id=\"" . $oObj->GetKey() . "\">\n";
|
||||
// Show only relevant information (hide the external key to the current object)
|
||||
foreach (MetaModel::ListAttributeDefs($sObjClass) as $sAttCode => $oAttDef) {
|
||||
if ($sAttCode == 'finalclass') {
|
||||
if ($sObjClass == $this->GetLinkedClass()) {
|
||||
// Simplify the output if the exact class could be determined implicitely
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if ($sAttCode == $this->GetExtKeyToMe()) {
|
||||
continue;
|
||||
}
|
||||
if ($oAttDef->IsExternalField()) {
|
||||
/** @var \AttributeExternalField $oAttDef */
|
||||
if ($oAttDef->GetKeyAttCode() == $this->GetExtKeyToMe()) {
|
||||
continue;
|
||||
}
|
||||
/** @var AttributeExternalField $oAttDef */
|
||||
if ($oAttDef->IsFriendlyName()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if ($oAttDef instanceof AttributeFriendlyName) {
|
||||
continue;
|
||||
}
|
||||
if (!$oAttDef->IsScalar()) {
|
||||
continue;
|
||||
}
|
||||
$sAttValue = $oObj->GetAsXML($sAttCode, $bLocalize);
|
||||
$sRes .= "<$sAttCode>$sAttValue</$sAttCode>\n";
|
||||
}
|
||||
$sRes .= "</$sObjClass>\n";
|
||||
}
|
||||
$sRes .= "</Set>\n";
|
||||
} else {
|
||||
$sRes = '';
|
||||
}
|
||||
|
||||
return $sRes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $sValue
|
||||
* @param string $sSeparator
|
||||
* @param string $sTextQualifier
|
||||
* @param \DBObject $oHostObject
|
||||
* @param bool $bLocalize
|
||||
* @param bool $bConvertToPlainText
|
||||
*
|
||||
* @return mixed|string
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public function GetAsCSV(
|
||||
$sValue, $sSeparator = ',', $sTextQualifier = '"', $oHostObject = null, $bLocalize = true,
|
||||
$bConvertToPlainText = false
|
||||
)
|
||||
{
|
||||
$sSepItem = MetaModel::GetConfig()->Get('link_set_item_separator');
|
||||
$sSepAttribute = MetaModel::GetConfig()->Get('link_set_attribute_separator');
|
||||
$sSepValue = MetaModel::GetConfig()->Get('link_set_value_separator');
|
||||
$sAttributeQualifier = MetaModel::GetConfig()->Get('link_set_attribute_qualifier');
|
||||
|
||||
if (is_object($sValue) && ($sValue instanceof ormLinkSet)) {
|
||||
$sValue->Rewind();
|
||||
$aItems = array();
|
||||
while ($oObj = $sValue->Fetch()) {
|
||||
$sObjClass = get_class($oObj);
|
||||
// Show only relevant information (hide the external key to the current object)
|
||||
$aAttributes = array();
|
||||
foreach (MetaModel::ListAttributeDefs($sObjClass) as $sAttCode => $oAttDef) {
|
||||
if ($sAttCode == 'finalclass') {
|
||||
if ($sObjClass == $this->GetLinkedClass()) {
|
||||
// Simplify the output if the exact class could be determined implicitely
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if ($sAttCode == $this->GetExtKeyToMe()) {
|
||||
continue;
|
||||
}
|
||||
if ($oAttDef->IsExternalField()) {
|
||||
continue;
|
||||
}
|
||||
if (!$oAttDef->IsBasedOnDBColumns()) {
|
||||
continue;
|
||||
}
|
||||
if (!$oAttDef->IsScalar()) {
|
||||
continue;
|
||||
}
|
||||
$sAttValue = $oObj->GetAsCSV($sAttCode, $sSepValue, '', $bLocalize);
|
||||
if (strlen($sAttValue) > 0) {
|
||||
$sAttributeData = str_replace($sAttributeQualifier, $sAttributeQualifier . $sAttributeQualifier,
|
||||
$sAttCode . $sSepValue . $sAttValue);
|
||||
$aAttributes[] = $sAttributeQualifier . $sAttributeData . $sAttributeQualifier;
|
||||
}
|
||||
}
|
||||
$sAttributes = implode($sSepAttribute, $aAttributes);
|
||||
$aItems[] = $sAttributes;
|
||||
}
|
||||
$sRes = implode($sSepItem, $aItems);
|
||||
} else {
|
||||
$sRes = '';
|
||||
}
|
||||
$sRes = str_replace($sTextQualifier, $sTextQualifier . $sTextQualifier, $sRes);
|
||||
$sRes = $sTextQualifier . $sRes . $sTextQualifier;
|
||||
|
||||
return $sRes;
|
||||
}
|
||||
|
||||
/**
|
||||
* List the available verbs for 'GetForTemplate'
|
||||
*/
|
||||
public function EnumTemplateVerbs()
|
||||
{
|
||||
return array(
|
||||
'' => 'Plain text (unlocalized) representation',
|
||||
'html' => 'HTML representation (unordered list)',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get various representations of the value, for insertion into a template (e.g. in Notifications)
|
||||
*
|
||||
* @param mixed $value The current value of the field
|
||||
* @param string $sVerb The verb specifying the representation of the value
|
||||
* @param DBObject $oHostObject The object
|
||||
* @param bool $bLocalize Whether or not to localize the value
|
||||
*
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function GetForTemplate($value, $sVerb, $oHostObject = null, $bLocalize = true)
|
||||
{
|
||||
$sRemoteName = $this->IsIndirect() ?
|
||||
/** @var \AttributeLinkedSetIndirect $this */
|
||||
$this->GetExtKeyToRemote() . '_friendlyname' : 'friendlyname';
|
||||
|
||||
$oLinkSet = clone $value; // Workaround/Safety net for Trac #887
|
||||
$iLimit = MetaModel::GetConfig()->Get('max_linkset_output');
|
||||
$iCount = 0;
|
||||
$aNames = array();
|
||||
foreach ($oLinkSet as $oItem) {
|
||||
if (($iLimit > 0) && ($iCount == $iLimit)) {
|
||||
$iTotal = $oLinkSet->Count();
|
||||
$aNames[] = '... ' . Dict::Format('UI:TruncatedResults', $iCount, $iTotal);
|
||||
break;
|
||||
}
|
||||
$aNames[] = $oItem->Get($sRemoteName);
|
||||
$iCount++;
|
||||
}
|
||||
|
||||
switch ($sVerb) {
|
||||
case '':
|
||||
return implode("\n", $aNames);
|
||||
|
||||
case 'html':
|
||||
return '<ul><li>' . implode("</li><li>", $aNames) . '</li></ul>';
|
||||
|
||||
default:
|
||||
throw new Exception("Unknown verb '$sVerb' for attribute " . $this->GetCode() . ' in class ' . get_class($oHostObject));
|
||||
}
|
||||
}
|
||||
|
||||
public function DuplicatesAllowed()
|
||||
{
|
||||
return false;
|
||||
} // No duplicates for 1:n links, never
|
||||
|
||||
public function GetImportColumns()
|
||||
{
|
||||
$aColumns = array();
|
||||
$aColumns[$this->GetCode()] = 'MEDIUMTEXT' . CMDBSource::GetSqlStringColumnDefinition();
|
||||
|
||||
return $aColumns;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sProposedValue
|
||||
* @param bool $bLocalizedValue
|
||||
* @param string $sSepItem
|
||||
* @param string $sSepAttribute
|
||||
* @param string $sSepValue
|
||||
* @param string $sAttributeQualifier
|
||||
*
|
||||
* @return \DBObjectSet|mixed
|
||||
* @throws \CSVParserException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function MakeValueFromString(
|
||||
$sProposedValue, $bLocalizedValue = false, $sSepItem = null, $sSepAttribute = null, $sSepValue = null,
|
||||
$sAttributeQualifier = null
|
||||
)
|
||||
{
|
||||
if (is_null($sSepItem) || empty($sSepItem)) {
|
||||
$sSepItem = MetaModel::GetConfig()->Get('link_set_item_separator');
|
||||
}
|
||||
if (is_null($sSepAttribute) || empty($sSepAttribute)) {
|
||||
$sSepAttribute = MetaModel::GetConfig()->Get('link_set_attribute_separator');
|
||||
}
|
||||
if (is_null($sSepValue) || empty($sSepValue)) {
|
||||
$sSepValue = MetaModel::GetConfig()->Get('link_set_value_separator');
|
||||
}
|
||||
if (is_null($sAttributeQualifier) || empty($sAttributeQualifier)) {
|
||||
$sAttributeQualifier = MetaModel::GetConfig()->Get('link_set_attribute_qualifier');
|
||||
}
|
||||
|
||||
$sTargetClass = $this->Get('linked_class');
|
||||
|
||||
$sInput = str_replace($sSepItem, "\n", $sProposedValue);
|
||||
$oCSVParser = new CSVParser($sInput, $sSepAttribute, $sAttributeQualifier);
|
||||
|
||||
$aInput = $oCSVParser->ToArray(0 /* do not skip lines */);
|
||||
|
||||
$aLinks = array();
|
||||
foreach ($aInput as $aRow) {
|
||||
// 1st - get the values, split the extkey->searchkey specs, and eventually get the finalclass value
|
||||
$aExtKeys = array();
|
||||
$aValues = array();
|
||||
foreach ($aRow as $sCell) {
|
||||
$iSepPos = strpos($sCell, $sSepValue);
|
||||
if ($iSepPos === false) {
|
||||
// Houston...
|
||||
throw new CoreException('Wrong format for link attribute specification', array('value' => $sCell));
|
||||
}
|
||||
|
||||
$sAttCode = trim(substr($sCell, 0, $iSepPos));
|
||||
$sValue = substr($sCell, $iSepPos + strlen($sSepValue));
|
||||
|
||||
if (preg_match('/^(.+)->(.+)$/', $sAttCode, $aMatches)) {
|
||||
$sKeyAttCode = $aMatches[1];
|
||||
$sRemoteAttCode = $aMatches[2];
|
||||
$aExtKeys[$sKeyAttCode][$sRemoteAttCode] = $sValue;
|
||||
if (!MetaModel::IsValidAttCode($sTargetClass, $sKeyAttCode)) {
|
||||
throw new CoreException('Wrong attribute code for link attribute specification',
|
||||
array('class' => $sTargetClass, 'attcode' => $sKeyAttCode));
|
||||
}
|
||||
/** @var \AttributeExternalKey $oKeyAttDef */
|
||||
$oKeyAttDef = MetaModel::GetAttributeDef($sTargetClass, $sKeyAttCode);
|
||||
$sRemoteClass = $oKeyAttDef->GetTargetClass();
|
||||
if (!MetaModel::IsValidAttCode($sRemoteClass, $sRemoteAttCode)) {
|
||||
throw new CoreException('Wrong attribute code for link attribute specification',
|
||||
array('class' => $sRemoteClass, 'attcode' => $sRemoteAttCode));
|
||||
}
|
||||
} else {
|
||||
if (!MetaModel::IsValidAttCode($sTargetClass, $sAttCode)) {
|
||||
throw new CoreException('Wrong attribute code for link attribute specification',
|
||||
array('class' => $sTargetClass, 'attcode' => $sAttCode));
|
||||
}
|
||||
$oAttDef = MetaModel::GetAttributeDef($sTargetClass, $sAttCode);
|
||||
$aValues[$sAttCode] = $oAttDef->MakeValueFromString($sValue, $bLocalizedValue, $sSepItem,
|
||||
$sSepAttribute, $sSepValue, $sAttributeQualifier);
|
||||
}
|
||||
}
|
||||
|
||||
// 2nd - Instanciate the object and set the value
|
||||
if (isset($aValues['finalclass'])) {
|
||||
$sLinkClass = $aValues['finalclass'];
|
||||
if (!is_subclass_of($sLinkClass, $sTargetClass)) {
|
||||
throw new CoreException('Wrong class for link attribute specification',
|
||||
array('requested_class' => $sLinkClass, 'expected_class' => $sTargetClass));
|
||||
}
|
||||
} elseif (MetaModel::IsAbstract($sTargetClass)) {
|
||||
throw new CoreException('Missing finalclass for link attribute specification');
|
||||
} else {
|
||||
$sLinkClass = $sTargetClass;
|
||||
}
|
||||
|
||||
$oLink = MetaModel::NewObject($sLinkClass);
|
||||
foreach ($aValues as $sAttCode => $sValue) {
|
||||
$oLink->Set($sAttCode, $sValue);
|
||||
}
|
||||
|
||||
// 3rd - Set external keys from search conditions
|
||||
foreach ($aExtKeys as $sKeyAttCode => $aReconciliation) {
|
||||
$oKeyAttDef = MetaModel::GetAttributeDef($sTargetClass, $sKeyAttCode);
|
||||
$sKeyClass = $oKeyAttDef->GetTargetClass();
|
||||
$oExtKeyFilter = new DBObjectSearch($sKeyClass);
|
||||
$aReconciliationDesc = array();
|
||||
foreach ($aReconciliation as $sRemoteAttCode => $sValue) {
|
||||
$oExtKeyFilter->AddCondition($sRemoteAttCode, $sValue, '=');
|
||||
$aReconciliationDesc[] = "$sRemoteAttCode=$sValue";
|
||||
}
|
||||
$oExtKeySet = new DBObjectSet($oExtKeyFilter);
|
||||
switch ($oExtKeySet->Count()) {
|
||||
case 0:
|
||||
$sReconciliationDesc = implode(', ', $aReconciliationDesc);
|
||||
throw new CoreException("Found no match",
|
||||
array('ext_key' => $sKeyAttCode, 'reconciliation' => $sReconciliationDesc));
|
||||
break;
|
||||
case 1:
|
||||
$oRemoteObj = $oExtKeySet->Fetch();
|
||||
$oLink->Set($sKeyAttCode, $oRemoteObj->GetKey());
|
||||
break;
|
||||
default:
|
||||
$sReconciliationDesc = implode(', ', $aReconciliationDesc);
|
||||
throw new CoreException("Found several matches",
|
||||
array('ext_key' => $sKeyAttCode, 'reconciliation' => $sReconciliationDesc));
|
||||
// Found several matches, ambiguous
|
||||
}
|
||||
}
|
||||
|
||||
// Check (roughly) if such a link is valid
|
||||
$aErrors = array();
|
||||
foreach (MetaModel::ListAttributeDefs($sTargetClass) as $sAttCode => $oAttDef) {
|
||||
if ($oAttDef->IsExternalKey()) {
|
||||
/** @var \AttributeExternalKey $oAttDef */
|
||||
if (($oAttDef->GetTargetClass() == $this->GetHostClass()) || (is_subclass_of($this->GetHostClass(),
|
||||
$oAttDef->GetTargetClass()))) {
|
||||
continue; // Don't check the key to self
|
||||
}
|
||||
}
|
||||
|
||||
if ($oAttDef->IsWritable() && $oAttDef->IsNull($oLink->Get($sAttCode)) && !$oAttDef->IsNullAllowed()) {
|
||||
$aErrors[] = $sAttCode;
|
||||
}
|
||||
}
|
||||
if (count($aErrors) > 0) {
|
||||
throw new CoreException("Missing value for mandatory attribute(s): " . implode(', ', $aErrors));
|
||||
}
|
||||
|
||||
$aLinks[] = $oLink;
|
||||
}
|
||||
$oSet = DBObjectSet::FromArray($sTargetClass, $aLinks);
|
||||
|
||||
return $oSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*
|
||||
* @param \ormLinkSet $value
|
||||
*/
|
||||
public function GetForJSON($value)
|
||||
{
|
||||
$aRet = array();
|
||||
if (is_object($value) && ($value instanceof ormLinkSet)) {
|
||||
$value->Rewind();
|
||||
while ($oObj = $value->Fetch()) {
|
||||
$sObjClass = get_class($oObj);
|
||||
// Show only relevant information (hide the external key to the current object)
|
||||
$aAttributes = array();
|
||||
foreach (MetaModel::ListAttributeDefs($sObjClass) as $sAttCode => $oAttDef) {
|
||||
if ($sAttCode == 'finalclass') {
|
||||
if ($sObjClass == $this->GetLinkedClass()) {
|
||||
// Simplify the output if the exact class could be determined implicitely
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if ($sAttCode == $this->GetExtKeyToMe()) {
|
||||
continue;
|
||||
}
|
||||
if ($oAttDef->IsExternalField()) {
|
||||
continue;
|
||||
}
|
||||
if (!$oAttDef->IsBasedOnDBColumns()) {
|
||||
continue;
|
||||
}
|
||||
if (!$oAttDef->IsScalar()) {
|
||||
continue;
|
||||
}
|
||||
$attValue = $oObj->Get($sAttCode);
|
||||
$aAttributes[$sAttCode] = $oAttDef->GetForJSON($attValue);
|
||||
}
|
||||
$aRet[] = $aAttributes;
|
||||
}
|
||||
}
|
||||
|
||||
return $aRet;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*
|
||||
* @return \DBObjectSet
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function FromJSONToValue($json)
|
||||
{
|
||||
$sTargetClass = $this->Get('linked_class');
|
||||
|
||||
$aLinks = array();
|
||||
foreach ($json as $aValues) {
|
||||
if (isset($aValues['finalclass'])) {
|
||||
$sLinkClass = $aValues['finalclass'];
|
||||
if (!is_subclass_of($sLinkClass, $sTargetClass)) {
|
||||
throw new CoreException('Wrong class for link attribute specification',
|
||||
array('requested_class' => $sLinkClass, 'expected_class' => $sTargetClass));
|
||||
}
|
||||
} elseif (MetaModel::IsAbstract($sTargetClass)) {
|
||||
throw new CoreException('Missing finalclass for link attribute specification');
|
||||
} else {
|
||||
$sLinkClass = $sTargetClass;
|
||||
}
|
||||
|
||||
$oLink = MetaModel::NewObject($sLinkClass);
|
||||
foreach ($aValues as $sAttCode => $sValue) {
|
||||
$oLink->Set($sAttCode, $sValue);
|
||||
}
|
||||
|
||||
// Check (roughly) if such a link is valid
|
||||
$aErrors = array();
|
||||
foreach (MetaModel::ListAttributeDefs($sTargetClass) as $sAttCode => $oAttDef) {
|
||||
if ($oAttDef->IsExternalKey()) {
|
||||
/** @var AttributeExternalKey $oAttDef */
|
||||
if (($oAttDef->GetTargetClass() == $this->GetHostClass()) || (is_subclass_of($this->GetHostClass(),
|
||||
$oAttDef->GetTargetClass()))) {
|
||||
continue; // Don't check the key to self
|
||||
}
|
||||
}
|
||||
|
||||
if ($oAttDef->IsWritable() && $oAttDef->IsNull($oLink->Get($sAttCode)) && !$oAttDef->IsNullAllowed()) {
|
||||
$aErrors[] = $sAttCode;
|
||||
}
|
||||
}
|
||||
if (count($aErrors) > 0) {
|
||||
throw new CoreException("Missing value for mandatory attribute(s): " . implode(', ', $aErrors));
|
||||
}
|
||||
|
||||
$aLinks[] = $oLink;
|
||||
}
|
||||
$oSet = DBObjectSet::FromArray($sTargetClass, $aLinks);
|
||||
|
||||
return $oSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $proposedValue
|
||||
* @param $oHostObj
|
||||
*
|
||||
* @return mixed
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function MakeRealValue($proposedValue, $oHostObj)
|
||||
{
|
||||
if ($proposedValue === null) {
|
||||
$sLinkedClass = $this->GetLinkedClass();
|
||||
$aLinkedObjectsArray = array();
|
||||
$oSet = DBObjectSet::FromArray($sLinkedClass, $aLinkedObjectsArray);
|
||||
|
||||
return new ormLinkSet(
|
||||
get_class($oHostObj),
|
||||
$this->GetCode(),
|
||||
$oSet
|
||||
);
|
||||
}
|
||||
|
||||
return $proposedValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ormLinkSet $val1
|
||||
* @param ormLinkSet $val2
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function Equals($val1, $val2)
|
||||
{
|
||||
if ($val1 === $val2) {
|
||||
$bAreEquivalent = true;
|
||||
} else {
|
||||
$bAreEquivalent = ($val2->HasDelta() === false);
|
||||
}
|
||||
|
||||
return $bAreEquivalent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the corresponding "link" attribute on the target class, if any
|
||||
*
|
||||
* @return null | AttributeDefinition
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function GetMirrorLinkAttribute()
|
||||
{
|
||||
$oRemoteAtt = MetaModel::GetAttributeDef($this->GetLinkedClass(), $this->GetExtKeyToMe());
|
||||
|
||||
return $oRemoteAtt;
|
||||
}
|
||||
|
||||
public static function GetFormFieldClass()
|
||||
{
|
||||
return '\\Combodo\\iTop\\Form\\Field\\LinkedSetField';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \DBObject $oObject
|
||||
* @param \Combodo\iTop\Form\Field\LinkedSetField $oFormField
|
||||
*
|
||||
* @return \Combodo\iTop\Form\Field\LinkedSetField
|
||||
* @throws \CoreException
|
||||
* @throws \DictExceptionMissingString
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function MakeFormField(DBObject $oObject, $oFormField = null)
|
||||
{
|
||||
if ($oFormField === null) {
|
||||
$sFormFieldClass = static::GetFormFieldClass();
|
||||
$oFormField = new $sFormFieldClass($this->GetCode());
|
||||
}
|
||||
|
||||
// Setting target class
|
||||
if (!$this->IsIndirect()) {
|
||||
$sTargetClass = $this->GetLinkedClass();
|
||||
} else {
|
||||
/** @var \AttributeExternalKey $oRemoteAttDef */
|
||||
/** @var \AttributeLinkedSetIndirect $this */
|
||||
$oRemoteAttDef = MetaModel::GetAttributeDef($this->GetLinkedClass(), $this->GetExtKeyToRemote());
|
||||
$sTargetClass = $oRemoteAttDef->GetTargetClass();
|
||||
|
||||
/** @var \AttributeLinkedSetIndirect $this */
|
||||
$oFormField->SetExtKeyToRemote($this->GetExtKeyToRemote());
|
||||
}
|
||||
$oFormField->SetTargetClass($sTargetClass);
|
||||
$oFormField->SetLinkedClass($this->GetLinkedClass());
|
||||
$oFormField->SetIndirect($this->IsIndirect());
|
||||
// Setting attcodes to display
|
||||
$aAttCodesToDisplay = MetaModel::FlattenZList(MetaModel::GetZListItems($sTargetClass, 'list'));
|
||||
// - Adding friendlyname attribute to the list is not already in it
|
||||
$sTitleAttCode = MetaModel::GetFriendlyNameAttributeCode($sTargetClass);
|
||||
if (($sTitleAttCode !== null) && !in_array($sTitleAttCode, $aAttCodesToDisplay)) {
|
||||
$aAttCodesToDisplay = array_merge(array($sTitleAttCode), $aAttCodesToDisplay);
|
||||
}
|
||||
// - Adding attribute properties
|
||||
$aAttributesToDisplay = array();
|
||||
foreach ($aAttCodesToDisplay as $sAttCodeToDisplay) {
|
||||
$oAttDefToDisplay = MetaModel::GetAttributeDef($sTargetClass, $sAttCodeToDisplay);
|
||||
$aAttributesToDisplay[$sAttCodeToDisplay] = [
|
||||
'att_code' => $sAttCodeToDisplay,
|
||||
'label' => $oAttDefToDisplay->GetLabel(),
|
||||
];
|
||||
}
|
||||
$oFormField->SetAttributesToDisplay($aAttributesToDisplay);
|
||||
|
||||
// Append lnk attributes (filtered from zlist)
|
||||
if ($this->IsIndirect()) {
|
||||
$aLnkAttDefToDisplay = MetaModel::GetZListAttDefsFilteredForIndirectLinkClass($this->m_sHostClass, $this->m_sCode);
|
||||
$aLnkAttributesToDisplay = array();
|
||||
foreach ($aLnkAttDefToDisplay as $oLnkAttDefToDisplay) {
|
||||
$aLnkAttributesToDisplay[$oLnkAttDefToDisplay->GetCode()] = [
|
||||
'att_code' => $oLnkAttDefToDisplay->GetCode(),
|
||||
'label' => $oLnkAttDefToDisplay->GetLabel(),
|
||||
'mandatory' => !$oLnkAttDefToDisplay->IsNullAllowed(),
|
||||
];
|
||||
}
|
||||
$oFormField->SetLnkAttributesToDisplay($aLnkAttributesToDisplay);
|
||||
}
|
||||
|
||||
parent::MakeFormField($oObject, $oFormField);
|
||||
|
||||
return $oFormField;
|
||||
}
|
||||
|
||||
public function IsPartOfFingerprint()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @param \ormLinkSet $proposedValue
|
||||
*/
|
||||
public function HasAValue($proposedValue): bool
|
||||
{
|
||||
// Protection against wrong value type
|
||||
if (false === ($proposedValue instanceof ormLinkSet)) {
|
||||
return parent::HasAValue($proposedValue);
|
||||
}
|
||||
|
||||
// We test if there is at least 1 item in the linkset (new or existing), not if an item is being added to it.
|
||||
return $proposedValue->Count() > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* SearchSpecificLabel.
|
||||
*
|
||||
* @param string $sDictEntrySuffix
|
||||
* @param string $sDefault
|
||||
* @param bool $bUserLanguageOnly
|
||||
* @param ...$aArgs
|
||||
* @return string
|
||||
* @since 3.1.0
|
||||
*/
|
||||
public function SearchSpecificLabel(string $sDictEntrySuffix, string $sDefault, bool $bUserLanguageOnly, ...$aArgs): string
|
||||
{
|
||||
try {
|
||||
$sNextClass = $this->m_sHostClass;
|
||||
|
||||
do {
|
||||
$sKey = "Class:{$sNextClass}/Attribute:{$this->m_sCode}/{$sDictEntrySuffix}";
|
||||
if (Dict::S($sKey, null, $bUserLanguageOnly) !== $sKey) {
|
||||
return Dict::Format($sKey, ...$aArgs);
|
||||
}
|
||||
$sNextClass = MetaModel::GetParentClass($sNextClass);
|
||||
} while ($sNextClass !== null);
|
||||
|
||||
if (Dict::S($sDictEntrySuffix, null, $bUserLanguageOnly) !== $sKey) {
|
||||
return Dict::Format($sDictEntrySuffix, ...$aArgs);
|
||||
} else {
|
||||
return $sDefault;
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
ExceptionLog::LogException($e);
|
||||
return $sDefault;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Set of objects linked to an object (n-n), and being part of its definition
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
class AttributeLinkedSetIndirect extends AttributeLinkedSet
|
||||
{
|
||||
/**
|
||||
* Useless constructor, but if not present PHP 7.4.0/7.4.1 is crashing :( (N°2329)
|
||||
*
|
||||
* @see https://www.php.net/manual/fr/language.oop5.decon.php states that child constructor can be ommited
|
||||
* @see https://bugs.php.net/bug.php?id=79010 bug solved in PHP 7.4.9
|
||||
*
|
||||
* @param string $sCode
|
||||
* @param array $aParams
|
||||
*
|
||||
* @throws \Exception
|
||||
* @noinspection SenselessProxyMethodInspection
|
||||
*/
|
||||
public function __construct($sCode, $aParams)
|
||||
{
|
||||
parent::__construct($sCode, $aParams);
|
||||
}
|
||||
|
||||
public static function ListExpectedParams()
|
||||
{
|
||||
return array_merge(parent::ListExpectedParams(), array("ext_key_to_remote"));
|
||||
}
|
||||
|
||||
public function IsIndirect()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function GetExtKeyToRemote()
|
||||
{
|
||||
return $this->Get('ext_key_to_remote');
|
||||
}
|
||||
|
||||
public function GetEditClass()
|
||||
{
|
||||
return "LinkedSet";
|
||||
}
|
||||
|
||||
public function DuplicatesAllowed()
|
||||
{
|
||||
return $this->GetOptional("duplicates", false);
|
||||
} // The same object may be linked several times... or not...
|
||||
|
||||
public function GetTrackingLevel()
|
||||
{
|
||||
return $this->GetOptional('tracking_level',
|
||||
MetaModel::GetConfig()->Get('tracking_level_linked_set_indirect_default'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the corresponding "link" attribute on the target class, if any
|
||||
*
|
||||
* @return null | AttributeDefinition
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public function GetMirrorLinkAttribute()
|
||||
{
|
||||
$oRet = null;
|
||||
/** @var \AttributeExternalKey $oExtKeyToRemote */
|
||||
$oExtKeyToRemote = MetaModel::GetAttributeDef($this->GetLinkedClass(), $this->GetExtKeyToRemote());
|
||||
$sRemoteClass = $oExtKeyToRemote->GetTargetClass();
|
||||
foreach (MetaModel::ListAttributeDefs($sRemoteClass) as $sRemoteAttCode => $oRemoteAttDef) {
|
||||
if (!$oRemoteAttDef instanceof AttributeLinkedSetIndirect) {
|
||||
continue;
|
||||
}
|
||||
if ($oRemoteAttDef->GetLinkedClass() != $this->GetLinkedClass()) {
|
||||
continue;
|
||||
}
|
||||
if ($oRemoteAttDef->GetExtKeyToMe() != $this->GetExtKeyToRemote()) {
|
||||
continue;
|
||||
}
|
||||
if ($oRemoteAttDef->GetExtKeyToRemote() != $this->GetExtKeyToMe()) {
|
||||
continue;
|
||||
}
|
||||
$oRet = $oRemoteAttDef;
|
||||
break;
|
||||
}
|
||||
|
||||
return $oRet;
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
public static function IsBulkModifyCompatible(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
45
sources/Core/AttributeDefinition/AttributeLongText.php
Normal file
45
sources/Core/AttributeDefinition/AttributeLongText.php
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Map a log to an attribute
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
class AttributeLongText extends AttributeText
|
||||
{
|
||||
/**
|
||||
* Useless constructor, but if not present PHP 7.4.0/7.4.1 is crashing :( (N°2329)
|
||||
*
|
||||
* @see https://www.php.net/manual/fr/language.oop5.decon.php states that child constructor can be ommited
|
||||
* @see https://bugs.php.net/bug.php?id=79010 bug solved in PHP 7.4.9
|
||||
*
|
||||
* @param string $sCode
|
||||
* @param array $aParams
|
||||
*
|
||||
* @throws \Exception
|
||||
* @noinspection SenselessProxyMethodInspection
|
||||
*/
|
||||
public function __construct($sCode, $aParams)
|
||||
{
|
||||
parent::__construct($sCode, $aParams);
|
||||
}
|
||||
|
||||
protected function GetSQLCol($bFullSpec = false)
|
||||
{
|
||||
return "LONGTEXT" . CMDBSource::GetSqlStringColumnDefinition();
|
||||
}
|
||||
|
||||
public function GetMaxSize()
|
||||
{
|
||||
// Is there a way to know the current limitation for mysql?
|
||||
// See mysql_field_len()
|
||||
return 65535 * 1024; // Limited... still 64 MB!
|
||||
}
|
||||
|
||||
protected function GetChangeRecordClassName(): string
|
||||
{
|
||||
return ($this->GetFormat() === 'html')
|
||||
? CMDBChangeOpSetAttributeHTML::class
|
||||
: CMDBChangeOpSetAttributeLongText::class;
|
||||
}
|
||||
}
|
||||
137
sources/Core/AttributeDefinition/AttributeMetaEnum.php
Normal file
137
sources/Core/AttributeDefinition/AttributeMetaEnum.php
Normal file
@@ -0,0 +1,137 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* A meta enum is an aggregation of enum from subclasses into an enum of a base class
|
||||
* It has been designed is to cope with the fact that statuses must be defined in leaf classes, while it makes sense to
|
||||
* have a superstatus available on the root classe(s)
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
class AttributeMetaEnum extends AttributeEnum
|
||||
{
|
||||
/**
|
||||
* Useless constructor, but if not present PHP 7.4.0/7.4.1 is crashing :( (N°2329)
|
||||
*
|
||||
* @see https://www.php.net/manual/fr/language.oop5.decon.php states that child constructor can be ommited
|
||||
* @see https://bugs.php.net/bug.php?id=79010 bug solved in PHP 7.4.9
|
||||
*
|
||||
* @param string $sCode
|
||||
* @param array $aParams
|
||||
*
|
||||
* @throws \Exception
|
||||
* @noinspection SenselessProxyMethodInspection
|
||||
*/
|
||||
public function __construct($sCode, $aParams)
|
||||
{
|
||||
parent::__construct($sCode, $aParams);
|
||||
}
|
||||
|
||||
public static function ListExpectedParams()
|
||||
{
|
||||
return array('allowed_values', 'sql', 'default_value', 'mapping');
|
||||
}
|
||||
|
||||
public function IsNullAllowed()
|
||||
{
|
||||
return false; // Well... this actually depends on the mapping
|
||||
}
|
||||
|
||||
public function IsWritable()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function RequiresIndex()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function GetPrerequisiteAttributes($sClass = null)
|
||||
{
|
||||
if (is_null($sClass)) {
|
||||
$sClass = $this->GetHostClass();
|
||||
}
|
||||
$aMappingData = $this->GetMapRule($sClass);
|
||||
if ($aMappingData == null) {
|
||||
$aRet = array();
|
||||
} else {
|
||||
$aRet = array($aMappingData['attcode']);
|
||||
}
|
||||
|
||||
return $aRet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overload the standard so as to leave the data unsorted
|
||||
*
|
||||
* @param array $aArgs
|
||||
* @param string $sContains
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
public function GetAllowedValues($aArgs = array(), $sContains = '')
|
||||
{
|
||||
$oValSetDef = $this->GetValuesDef();
|
||||
if (!$oValSetDef) {
|
||||
return null;
|
||||
}
|
||||
$aRawValues = $oValSetDef->GetValueList();
|
||||
|
||||
if (is_null($aRawValues)) {
|
||||
return null;
|
||||
}
|
||||
$aLocalizedValues = array();
|
||||
foreach ($aRawValues as $sKey => $sValue) {
|
||||
$aLocalizedValues[$sKey] = $this->GetValueLabel($sKey);
|
||||
}
|
||||
|
||||
return $aLocalizedValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the meta value for the given object.
|
||||
* See also MetaModel::RebuildMetaEnums() that must be maintained when MapValue changes
|
||||
*
|
||||
* @param $oObject
|
||||
*
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public function MapValue($oObject)
|
||||
{
|
||||
$aMappingData = $this->GetMapRule(get_class($oObject));
|
||||
if ($aMappingData == null) {
|
||||
$sRet = $this->GetDefaultValue();
|
||||
} else {
|
||||
$sAttCode = $aMappingData['attcode'];
|
||||
$value = $oObject->Get($sAttCode);
|
||||
if (array_key_exists($value, $aMappingData['values'])) {
|
||||
$sRet = $aMappingData['values'][$value];
|
||||
} elseif ($this->GetDefaultValue() != '') {
|
||||
$sRet = $this->GetDefaultValue();
|
||||
} else {
|
||||
throw new Exception('AttributeMetaEnum::MapValue(): mapping not found for value "' . $value . '" in ' . get_class($oObject) . ', on attribute ' . MetaModel::GetAttributeOrigin($this->GetHostClass(),
|
||||
$this->GetCode()) . '::' . $this->GetCode());
|
||||
}
|
||||
}
|
||||
|
||||
return $sRet;
|
||||
}
|
||||
|
||||
public function GetMapRule($sClass)
|
||||
{
|
||||
$aMappings = $this->Get('mapping');
|
||||
if (array_key_exists($sClass, $aMappings)) {
|
||||
$aMappingData = $aMappings[$sClass];
|
||||
} else {
|
||||
$sParent = MetaModel::GetParentClass($sClass);
|
||||
if (is_null($sParent)) {
|
||||
$aMappingData = null;
|
||||
} else {
|
||||
$aMappingData = $this->GetMapRule($sParent);
|
||||
}
|
||||
}
|
||||
|
||||
return $aMappingData;
|
||||
}
|
||||
}
|
||||
33
sources/Core/AttributeDefinition/AttributeOQL.php
Normal file
33
sources/Core/AttributeDefinition/AttributeOQL.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Specialization of a string: OQL expression
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
class AttributeOQL extends AttributeText
|
||||
{
|
||||
const SEARCH_WIDGET_TYPE = self::SEARCH_WIDGET_TYPE_STRING;
|
||||
|
||||
/**
|
||||
* Useless constructor, but if not present PHP 7.4.0/7.4.1 is crashing :( (N°2329)
|
||||
*
|
||||
* @see https://www.php.net/manual/fr/language.oop5.decon.php states that child constructor can be ommited
|
||||
* @see https://bugs.php.net/bug.php?id=79010 bug solved in PHP 7.4.9
|
||||
*
|
||||
* @param string $sCode
|
||||
* @param array $aParams
|
||||
*
|
||||
* @throws \Exception
|
||||
* @noinspection SenselessProxyMethodInspection
|
||||
*/
|
||||
public function __construct($sCode, $aParams)
|
||||
{
|
||||
parent::__construct($sCode, $aParams);
|
||||
}
|
||||
|
||||
public function GetEditClass()
|
||||
{
|
||||
return "OQLExpression";
|
||||
}
|
||||
}
|
||||
107
sources/Core/AttributeDefinition/AttributeObjectKey.php
Normal file
107
sources/Core/AttributeDefinition/AttributeObjectKey.php
Normal file
@@ -0,0 +1,107 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* An external key for which the class is defined as the value of another attribute
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
class AttributeObjectKey extends AttributeDBFieldVoid
|
||||
{
|
||||
const SEARCH_WIDGET_TYPE = self::SEARCH_WIDGET_TYPE_EXTERNAL_KEY;
|
||||
|
||||
/**
|
||||
* Useless constructor, but if not present PHP 7.4.0/7.4.1 is crashing :( (N°2329)
|
||||
*
|
||||
* @see https://www.php.net/manual/fr/language.oop5.decon.php states that child constructor can be ommited
|
||||
* @see https://bugs.php.net/bug.php?id=79010 bug solved in PHP 7.4.9
|
||||
*
|
||||
* @param string $sCode
|
||||
* @param array $aParams
|
||||
*
|
||||
* @throws \Exception
|
||||
* @noinspection SenselessProxyMethodInspection
|
||||
*/
|
||||
public function __construct($sCode, $aParams)
|
||||
{
|
||||
parent::__construct($sCode, $aParams);
|
||||
}
|
||||
|
||||
public static function ListExpectedParams()
|
||||
{
|
||||
return array_merge(parent::ListExpectedParams(), array('class_attcode', 'is_null_allowed'));
|
||||
}
|
||||
|
||||
public function GetEditClass()
|
||||
{
|
||||
return "String";
|
||||
}
|
||||
|
||||
protected function GetSQLCol($bFullSpec = false)
|
||||
{
|
||||
return "INT(11)" . ($bFullSpec ? " DEFAULT 0" : "");
|
||||
}
|
||||
|
||||
public function GetDefaultValue(DBObject $oHostObject = null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function IsNullAllowed()
|
||||
{
|
||||
return $this->Get("is_null_allowed");
|
||||
}
|
||||
|
||||
|
||||
public function GetBasicFilterOperators()
|
||||
{
|
||||
return parent::GetBasicFilterOperators();
|
||||
}
|
||||
|
||||
public function GetBasicFilterLooseOperator()
|
||||
{
|
||||
return parent::GetBasicFilterLooseOperator();
|
||||
}
|
||||
|
||||
public function GetBasicFilterSQLExpr($sOpCode, $value)
|
||||
{
|
||||
return parent::GetBasicFilterSQLExpr($sOpCode, $value);
|
||||
}
|
||||
|
||||
public function GetNullValue()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function IsNull($proposedValue)
|
||||
{
|
||||
return ($proposedValue == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function HasAValue($proposedValue): bool
|
||||
{
|
||||
return ((int)$proposedValue) !== 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*
|
||||
* @param int|DBObject $proposedValue Object key or valid ({@see MetaModel::IsValidObject()}) datamodel object
|
||||
*/
|
||||
public function MakeRealValue($proposedValue, $oHostObj)
|
||||
{
|
||||
if (is_null($proposedValue)) {
|
||||
return 0;
|
||||
}
|
||||
if ($proposedValue === '') {
|
||||
return 0;
|
||||
}
|
||||
if (MetaModel::IsValidObject($proposedValue)) {
|
||||
return $proposedValue->GetKey();
|
||||
}
|
||||
|
||||
return (int)$proposedValue;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
class AttributeObsolescenceDate extends AttributeDate
|
||||
{
|
||||
/**
|
||||
* Useless constructor, but if not present PHP 7.4.0/7.4.1 is crashing :( (N°2329)
|
||||
*
|
||||
* @see https://www.php.net/manual/fr/language.oop5.decon.php states that child constructor can be ommited
|
||||
* @see https://bugs.php.net/bug.php?id=79010 bug solved in PHP 7.4.9
|
||||
*
|
||||
* @param string $sCode
|
||||
* @param array $aParams
|
||||
*
|
||||
* @throws \Exception
|
||||
* @noinspection SenselessProxyMethodInspection
|
||||
*/
|
||||
public function __construct($sCode, $aParams)
|
||||
{
|
||||
parent::__construct($sCode, $aParams);
|
||||
}
|
||||
|
||||
public function GetLabel($sDefault = null)
|
||||
{
|
||||
$sDefault = Dict::S('Core:AttributeObsolescenceDate/Label', $sDefault);
|
||||
|
||||
return parent::GetLabel($sDefault);
|
||||
}
|
||||
|
||||
public function GetDescription($sDefault = null)
|
||||
{
|
||||
$sDefault = Dict::S('Core:AttributeObsolescenceDate/Label+', $sDefault);
|
||||
|
||||
return parent::GetDescription($sDefault);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user