mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-14 16:04:10 +01:00
Compare commits
779 Commits
support/2.
...
2.6.4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c5b1f02d2b | ||
|
|
f81ab4d71a | ||
|
|
b88b9dabdb | ||
|
|
06b17e82db | ||
|
|
2add79a473 | ||
|
|
3a37e24496 | ||
|
|
b1d703bff3 | ||
|
|
a3a34a94e7 | ||
|
|
6edc365685 | ||
|
|
4b7f736af0 | ||
|
|
016fbaed36 | ||
|
|
bfcd137e52 | ||
|
|
f9af8fc912 | ||
|
|
bd083d632f | ||
|
|
bd9da07734 | ||
|
|
50a8af4082 | ||
|
|
6a1125875b | ||
|
|
4f0e3430c0 | ||
|
|
5fce2a2c1c | ||
|
|
03b8ed5ce4 | ||
|
|
31a34c247c | ||
|
|
a625733885 | ||
|
|
d7fad4b646 | ||
|
|
f4d538ef6c | ||
|
|
aadb605dec | ||
|
|
f63f2bd445 | ||
|
|
fefd9aae95 | ||
|
|
878b87b68c | ||
|
|
14ae9f0809 | ||
|
|
33903f570b | ||
|
|
127809a836 | ||
|
|
a93be39aeb | ||
|
|
7c93d116ec | ||
|
|
f948d6e026 | ||
|
|
a222ead43c | ||
|
|
d6bfbbcd30 | ||
|
|
17df9d0f9d | ||
|
|
5c341138e1 | ||
|
|
56b9eb6cf3 | ||
|
|
db20244212 | ||
|
|
6f9f74e72f | ||
|
|
8070d5b9b7 | ||
|
|
6197ecbaf4 | ||
|
|
ca585d3f42 | ||
|
|
9e5d668c02 | ||
|
|
051656f295 | ||
|
|
9a51a44549 | ||
|
|
d04102bab3 | ||
|
|
c723d19e01 | ||
|
|
dac77e0606 | ||
|
|
02b98543d9 | ||
|
|
519aaadd9a | ||
|
|
fe27fef530 | ||
|
|
72dbb6f937 | ||
|
|
ccb29d10ae | ||
|
|
e479775833 | ||
|
|
86a7192f5a | ||
|
|
4a1be13904 | ||
|
|
0f3347f64d | ||
|
|
6564d84a2f | ||
|
|
f4747c5cef | ||
|
|
1e92c2f28a | ||
|
|
e4b097b196 | ||
|
|
85653c9ffc | ||
|
|
da5d8b20fa | ||
|
|
9a5a5f858f | ||
|
|
a0cd281c42 | ||
|
|
6bb5606c00 | ||
|
|
a6ceb88fca | ||
|
|
7bb7a94fbc | ||
|
|
e4324cedb4 | ||
|
|
07781c7c9d | ||
|
|
ea58a807fc | ||
|
|
fb6806a1c1 | ||
|
|
166451c4e9 | ||
|
|
7c1290f684 | ||
|
|
179c774ba8 | ||
|
|
e886d80de6 | ||
|
|
3791b2dd24 | ||
|
|
12c916f4e5 | ||
|
|
ba7e00e130 | ||
|
|
bada955725 | ||
|
|
f9e18675f3 | ||
|
|
22416cc0be | ||
|
|
ec086ad94a | ||
|
|
17d4b570e8 | ||
|
|
2dfad12553 | ||
|
|
26dcaa0ded | ||
|
|
b5d3ddb7e3 | ||
|
|
8b178914b3 | ||
|
|
ce6fd4d775 | ||
|
|
9c75cb4537 | ||
|
|
633fa343a5 | ||
|
|
a1d01e252b | ||
|
|
b157fad0b6 | ||
|
|
70d2bb163c | ||
|
|
fae6c89e9a | ||
|
|
89d310258b | ||
|
|
a58529f46c | ||
|
|
12a2035791 | ||
|
|
b1ff7f0e9b | ||
|
|
3c4fe338b6 | ||
|
|
6159ab33b7 | ||
|
|
77f757995e | ||
|
|
99f398a87e | ||
|
|
87ee731dbe | ||
|
|
f2380ae354 | ||
|
|
2d039af278 | ||
|
|
831879fe37 | ||
|
|
ea1dfd8933 | ||
|
|
24519c69a4 | ||
|
|
b5c4801beb | ||
|
|
3eff8f62b1 | ||
|
|
b83e5e2b72 | ||
|
|
cac0da4e3d | ||
|
|
7e064365eb | ||
|
|
4918b9c83a | ||
|
|
ed95f4e05f | ||
|
|
693fdfdc5b | ||
|
|
01108ca83d | ||
|
|
3d5b7197f6 | ||
|
|
54c027823b | ||
|
|
f63aceeabe | ||
|
|
243aab1030 | ||
|
|
22dba9ae07 | ||
|
|
02857a86fd | ||
|
|
d663d01798 | ||
|
|
3602163b38 | ||
|
|
83bb3b6d72 | ||
|
|
75737b4ffe | ||
|
|
a5340917a7 | ||
|
|
914d19e7e4 | ||
|
|
eb49dbbdc8 | ||
|
|
912bab5a43 | ||
|
|
94092f445f | ||
|
|
856c037bb0 | ||
|
|
388896b963 | ||
|
|
1d8addf675 | ||
|
|
c8c3d32b18 | ||
|
|
bc841dd239 | ||
|
|
9c71d32964 | ||
|
|
d199d84b27 | ||
|
|
24aca83de4 | ||
|
|
5a0edb5c39 | ||
|
|
38951fab1a | ||
|
|
1224570fa5 | ||
|
|
733c908e34 | ||
|
|
377b4b038c | ||
|
|
3f7fd6f9f9 | ||
|
|
1cb36621a1 | ||
|
|
ddd9188eb7 | ||
|
|
02254eac67 | ||
|
|
ebe026b2e9 | ||
|
|
efc7c5b0f4 | ||
|
|
f68a77450d | ||
|
|
1f7923beae | ||
|
|
a2d34d1779 | ||
|
|
48f15d7781 | ||
|
|
a89bca4626 | ||
|
|
63a36fd0f6 | ||
|
|
7cf7e55454 | ||
|
|
5067c867b8 | ||
|
|
7bb49893ee | ||
|
|
818b4d08da | ||
|
|
f438fbd06f | ||
|
|
297a45d477 | ||
|
|
17fe9dfd5f | ||
|
|
9d0cbca497 | ||
|
|
a613b4b101 | ||
|
|
c989e2eda5 | ||
|
|
c6fd381b01 | ||
|
|
a784661025 | ||
|
|
1f9a638bc1 | ||
|
|
43b0747b83 | ||
|
|
84767692b0 | ||
|
|
d484614c0f | ||
|
|
b403bace6c | ||
|
|
0b751a9dd6 | ||
|
|
8f434cad08 | ||
|
|
f83292fccc | ||
|
|
90e128f951 | ||
|
|
8efc372a68 | ||
|
|
257fb4d036 | ||
|
|
97261820f6 | ||
|
|
2f83a2168c | ||
|
|
c0275eec21 | ||
|
|
2bd7a7b5f8 | ||
|
|
505aad1e89 | ||
|
|
00c59b7f2c | ||
|
|
dbcde14f5e | ||
|
|
a6f4adfed8 | ||
|
|
effaba42d0 | ||
|
|
340cacc691 | ||
|
|
a85bedd31c | ||
|
|
23269eab77 | ||
|
|
27ad2e2169 | ||
|
|
5d09841cd5 | ||
|
|
11ec46c18b | ||
|
|
2b563d4fc8 | ||
|
|
2773a8bf2f | ||
|
|
ad36011fc8 | ||
|
|
b82b095f58 | ||
|
|
2f5c810276 | ||
|
|
d90e094d4d | ||
|
|
352f8cee10 | ||
|
|
9f3332b2f2 | ||
|
|
2b71621628 | ||
|
|
5349fc6f4b | ||
|
|
1665b12b86 | ||
|
|
1bbed99636 | ||
|
|
bb6bd61c37 | ||
|
|
b51b5582a0 | ||
|
|
27b1b1f8a8 | ||
|
|
a45e543eac | ||
|
|
50235bbb04 | ||
|
|
a2ddb30f78 | ||
|
|
75fbb831c9 | ||
|
|
3219957eed | ||
|
|
44671a5085 | ||
|
|
bc4873dfe5 | ||
|
|
92657951c7 | ||
|
|
8b2c18ab8c | ||
|
|
18999f29c5 | ||
|
|
e8075bf5fd | ||
|
|
5338325a73 | ||
|
|
4d3810a10d | ||
|
|
672bc471be | ||
|
|
3089cbc2bc | ||
|
|
ce9416d887 | ||
|
|
473d1fb756 | ||
|
|
b880ca05a5 | ||
|
|
cbc9784d21 | ||
|
|
16cb1bbbbf | ||
|
|
a1c2b809ba | ||
|
|
c9691457b8 | ||
|
|
9ef6c78395 | ||
|
|
81f70c4c58 | ||
|
|
869f590bf4 | ||
|
|
3b6aa7eaf5 | ||
|
|
53ef2b0b5d | ||
|
|
4dfe6fc817 | ||
|
|
260143050e | ||
|
|
6adde38399 | ||
|
|
76a40b2f45 | ||
|
|
77c2537df7 | ||
|
|
6a88f622ad | ||
|
|
9b5d8b8a01 | ||
|
|
b4448c5bb9 | ||
|
|
7faf3258f7 | ||
|
|
7c0d03ea3b | ||
|
|
d1837377a4 | ||
|
|
1c3a503a82 | ||
|
|
daafa9123c | ||
|
|
5a1b6e43c9 | ||
|
|
81d502cae8 | ||
|
|
4a99ed2ad8 | ||
|
|
7016724abc | ||
|
|
0a8e3f099e | ||
|
|
45910dc115 | ||
|
|
afd6428411 | ||
|
|
7eb419507b | ||
|
|
b4a6d378ab | ||
|
|
44b7821015 | ||
|
|
52ac819c1f | ||
|
|
c4ba1d55ac | ||
|
|
85acac60c7 | ||
|
|
f54da5f9a6 | ||
|
|
36d47c2274 | ||
|
|
bd082c0a6e | ||
|
|
29dd196193 | ||
|
|
80a8f7a888 | ||
|
|
7f497fe3be | ||
|
|
53fe826f9f | ||
|
|
56b4ecb4ce | ||
|
|
d17717e4b5 | ||
|
|
68da3a4aad | ||
|
|
855480fd7b | ||
|
|
79200e8f96 | ||
|
|
540bc3a54b | ||
|
|
35752a8041 | ||
|
|
86dce21849 | ||
|
|
fca5a625d2 | ||
|
|
2766fad61a | ||
|
|
c6da1db72b | ||
|
|
843c06b007 | ||
|
|
7cf7628b8f | ||
|
|
41b096ba76 | ||
|
|
2a4bd4b0dc | ||
|
|
f4f5281769 | ||
|
|
a4a09cd8c7 | ||
|
|
831b18b4d2 | ||
|
|
e4e5f627c4 | ||
|
|
53e532cbaf | ||
|
|
3fa0cbf0fe | ||
|
|
af8b06dda6 | ||
|
|
72e2473444 | ||
|
|
6e31a040b2 | ||
|
|
6c07688c34 | ||
|
|
598c22a285 | ||
|
|
d392b9c0f6 | ||
|
|
387c166985 | ||
|
|
9115bc118d | ||
|
|
aca11ac966 | ||
|
|
c15d626095 | ||
|
|
79d00b9fe6 | ||
|
|
a92e2fd882 | ||
|
|
7ed51984c7 | ||
|
|
cdf11a3485 | ||
|
|
bbefd22950 | ||
|
|
e08369122d | ||
|
|
0ce0572c40 | ||
|
|
9d19556419 | ||
|
|
67c0e0eb1c | ||
|
|
c5d0dd05b9 | ||
|
|
4e1f877ab4 | ||
|
|
19d4de482d | ||
|
|
122c3a9542 | ||
|
|
15d9ba9906 | ||
|
|
95a22a1a7e | ||
|
|
5309aa225a | ||
|
|
c0cd450c5f | ||
|
|
1b4b71cb35 | ||
|
|
f37f3c4c22 | ||
|
|
83b3fb80d5 | ||
|
|
c242f90440 | ||
|
|
e4912ee175 | ||
|
|
83e1f35f9c | ||
|
|
c42333d085 | ||
|
|
c4c0b0f630 | ||
|
|
aec3c34eea | ||
|
|
c4ff20b9fb | ||
|
|
c7ce35a877 | ||
|
|
5ccfa24b27 | ||
|
|
1c6a6edf5a | ||
|
|
a659de9c9b | ||
|
|
29e28dedf1 | ||
|
|
0acc0b4a74 | ||
|
|
c300e46480 | ||
|
|
0a3f076335 | ||
|
|
12d9551845 | ||
|
|
0d6c799f9c | ||
|
|
a395f5b63c | ||
|
|
2e46fa50b3 | ||
|
|
f9bb2e7a14 | ||
|
|
57e8b9faaf | ||
|
|
c737b83eb5 | ||
|
|
5c91a1a612 | ||
|
|
0c49641094 | ||
|
|
99e909dae4 | ||
|
|
ecf34b47cb | ||
|
|
949b4495fc | ||
|
|
bd7e0174f3 | ||
|
|
ac89b2dc44 | ||
|
|
7e3fceb7dc | ||
|
|
b28ed08a85 | ||
|
|
a488c42dca | ||
|
|
fb233709e0 | ||
|
|
9169cced20 | ||
|
|
1db9708624 | ||
|
|
52b42d0210 | ||
|
|
67f5f09530 | ||
|
|
b9e0747825 | ||
|
|
e44ed248ef | ||
|
|
b0c120d7fd | ||
|
|
177b6d1757 | ||
|
|
ff39b7bc51 | ||
|
|
7401e88844 | ||
|
|
b1e1e29254 | ||
|
|
ffac3250af | ||
|
|
e9fb885d34 | ||
|
|
b87037d187 | ||
|
|
a97680fb04 | ||
|
|
798e526010 | ||
|
|
d344478b48 | ||
|
|
b898a09c4c | ||
|
|
17589e060a | ||
|
|
7867cc1dca | ||
|
|
114b18d7c8 | ||
|
|
5baff6257b | ||
|
|
8264d21520 | ||
|
|
8bd10a2d11 | ||
|
|
cce88f09b0 | ||
|
|
26475ad10f | ||
|
|
c1a81e4f0d | ||
|
|
4a5cb23730 | ||
|
|
f0e5128fb5 | ||
|
|
63b08b0e70 | ||
|
|
4072ed09ac | ||
|
|
70137808f0 | ||
|
|
36ade3b15c | ||
|
|
6b5f32611d | ||
|
|
43bfe06882 | ||
|
|
29df8f8f92 | ||
|
|
405b1b8e6f | ||
|
|
b050210737 | ||
|
|
ed02e3522e | ||
|
|
a327b5fb5e | ||
|
|
f9b2fda092 | ||
|
|
0d082bf378 | ||
|
|
d8cef95d56 | ||
|
|
2258e8c652 | ||
|
|
5e19d338b9 | ||
|
|
14ecfc4ce8 | ||
|
|
170d84d635 | ||
|
|
a962f6535e | ||
|
|
a4055c4a74 | ||
|
|
9ed550ee7f | ||
|
|
00bd7583f7 | ||
|
|
e4619fbc0f | ||
|
|
518d94f5f3 | ||
|
|
389a1791d7 | ||
|
|
54eb41b66f | ||
|
|
ede2673ba5 | ||
|
|
dd50c99ec4 | ||
|
|
357555e507 | ||
|
|
1f6a51b31f | ||
|
|
6d4cf71197 | ||
|
|
87f898d29d | ||
|
|
d5576522ae | ||
|
|
6addd9acec | ||
|
|
9b5942bf4e | ||
|
|
9faa4e4cbd | ||
|
|
8b80bd71e7 | ||
|
|
8989206461 | ||
|
|
89a21c8e44 | ||
|
|
a7ec6e5ca0 | ||
|
|
a08675352a | ||
|
|
7158b1f787 | ||
|
|
3925ad252f | ||
|
|
f3fd47a792 | ||
|
|
af92f58265 | ||
|
|
81b5f18579 | ||
|
|
184c0cb84b | ||
|
|
c892862822 | ||
|
|
b61d1feec4 | ||
|
|
a73ff16642 | ||
|
|
7763983ef4 | ||
|
|
35f7fe98ae | ||
|
|
533acbde8d | ||
|
|
d72da422de | ||
|
|
891608f812 | ||
|
|
e66da81a20 | ||
|
|
cae0cd00c2 | ||
|
|
32fc87023c | ||
|
|
0021482c1b | ||
|
|
276427e3df | ||
|
|
7b49bde3ad | ||
|
|
a94d940bd3 | ||
|
|
313c3c6fc3 | ||
|
|
de86f71c90 | ||
|
|
098b0531d8 | ||
|
|
34552214bf | ||
|
|
d61a8ba160 | ||
|
|
84ebca58ac | ||
|
|
def4c54d26 | ||
|
|
027b0fcff7 | ||
|
|
fc0cb44a84 | ||
|
|
574d72b0e7 | ||
|
|
cd5e1afb2b | ||
|
|
0298d6bc19 | ||
|
|
60d2fd4f7e | ||
|
|
5faa0ffe08 | ||
|
|
705ce02580 | ||
|
|
78c674a989 | ||
|
|
84d9be3293 | ||
|
|
30c622052e | ||
|
|
ada56da63e | ||
|
|
21c5638e1e | ||
|
|
02da84b4cf | ||
|
|
ebb5ede613 | ||
|
|
db4b8b2f43 | ||
|
|
c17f7caa29 | ||
|
|
d7df975971 | ||
|
|
f3f70d6296 | ||
|
|
256d4e2cb3 | ||
|
|
fb31c9006a | ||
|
|
bf000e6a89 | ||
|
|
94b4f10277 | ||
|
|
15671f6dd4 | ||
|
|
2460d2112f | ||
|
|
709badd0f7 | ||
|
|
99153d02ee | ||
|
|
4347b2c5ff | ||
|
|
c13b6ea13a | ||
|
|
6e5d4834f1 | ||
|
|
9f489d8a59 | ||
|
|
c9be1a8e71 | ||
|
|
c1e2f35c96 | ||
|
|
462148a12f | ||
|
|
7e4edc6e3a | ||
|
|
452e7cce01 | ||
|
|
cb7b5dfffb | ||
|
|
0a34fb7a7a | ||
|
|
460337954b | ||
|
|
74a8c3f5bd | ||
|
|
3347d32f2a | ||
|
|
4c2be6b2c5 | ||
|
|
860bb6d615 | ||
|
|
950ffcde2b | ||
|
|
0580c71749 | ||
|
|
c66b0bea41 | ||
|
|
7281bd4a1a | ||
|
|
c9d73fc0c8 | ||
|
|
8720ac2b08 | ||
|
|
33e8b6a64c | ||
|
|
d7cf339ab5 | ||
|
|
714fada9f0 | ||
|
|
d36fd6a47d | ||
|
|
c0d83e96d8 | ||
|
|
3da6251cc7 | ||
|
|
1bf39aa092 | ||
|
|
3387d8fdd2 | ||
|
|
9f926fccd8 | ||
|
|
e9a77c798e | ||
|
|
29691a09fe | ||
|
|
cb73c2a3f9 | ||
|
|
713a41909b | ||
|
|
9972e253d5 | ||
|
|
55309be9a1 | ||
|
|
fd75f3af28 | ||
|
|
af7e5eb03e | ||
|
|
b97ce7a25f | ||
|
|
89d617c152 | ||
|
|
4595c565cc | ||
|
|
8f55d4054a | ||
|
|
2e255b10a7 | ||
|
|
cf9c1b52ed | ||
|
|
d3b3c44cbd | ||
|
|
edb25b6dca | ||
|
|
4bf748641d | ||
|
|
16a6b70708 | ||
|
|
40355cb2d0 | ||
|
|
b52aaaadf2 | ||
|
|
f55c0aa1c9 | ||
|
|
333c51b0f9 | ||
|
|
46dee2919e | ||
|
|
799618dee7 | ||
|
|
96aaa0d8e1 | ||
|
|
5556e3efec | ||
|
|
d8b2d4435a | ||
|
|
a4315b4789 | ||
|
|
3e8dd61607 | ||
|
|
1d28a67d21 | ||
|
|
3a551e9cec | ||
|
|
cf6693a534 | ||
|
|
8c5c275952 | ||
|
|
5fa4b4cb88 | ||
|
|
58525f247e | ||
|
|
d78f19525e | ||
|
|
5559c8205f | ||
|
|
2a6a97526d | ||
|
|
1adea8f014 | ||
|
|
29177ec86b | ||
|
|
741e88e1f0 | ||
|
|
66bddc5730 | ||
|
|
6eaa7c0530 | ||
|
|
b257fae03e | ||
|
|
2d24324dea | ||
|
|
ec597f697a | ||
|
|
3bed62a473 | ||
|
|
b5f7227ecd | ||
|
|
615adf8281 | ||
|
|
cb7bb3242a | ||
|
|
4b08eea998 | ||
|
|
01551942b3 | ||
|
|
720d334053 | ||
|
|
9397d1ac2e | ||
|
|
1530bb89fe | ||
|
|
f09683949d | ||
|
|
e1f96974bb | ||
|
|
1fc261937f | ||
|
|
a94211d3d3 | ||
|
|
534f6b6a54 | ||
|
|
901764bf70 | ||
|
|
e67d6e8a80 | ||
|
|
16476f736a | ||
|
|
e9ecd89cda | ||
|
|
55036511ab | ||
|
|
3cf5d31f5d | ||
|
|
84ae36cf1a | ||
|
|
00515ac14a | ||
|
|
245612d0eb | ||
|
|
ae6e3b4f17 | ||
|
|
12a3f1c36c | ||
|
|
1af1e92b60 | ||
|
|
a1ad7a5def | ||
|
|
398d1aa820 | ||
|
|
38278f3432 | ||
|
|
baf4662ed8 | ||
|
|
cf07c9f1a2 | ||
|
|
446bd0ad1f | ||
|
|
3d5e46faac | ||
|
|
b8fba8997a | ||
|
|
a07c81d0d9 | ||
|
|
0252d091ca | ||
|
|
18d9ada58d | ||
|
|
055d2cc62c | ||
|
|
e15c5c58d8 | ||
|
|
b734aca4d0 | ||
|
|
e495b36dfb | ||
|
|
cdcfe03d67 | ||
|
|
2c6dc20046 | ||
|
|
a8c3b7ac2e | ||
|
|
98572c6efb | ||
|
|
70840c53aa | ||
|
|
9fbd27f3a8 | ||
|
|
c3c1897258 | ||
|
|
5403219746 | ||
|
|
fb08903a8a | ||
|
|
416005654e | ||
|
|
1debf77ab4 | ||
|
|
f1a8bb08da | ||
|
|
7edff12bbf | ||
|
|
34d601f49c | ||
|
|
ec38473d88 | ||
|
|
875c77ae65 | ||
|
|
75e24f9f79 | ||
|
|
16a4662129 | ||
|
|
1eda1eb9de | ||
|
|
d981fd35ef | ||
|
|
6f1dc44932 | ||
|
|
95b929dd27 | ||
|
|
0c75b98f48 | ||
|
|
ecc5a0bf8a | ||
|
|
d9315bec84 | ||
|
|
d1ee7f4353 | ||
|
|
979095337b | ||
|
|
34b528b1f4 | ||
|
|
5ea056a3fc | ||
|
|
2ba31244c2 | ||
|
|
3ea16694b4 | ||
|
|
35e872310d | ||
|
|
b86b24d444 | ||
|
|
45e1a6ffd6 | ||
|
|
c87f001956 | ||
|
|
1fc3b3a4ed | ||
|
|
c706a2d77c | ||
|
|
8577fc6701 | ||
|
|
ead3067d49 | ||
|
|
4772b8c5bb | ||
|
|
6817cfbeea | ||
|
|
f851238eab | ||
|
|
79157c465a | ||
|
|
64438f6b6d | ||
|
|
f2b914a4c5 | ||
|
|
da71004898 | ||
|
|
e9019b294a | ||
|
|
e2c3ea22e4 | ||
|
|
c7f3f20229 | ||
|
|
46dc024335 | ||
|
|
34c68cfef0 | ||
|
|
d6a564a38b | ||
|
|
31c69088ca | ||
|
|
49bb8fd515 | ||
|
|
b8f8a0d455 | ||
|
|
374e34a8b8 | ||
|
|
7ef1d72314 | ||
|
|
5666a3d74c | ||
|
|
8004b411da | ||
|
|
e473c46dc3 | ||
|
|
148309245b | ||
|
|
5dc39fe068 | ||
|
|
47c7a3c5e3 | ||
|
|
85b7e86e58 | ||
|
|
f871581997 | ||
|
|
3fca465f1d | ||
|
|
7955dd86f4 | ||
|
|
40a4e6d7b0 | ||
|
|
bef4ac83a4 | ||
|
|
bde83fc705 | ||
|
|
cad18bee73 | ||
|
|
98e5eaa4e0 | ||
|
|
3129e94363 | ||
|
|
7ac0e50bd9 | ||
|
|
7d502fae23 | ||
|
|
894eeef140 | ||
|
|
7991069282 | ||
|
|
39f3972a24 | ||
|
|
fc0e5ecd3b | ||
|
|
8897d9f82b | ||
|
|
1329b5f684 | ||
|
|
e58bc738d0 | ||
|
|
af63579f31 | ||
|
|
55fad3a9ec | ||
|
|
3250e0a1e6 | ||
|
|
8df287f45e | ||
|
|
f458a77449 | ||
|
|
1953c05b33 | ||
|
|
a03c553000 | ||
|
|
ecdc4076d9 | ||
|
|
cd2ea3793e | ||
|
|
d40ffd944f | ||
|
|
0ee4b52baa | ||
|
|
5e7db7a27e | ||
|
|
9631021f84 | ||
|
|
157193c831 | ||
|
|
1415f12506 | ||
|
|
4df497a768 | ||
|
|
9a13eb0f90 | ||
|
|
eaa49bce05 | ||
|
|
96334d859a | ||
|
|
13855b1501 | ||
|
|
277b24e2f0 | ||
|
|
abb2a2a6e2 | ||
|
|
961f5fd387 | ||
|
|
bdb62de81c | ||
|
|
422a850792 | ||
|
|
1dfcc77098 | ||
|
|
13097d7e0e | ||
|
|
ea9b7eddde | ||
|
|
07056613e5 | ||
|
|
4d45793ec7 | ||
|
|
4718133ab6 | ||
|
|
ba518fa975 | ||
|
|
0311e78690 | ||
|
|
9db47428db | ||
|
|
84dc3c2093 | ||
|
|
7d37b06555 | ||
|
|
6e6a89fb8c | ||
|
|
135d9c5e55 | ||
|
|
dd46048ea6 | ||
|
|
8fe38b03f6 | ||
|
|
0adadeb280 | ||
|
|
775a5122c9 | ||
|
|
5099060be2 | ||
|
|
201c93e20a | ||
|
|
c852d91a72 | ||
|
|
a3c6e62bd5 | ||
|
|
8cd18fe190 | ||
|
|
5e1452f9b9 | ||
|
|
b76de65886 | ||
|
|
48b3bd8bf3 | ||
|
|
ab1715edec | ||
|
|
3589783ee1 | ||
|
|
af43e22f03 | ||
|
|
956f6403b8 | ||
|
|
82ed1853fa | ||
|
|
eb0403945b | ||
|
|
3126af94ac | ||
|
|
e71ad536a9 | ||
|
|
d0322b471d | ||
|
|
a6af11e644 | ||
|
|
1809180d41 | ||
|
|
9612b1b9e9 | ||
|
|
526d4c4d15 | ||
|
|
3f4c824fd5 | ||
|
|
9c25feb67c | ||
|
|
e31faf81a9 | ||
|
|
6eb13c24aa | ||
|
|
dd20017b0a | ||
|
|
6630051ef3 | ||
|
|
a66d91c507 | ||
|
|
2f34f0458b | ||
|
|
076abc8ae7 | ||
|
|
5134e57109 | ||
|
|
3d1ccf2028 | ||
|
|
60b980fbff | ||
|
|
df20f1b5ab | ||
|
|
27144f07b1 | ||
|
|
8135fdb9d2 | ||
|
|
985ad18048 | ||
|
|
768ed2666d | ||
|
|
c289a53ed3 | ||
|
|
5c206718c8 | ||
|
|
d7f18e879a | ||
|
|
4881a2c274 | ||
|
|
5eb5fa05bc | ||
|
|
c7e0f36d7c | ||
|
|
54d54ca78e | ||
|
|
4cd591f81c | ||
|
|
d21d732545 | ||
|
|
ea4854d239 | ||
|
|
7ca95b9413 | ||
|
|
00d0d383f8 | ||
|
|
401a8cdd77 | ||
|
|
b2384855fd | ||
|
|
602c087c29 | ||
|
|
0d96ed5436 | ||
|
|
97fa3ac3b3 |
103
.doc/README.md
Normal file
103
.doc/README.md
Normal file
@@ -0,0 +1,103 @@
|
||||
# Phpdoc dokuwiki template
|
||||
This directory contains a template rendering iTop phpdoc as wiki pages.
|
||||
|
||||
|
||||
conventional tag that you should use:
|
||||
* `@internal` : exclude from the documentation.
|
||||
* `@api` : it means that a method is an api, thus it may be interacted with.
|
||||
* `@see` : it points to another documented method
|
||||
* `@link` : external url
|
||||
* if you point to another page of the wiki, please use relative links.
|
||||
* `@example` : let you provide example of code
|
||||
* `@param`, `@return`, `@throws`, ...
|
||||
|
||||
|
||||
## Special instructions
|
||||
|
||||
some tags where added :
|
||||
* `@api-advanced`: it means that a method is an `@api` but mark it also as "complex" to use
|
||||
* `@overwritable-hook`: used to mark a method as "designed to be extended"
|
||||
* `@extension-hook`: not used for now
|
||||
* `@phpdoc-tuning-exclude-inherited`: once this tag is present on a class, it's inherited methods won't be showed.
|
||||
|
||||
|
||||
### known limitations:
|
||||
#### `@see` tags must be very specific:
|
||||
* always prefix class members with `ClassName::`
|
||||
* for methods always suffix them with `()`,
|
||||
* do not reference variables since they are not documented. If you have to, always prefix them with `$`
|
||||
|
||||
examples:
|
||||
```
|
||||
/**
|
||||
* @see DBObject
|
||||
* @see DBObject::Get()
|
||||
* @see DBObject::$foo
|
||||
*/
|
||||
```
|
||||
|
||||
#### Do not use inline tags, they do not work properly, example:
|
||||
```
|
||||
/**
|
||||
* This is a texts with ans inline tag {@see [FQSEN] [<description>]} it must never be used
|
||||
*/
|
||||
```
|
||||
|
||||
#### The `@example` tag must respect this very precise syntax
|
||||
* the sentence in the first line (next to the tag) is the title, it must be enclose by double quotes
|
||||
* the following lines are the sample code.
|
||||
* 💔 since we simply hack the official tag, this syntax must be respected carefully 💔
|
||||
example:
|
||||
```
|
||||
/**
|
||||
* @example "This is the title of the multiline example"
|
||||
* $foo = DBObject::Get('foo');
|
||||
* DBObject::Set('foo', ++$foo);
|
||||
*/
|
||||
```
|
||||
|
||||
## How content is included into the documentation
|
||||
|
||||
**For a class** those requirements have to be respected:
|
||||
- the file containing the class must be listed in `/phpdoc/files/file[]` of `.doc/phpdoc-objects-manipulation.dist.xml`
|
||||
- the class **must not** have the tag `@internal`
|
||||
- the class **must** have at least one of: `@api`, `@api-advanced`, `@overwritable-hook`, `@extension-hook`
|
||||
|
||||
Then, **for a method** of an eligible class:
|
||||
- **public** methods **must** have at least one of: `@api`, `@api-advanced`, `@overwritable-hook`, `@extension-hook`
|
||||
- **protected** methods **must** have at least one of: `@overwritable-hook`, `@extension-hook`
|
||||
- **private** methods are **always excluded**
|
||||
|
||||
**Class properties** and **constants** are never documented (this is subject to change).
|
||||
|
||||
|
||||
|
||||
|
||||
## A note about the rendering engine
|
||||
|
||||
:notebook: as spaces are used to mark code, the templates (`.doc/phpdoc-templates/combodo-wiki/*`) have very few indentation, thus they are awful to read (sorry).
|
||||
|
||||
|
||||
|
||||
|
||||
## Installation
|
||||
```
|
||||
composer require phpdocumentor/phpdocumentor:~2 --dev
|
||||
```
|
||||
|
||||
## Generation
|
||||
`.doc/bin/build-doc-object-manipulation` and `.doc/bin/build-doc-extensions` contains examples of doc. generation, beware: they have to be called from iTop root directory:
|
||||
```shell
|
||||
cd /path/to/itop/
|
||||
./.doc/bin/build-doc-object-manipulation
|
||||
```
|
||||
|
||||
the resulting documentation is written into `data/phpdocumentor/output`
|
||||
|
||||
|
||||
## Dokuwiki requirements
|
||||
* the template uses the [wrap plugin](https://www.dokuwiki.org/plugin:wrap).
|
||||
* the generated files have to be placed under an arbitrary directory of `[/path/to/dokuwiki]/data/pages`.
|
||||
* the html has to be activated [config:htmlok](https://www.dokuwiki.org/config:htmlok)
|
||||
* the generated files have to be in lowercase
|
||||
|
||||
7
.doc/bin/build-doc-extensions
Executable file
7
.doc/bin/build-doc-extensions
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/bin/sh -x
|
||||
|
||||
rm -rf /tmp/phpdoc-twig-cache/ && rm -rf data/phpdocumentor/output/extensions/ && rm -rf data/phpdocumentor/temp/extensions/ && vendor/bin/phpdoc -c .doc/phpdoc-extensions.dist.xml -vvv
|
||||
|
||||
# now wee need to lowercase every generated file because dokuwiki can't handle uppercase
|
||||
cd data/phpdocumentor/output/extensions/
|
||||
for i in $( ls | grep [A-Z] ); do mv -i $i `echo $i | tr 'A-Z' 'a-z'`; done
|
||||
8
.doc/bin/build-doc-object-manipulation
Executable file
8
.doc/bin/build-doc-object-manipulation
Executable file
@@ -0,0 +1,8 @@
|
||||
#!/bin/sh -x
|
||||
|
||||
rm -rf /tmp/phpdoc-twig-cache/ && rm -rf data/phpdocumentor/output/objects-manipulation/ && rm -rf data/phpdocumentor/temp/objects-manipulation/ && vendor/bin/phpdoc -c .doc/phpdoc-objects-manipulation.dist.xml -vvv
|
||||
|
||||
|
||||
# now wee need to lowercase every generated file because dokuwiki can't handle uppercase
|
||||
cd data/phpdocumentor/output/objects-manipulation/
|
||||
for i in $( ls | grep [A-Z] ); do mv -i $i `echo $i | tr 'A-Z' 'a-z'`; done
|
||||
20
.doc/phpdoc-extensions.dist.xml
Executable file
20
.doc/phpdoc-extensions.dist.xml
Executable file
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<phpdoc>
|
||||
<title><![CDATA[iTop extensions]]></title>
|
||||
|
||||
<parser>
|
||||
<target>../data/phpdocumentor/temp/extensions</target>
|
||||
</parser>
|
||||
|
||||
<transformer>
|
||||
<target>../data/phpdocumentor/output/extensions</target>
|
||||
</transformer>
|
||||
|
||||
<transformations>
|
||||
<template name="phpdoc-templates/combodo-wiki"/>
|
||||
</transformations>
|
||||
|
||||
<files>
|
||||
<file>../application/applicationextension.inc.php</file>
|
||||
</files>
|
||||
</phpdoc>
|
||||
58
.doc/phpdoc-objects-manipulation.dist.xml
Executable file
58
.doc/phpdoc-objects-manipulation.dist.xml
Executable file
@@ -0,0 +1,58 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<phpdoc>
|
||||
|
||||
<!--
|
||||
/**
|
||||
The documentation of this file can be found here : https://docs.phpdoc.org/references/configuration.html
|
||||
it has to be completed by the CLI parameters documentation which is more comprehensive: https://docs.phpdoc.org/references/commands/project_run.html#usage
|
||||
|
||||
usage:
|
||||
vendor/bin/phpdoc -c phpdoc-objects-manipulation.dist.xml
|
||||
|
||||
*/
|
||||
-->
|
||||
|
||||
<title><![CDATA[iTop's objects manipulation API]]></title>
|
||||
|
||||
<parser>
|
||||
<default-package-name>iTopORM</default-package-name>
|
||||
<target>../data/phpdocumentor/temp/objects-manipulation</target>
|
||||
<visibility>public,protected</visibility>
|
||||
<markers>
|
||||
<!--<item>TODO</item>-->
|
||||
<!--<item>FIXME</item>-->
|
||||
</markers>
|
||||
<extensions>
|
||||
<extension>php</extension>
|
||||
</extensions>
|
||||
</parser>
|
||||
|
||||
<transformer>
|
||||
<target>../data/phpdocumentor/output/objects-manipulation</target>
|
||||
</transformer>
|
||||
|
||||
<transformations>
|
||||
<template name="phpdoc-templates/combodo-wiki"/>
|
||||
</transformations>
|
||||
|
||||
<!--<logging>-->
|
||||
<!--<level>warn</level>-->
|
||||
<!--<paths>-->
|
||||
<!--<!–<default>data/phpdocumentor/log/objects-manipulation/{DATE}.log</default>–>-->
|
||||
<!--<!–<errors>data/phpdocumentor/log/objects-manipulation/{DATE}.errors.log</errors>–>-->
|
||||
|
||||
<!--<default>{APP_ROOT}/data/log/{DATE}.log</default>-->
|
||||
<!--<errors>{APP_ROOT}/data/log/{DATE}.errors.log</errors>-->
|
||||
<!--</paths>-->
|
||||
<!--</logging>-->
|
||||
|
||||
<files>
|
||||
<file>../core/dbobject.class.php</file>
|
||||
<file>../core/dbobjectsearch.class.php</file>
|
||||
<file>../core/metamodel.class.php</file>
|
||||
<file>../core/dbobjectset.class.php</file>
|
||||
<file>../core/dbsearch.class.php</file>
|
||||
<file>../core/dbunionsearch.class.php</file>
|
||||
</files>
|
||||
|
||||
</phpdoc>
|
||||
0
.doc/phpdoc-templates/.placeholder
Normal file
0
.doc/phpdoc-templates/.placeholder
Normal file
136
.doc/phpdoc-templates/combodo-wiki/class.txt.twig
Normal file
136
.doc/phpdoc-templates/combodo-wiki/class.txt.twig
Normal file
@@ -0,0 +1,136 @@
|
||||
{% extends 'layout.txt.twig' %}
|
||||
|
||||
{% block content %}
|
||||
<wrap button>[[start|🔙 Back]]</wrap>
|
||||
|
||||
{% if node.tags['internal'] is defined %}
|
||||
====== {{ node.name }} ======
|
||||
<WRAP alert>This class is "internal", and thus is not documented!</WRAP>
|
||||
{% elseif node.tags['api'] is not defined and node.tags['api-advanced'] is not defined and node.tags['overwritable-hook'] is not defined and node.tags['extension-hook'] is not defined %}
|
||||
====== {{ node.name }} ======
|
||||
<WRAP alert>This class is neither "api", "api-advanced", "overwritable-hook" or "extension-hook", and thus is not documented!</WRAP>
|
||||
{% else %}
|
||||
|
||||
====== {{ node.name }} ======
|
||||
|
||||
{% if node.deprecated %}<wrap danger>deprecated</wrap>{% endif %}
|
||||
{% if node.abstract %}<wrap warning>abstract</wrap>{% endif %}
|
||||
{% if node.final %}<wrap notice>final</wrap>{% endif %}
|
||||
{% include 'includes/wrap-tags.txt.twig' with {structure:node, wrap: 'safety', wrapTags: ['api', 'api-advanced', 'overwritable-hook', 'extension-hook']} %}
|
||||
|
||||
|
||||
|
||||
{% if node.deprecated %}
|
||||
=== **<del>Deprecated</del>**===
|
||||
//{{ node.tags.deprecated[0].description }}//
|
||||
{% endif %}
|
||||
|
||||
|
||||
== {{ node.summary|replace({"\n":""})|raw }} ==
|
||||
<html>{{ node.description|markdown|raw }}</html>
|
||||
|
||||
|
||||
{% include 'includes/code-examples.txt.twig' with {structure:node, title_level: '====='} %}
|
||||
|
||||
|
||||
{% set class = node.parent %}
|
||||
{% block hierarchy_element %}
|
||||
|
||||
{% if class and class.name is defined and class.name|trim != '' %}
|
||||
==== parent ====
|
||||
{% set child = class %}
|
||||
{% set class = class.parent %}
|
||||
{{ block('hierarchy_element') }}
|
||||
[[{{ child.name }}|{{ child.name }}]]
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% for interface in node.interfaces|sort_asc %}
|
||||
{% if loop.first %}
|
||||
==== Implements ====
|
||||
{% endif %}
|
||||
{% if loop.length > 1 %} * {% endif %}{{ interface.fullyQualifiedStructuralElementName ?: interface }}
|
||||
{% endfor %}
|
||||
|
||||
|
||||
{% for trait in node.usedTraits|sort_asc %}
|
||||
{% if loop.first %}
|
||||
==== Uses traits ====
|
||||
{% endif %}
|
||||
{% if loop.length > 1 %} * {% endif %}{{ trait.fullyQualifiedStructuralElementName ?: trait }}
|
||||
{% endfor %}
|
||||
|
||||
|
||||
{% include 'includes/see-also.txt.twig' with {structure:node, title_level: '==='} %}
|
||||
|
||||
{% include 'includes/tags.txt.twig' with {structure:node, title_level: '=====', blacklist: ['link', 'see', 'abstract', 'example', 'method', 'property', 'property-read', 'property-write', 'package', 'subpackage', 'phpdoc-tuning-exclude-inherited', 'api', 'api-advanced', 'overwritable-hook', 'extension-hook', 'copyright', 'license', 'code-example']} %}
|
||||
|
||||
{% set methods = node.inheritedMethods.merge(node.methods.merge(node.magicMethods)) %}
|
||||
{% include 'includes/tag-synthesys.txt.twig' with {methods:methods, tag:'api'} %}
|
||||
{% include 'includes/tag-synthesys.txt.twig' with {methods:methods, tag:'api-advanced'} %}
|
||||
{% include 'includes/tag-synthesys.txt.twig' with {methods:methods, tag:'overwritable-hook'} %}
|
||||
{% include 'includes/tag-synthesys.txt.twig' with {methods:methods, tag:'extension-hook'} %}
|
||||
|
||||
|
||||
{% include 'includes/code-examples.txt.twig' with {structure:node, title_level: '=====', sub_title_level: '=='} %}
|
||||
|
||||
<WRAP clear />
|
||||
|
||||
{% for method in methods|sort_asc
|
||||
if method.visibility == 'public'
|
||||
and (
|
||||
method.tags['api'] is defined
|
||||
or method.tags['api-advanced'] is defined
|
||||
or method.tags['overwritable-hook'] is defined
|
||||
or method.tags['extension-hook'] is defined
|
||||
)
|
||||
and (
|
||||
node.tags['phpdoc-tuning-exclude-inherited'] is not defined
|
||||
or method.parent.name == node.name
|
||||
)
|
||||
%}
|
||||
{%- if loop.first %}
|
||||
===== Public methods =====
|
||||
{% endif %}
|
||||
{{ block('method') }}
|
||||
{% endfor %}
|
||||
{% for method in methods|sort_asc if method.visibility == 'protected' and (method.tags['overwritable-hook'] is defined or method.tags['extension-hook'] is defined) %}
|
||||
{%- if loop.first %}
|
||||
===== Protected methods =====
|
||||
{% endif %}
|
||||
{{ block('method') }}
|
||||
{% endfor %}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
{% set constants = node.inheritedConstants.merge(node.constants) %}
|
||||
{% if constants|length > 0 %}
|
||||
===== Constants =====
|
||||
{% for constant in constants|sort_asc %}
|
||||
{{ block('constant') }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
|
||||
{#{% set properties = node.inheritedProperties.merge(node.properties.merge(node.magicProperties)) %}#}
|
||||
{#{% for property in properties|sort_asc if property.visibility == 'public' %}#}
|
||||
{#{%- if loop.first %}#}
|
||||
{#===== Public properties =====#}
|
||||
{#{% endif %}#}
|
||||
{#{{ block('property') }}#}
|
||||
{#{% endfor %}#}
|
||||
{#{% for property in properties|sort_asc if property.visibility == 'protected' %}#}
|
||||
{#{%- if loop.first %}#}
|
||||
{#===== Protected properties =====#}
|
||||
{#{% endif %}#}
|
||||
{#{{ block('property') }}#}
|
||||
{#{% endfor %}#}
|
||||
|
||||
|
||||
{%- endif %} {#{% elseif node.tags['xxx'] is not defined and ... #}
|
||||
|
||||
<wrap button>[[start|🔙 Back]]</wrap>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,31 @@
|
||||
{% block constant %}
|
||||
|
||||
<WRAP group box >
|
||||
<WRAP twothirds column >
|
||||
==== {{ constant.name }} ====
|
||||
</WRAP>{# twothirds column#}
|
||||
|
||||
<WRAP third column>
|
||||
{% if constant.deprecated %}<wrap danger>deprecated</wrap> {% endif %}
|
||||
{% if (node.parent is not null and constant.parent.fullyQualifiedStructuralElementName != node.fullyQualifiedStructuralElementName) %}<wrap notice>inherited</wrap> {% endif %}
|
||||
</WRAP>{# third column#}
|
||||
|
||||
== {{ constant.summary|replace({"\n":""})|raw }} ==
|
||||
<html>{{ constant.description|markdown|raw }}</html>
|
||||
|
||||
{% if constant.deprecated %}
|
||||
=== Deprecated ===
|
||||
{{ constant.tags.deprecated[0].description|raw }}
|
||||
{% endif %}
|
||||
|
||||
{% include 'includes/inherited-from.txt.twig' with {structure:constant} %}
|
||||
|
||||
{% include 'includes/see-also.txt.twig' with {structure:constant, title_level: '=='} %}
|
||||
|
||||
{% include 'includes/uses.txt.twig' with {structure:constant, title_level: '=='} %}
|
||||
|
||||
{% include 'includes/tags.txt.twig' with {structure:constant, title_level: '==', blacklist: ['link', 'see', 'var', 'deprecated', 'uses', 'package', 'subpackage', 'todo', 'code-example']} %}
|
||||
|
||||
</WRAP>{# group #}
|
||||
|
||||
{% endblock %}
|
||||
95
.doc/phpdoc-templates/combodo-wiki/elements/method.txt.twig
Normal file
95
.doc/phpdoc-templates/combodo-wiki/elements/method.txt.twig
Normal file
@@ -0,0 +1,95 @@
|
||||
{% block method %}
|
||||
|
||||
|
||||
<WRAP group box >
|
||||
<WRAP twothirds column >
|
||||
==== {{ method.name }} ====
|
||||
</WRAP>{# twothirds column#}
|
||||
<WRAP third column >
|
||||
{% include 'includes/wrap-tags.txt.twig' with {structure:method, wrap: 'safety', wrapTags: ['api', 'api-advanced', 'overwritable-hook', 'extension-hook']} %}
|
||||
{% if method.deprecated %}<wrap danger>deprecated</wrap> {% endif %}
|
||||
{% if (node.parent is not null and method.parent.fullyQualifiedStructuralElementName != node.fullyQualifiedStructuralElementName) %}<wrap notice>inherited</wrap> {% endif %}
|
||||
{% if method.abstract %}<wrap warning>abstract</wrap> {% endif %}
|
||||
{% if method.final %}<wrap notice>final</wrap> {% endif %}
|
||||
<wrap notice>{{ method.visibility }}</wrap>
|
||||
{% if method.static %}<wrap warning>static</wrap> {% endif %}
|
||||
</WRAP>{# third column#}
|
||||
|
||||
|
||||
== {{ method.summary|replace({"\n":""})|raw }} ==
|
||||
<html>{{ method.description|markdown|raw }}</html>
|
||||
|
||||
<code php>{% if method.abstract %}abstract {% endif %}{% if method.final %}final {% endif %}{{ method.visibility }} {% if method.static %}static {% endif %}{{ method.name }}({% for argument in method.arguments %}{{ argument.isVariadic ? '...' }}{{ argument.name }}{{ argument.default ? (' = '~argument.default)|raw }}{% if not loop.last %}, {% endif %}{% endfor %})</code>
|
||||
|
||||
<WRAP twothirds column >
|
||||
|
||||
|
||||
=== Parameters ===
|
||||
{% if method.arguments|length > 0 -%}
|
||||
^ types ^ name ^ default ^ description ^
|
||||
{% for argument in method.arguments -%}
|
||||
| **<nowiki>{{ argument.types|join('|')|raw }}</nowiki>** | {{ argument.name }} {{ argument.isVariadic ? '<small style="color: gray">variadic</small>' }} | <nowiki>{{ argument.default|raw }}</nowiki> | {{ argument.description|trim|replace("\n", ' ')|raw }} |{{ "\r\n" }}
|
||||
{%- endfor %}
|
||||
{% else %}
|
||||
//none//
|
||||
{% endif %}
|
||||
|
||||
|
||||
{#=== Parameters ===#}
|
||||
{#{% if method.arguments|length > 0 -%}#}
|
||||
{#{% for argument in method.arguments -%}#}
|
||||
{#== {{ argument.name }} ==#}
|
||||
|
||||
|
||||
{#{% set varDesc %}#}
|
||||
{#<span style="margin:0 10px; 0 20px; font-weight: bold;">{{ argument.types|join('|') }}</span>#}
|
||||
{#{{ argument.isVariadic ? '<small style="color: gray">variadic</small>' }}#}
|
||||
{#{{ argument.description|raw }}#}
|
||||
{#{% endset %}#}
|
||||
{#<html>{{ varDesc|markdown|raw }}</html>#}
|
||||
{#{%- endfor %}#}
|
||||
{#{% else %}#}
|
||||
{#<wrap tip>This method has no parameter</wrap>#}
|
||||
{#{% endif %}#}
|
||||
|
||||
|
||||
{% if method.response and method.response.types|join() != 'void' %}
|
||||
=== Returns ===
|
||||
<html>{{ ('**' ~ method.response.types|join('|')|trim ~ '** ' ~ method.response.description)|markdown|raw }}</html>
|
||||
{% endif %}
|
||||
|
||||
</WRAP>{# twothirds column#}
|
||||
|
||||
<WRAP third column >
|
||||
|
||||
{% if method.tags.throws|length > 0 or method.tags.throw|length > 0 %}
|
||||
=== Throws ===
|
||||
{% for exception in method.tags.throws -%}
|
||||
{% if loop.length > 1 %} * {% endif %}''{{ exception.types|join('|')|raw }}'' <nowiki>{{ exception.description|raw }}</nowiki>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% include 'includes/inherited-from.txt.twig' with {structure:method} %}
|
||||
|
||||
{% include 'includes/see-also.txt.twig' with {structure:method, title_level: '==='} %}
|
||||
|
||||
{% include 'includes/uses.txt.twig' with {structure:method, title_level: '==='} %}
|
||||
|
||||
{% include 'includes/used-by.txt.twig' with {structure:method, title_level: '==='} %}
|
||||
|
||||
{% include 'includes/tags-with-description.txt.twig' with {structure:method, title_level: '===', WRAP: 'info', tagsWithDescription: ['api', 'api-advanced', 'overwritable-hook', 'extension-hook']} %}
|
||||
|
||||
{% include 'includes/tags.txt.twig' with {structure:method, title_level: '===', blacklist: ['todo', 'link', 'see', 'abstract', 'example', 'param', 'return', 'access', 'deprecated', 'throws', 'throw', 'uses', 'api', 'api-advanced', 'overwritable-hook', 'extension-hook', 'used-by', 'inheritdoc', 'code-example']} %}
|
||||
|
||||
</WRAP>{# third column#}
|
||||
|
||||
|
||||
|
||||
{% include 'includes/code-examples.txt.twig' with {structure:method, title_level: '==='} %}
|
||||
|
||||
</WRAP>{# group #}
|
||||
|
||||
|
||||
|
||||
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,49 @@
|
||||
{% block property %}
|
||||
|
||||
<WRAP group box>
|
||||
<WRAP twothirds column >
|
||||
==== ${{ property.name }} ====
|
||||
</WRAP>{# twothirds column#}
|
||||
|
||||
<WRAP third column>
|
||||
{% if property.deprecated %}<wrap danger>deprecated</wrap> {% endif %}
|
||||
{% if (node.parent is not null and property.parent.fullyQualifiedStructuralElementName != node.fullyQualifiedStructuralElementName) %}<wrap notice>inherited</wrap> {% endif %}
|
||||
</WRAP>{# third column#}
|
||||
|
||||
|
||||
|
||||
|
||||
== {{ property.summary|replace({"\n":""})|raw }} ==
|
||||
<html>{{ property.description|markdown|raw }}</html>
|
||||
{% if property.var.0.description %}<html>{{ property.var.0.description|markdown|raw }}</html>{% endif %}
|
||||
|
||||
|
||||
|
||||
{#{% if property.types %}#}
|
||||
{#== Type ==#}
|
||||
{#{% for type in property.types %}#}
|
||||
{#{% if loop.length > 1 %} * {% endif %}{{ type|raw }} : {{ type.description|raw }}#}
|
||||
{#{% endfor %}#}
|
||||
{#{{ property.types|join('|')|raw }}#}
|
||||
{#{% endif %}#}
|
||||
|
||||
|
||||
{% if property.deprecated %}
|
||||
== Deprecated ==
|
||||
{{ property.tags.deprecated[0].description }}
|
||||
{% endif %}
|
||||
|
||||
{% include 'includes/inherited-from.txt.twig' with {structure:property} %}
|
||||
|
||||
{% include 'includes/see-also.txt.twig' with {structure:property, title_level: '=='} %}
|
||||
|
||||
{% include 'includes/uses.txt.twig' with {structure:property, title_level: ''} %}
|
||||
|
||||
{% include 'includes/tags.txt.twig' with {structure:property, title_level: '==', blacklist: ['link', 'see', 'access', 'var', 'deprecated', 'uses', 'todo', 'code-example']} %}
|
||||
|
||||
|
||||
<code php>{{ property.visibility }} ${{ property.name }}{% if property.types %} : {{ property.types|join('|')|raw }}{% endif %}</code>
|
||||
|
||||
</WRAP>{# group #}
|
||||
|
||||
{% endblock %}
|
||||
1
.doc/phpdoc-templates/combodo-wiki/file.source.txt.twig
Normal file
1
.doc/phpdoc-templates/combodo-wiki/file.source.txt.twig
Normal file
@@ -0,0 +1 @@
|
||||
{{ node.source|raw }}
|
||||
122
.doc/phpdoc-templates/combodo-wiki/file.txt.twig
Normal file
122
.doc/phpdoc-templates/combodo-wiki/file.txt.twig
Normal file
@@ -0,0 +1,122 @@
|
||||
{% extends 'layout.txt.twig' %}
|
||||
|
||||
{% block javascripts %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{#<section class="row-fluid">#}
|
||||
{#<div class="span2 sidebar">#}
|
||||
{#{% set namespace = project.namespace %}#}
|
||||
{#{{ block('sidebarNamespaces') }}#}
|
||||
{#</div>#}
|
||||
{#</section>#}
|
||||
{#<section class="row-fluid">#}
|
||||
====== {{ node.path|split('/')|slice(0,-1)|join('/') }}{{ node.name }} ======
|
||||
{{ node.summary }}
|
||||
<html>{{ node.description|markdown|raw }}</html>
|
||||
|
||||
{% if node.traits|length > 0 %}
|
||||
|
||||
===== Traits =====
|
||||
{% for trait in node.traits %}
|
||||
<tr>
|
||||
<td>{{ trait|raw }}</td>
|
||||
<td><em>{{ trait.summary }}</em></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% if node.interfaces|length > 0 %}
|
||||
===== Interfaces =====
|
||||
{% for interface in node.interfaces %}
|
||||
<tr>
|
||||
<td>{{ interface|raw }}</td>
|
||||
<td><em>{{ interface.summary }}</em></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% if node.classes|length > 0 %}
|
||||
===== Classes =====
|
||||
{% for class in node.classes %}
|
||||
{{ class|raw }}
|
||||
<em>{{ class.summary }}</em>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% if node.package is not empty and node.package != '\\' %}
|
||||
===== Package =====
|
||||
{{ node.subpackage ? (node.package ~ '\\' ~ node.subpackage) : node.package }}
|
||||
{% endif %}
|
||||
|
||||
{% for tagName,tags in node.tags if tagName in ['link', 'see'] %}
|
||||
{% if loop.first %}
|
||||
===== See also =====
|
||||
{% endif %}
|
||||
{% for tag in tags %}
|
||||
<dd><a href="{{ tag.reference ?: tag.link }}"><div class="namespace-wrapper">{{ tag.description ?: tag.reference }}</div></a></dd>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
|
||||
<h2>Tags</h2>
|
||||
<table class="table table-condensed">
|
||||
{% for tagName,tags in node.tags if tagName not in ['link', 'see', 'package', 'subpackage'] %}
|
||||
<tr>
|
||||
<th>
|
||||
{{ tagName }}
|
||||
</th>
|
||||
<td>
|
||||
{% for tag in tags %}
|
||||
{{ tag.description|markdown|raw }}
|
||||
{% endfor %}
|
||||
</td>
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr><td colspan="2"><em>None found</em></td></tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
||||
</aside>
|
||||
</div>
|
||||
|
||||
{% if node.constants|length > 0 %}
|
||||
<div class="row-fluid">
|
||||
<section class="span8 content file">
|
||||
<h2>Constants</h2>
|
||||
</section>
|
||||
<aside class="span4 detailsbar"></aside>
|
||||
</div>
|
||||
|
||||
{% for constant in node.constants %}
|
||||
{{ block('constant') }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% if node.functions|length > 0 %}
|
||||
<div class="row-fluid">
|
||||
<section class="span8 content file">
|
||||
<h2>Functions</h2>
|
||||
</section>
|
||||
<aside class="span4 detailsbar"></aside>
|
||||
</div>
|
||||
|
||||
{% for method in node.functions %}
|
||||
{{ block('method') }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div id="source-view" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="source-view-label" aria-hidden="true">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h3 id="source-view-label">{{ node.file.name }}</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<pre data-src="{{ path('files/' ~ node.path ~ '.txt')|raw }}" class="language-php line-numbers"></pre>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
42
.doc/phpdoc-templates/combodo-wiki/graphs/class.html.twig
Normal file
42
.doc/phpdoc-templates/combodo-wiki/graphs/class.html.twig
Normal file
@@ -0,0 +1,42 @@
|
||||
{% extends 'layout.html.twig' %}
|
||||
|
||||
{% block stylesheets %}
|
||||
<link href="{{ path('css/jquery.iviewer.css') }}" rel="stylesheet" media="all"/>
|
||||
<style>
|
||||
#viewer {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
.wrapper {
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block javascripts %}
|
||||
<script src="{{ path('js/jquery.mousewheel.js') }}" type="text/javascript"></script>
|
||||
<script src="{{ path('js/jquery.iviewer.js') }}" type="text/javascript"></script>
|
||||
<script type="text/javascript">
|
||||
$(window).resize(function(){
|
||||
$("#viewer").height($(window).height() - 100);
|
||||
});
|
||||
|
||||
$(document).ready(function() {
|
||||
$("#viewer").iviewer({src: '{{ path('graphs/classes.svg') }}', zoom_animation: false});
|
||||
$('#viewer img').bind('dragstart', function(event){
|
||||
event.preventDefault();
|
||||
});
|
||||
$(window).resize();
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row-fluid">
|
||||
<div class="span12">
|
||||
<div class="wrapper">
|
||||
<div id="viewer" class="viewer"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
5
.doc/phpdoc-templates/combodo-wiki/htaccess.dist
Normal file
5
.doc/phpdoc-templates/combodo-wiki/htaccess.dist
Normal file
@@ -0,0 +1,5 @@
|
||||
# Fixes a vulnerability in CentOS: http://stackoverflow.com/questions/20533279/prevent-php-from-parsing-non-php-files-such-as-somefile-php-txt
|
||||
<FilesMatch \.php\.txt$>
|
||||
RemoveHandler .php
|
||||
ForceType text/plain
|
||||
</FilesMatch>
|
||||
@@ -0,0 +1,34 @@
|
||||
{% if title_level is not defined %}
|
||||
{%- set title_level = '==' -%}
|
||||
{% endif %}
|
||||
|
||||
{% if sub_title_level is not defined %}
|
||||
{%- set sub_title_level = title_level|slice(1) -%}
|
||||
{% endif %}
|
||||
{% if sub_title_level == '=' %}
|
||||
{%- set sub_title_level = '' -%}
|
||||
{% endif %}
|
||||
|
||||
{#{% for tagName,tags in structure.tags if tagName in ['code-example'] %}#}
|
||||
{#{% if loop.first %}#}
|
||||
{#{{title_level}} Examples {{title_level}}#}
|
||||
{#{% endif %}#}
|
||||
{#{% for tag in tags %}#}
|
||||
{#{%- set descToken = tag.description|split("\n", 2) -%}#}
|
||||
{#{%- set title = descToken[0] -%}#}
|
||||
{#{%- set code = descToken[1] -%}#}
|
||||
{#{{sub_title_level}} {{ title }} {{sub_title_level}}#}
|
||||
{#<code php>{{ code|raw }}</code>#}
|
||||
{#{% endfor %}#}
|
||||
{#{% endfor %}#}
|
||||
|
||||
|
||||
{% for tagName,tags in structure.tags if tagName in ['example'] %}
|
||||
{% if loop.first %}
|
||||
{{title_level}} Examples {{title_level}}
|
||||
{% endif %}
|
||||
{% for tag in tags %}
|
||||
{{ sub_title_level }} {{ tag.filePath|escape }}{{ sub_title_level }}
|
||||
<code php>{{ tag.description|raw }}</code>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
@@ -0,0 +1,12 @@
|
||||
{% if title_level is not defined %}
|
||||
{% set title_level='' %}
|
||||
{% endif %}
|
||||
|
||||
{% if (node.parent is null) %}
|
||||
{{title_level}} File {{ structure.path }} {{title_level}}
|
||||
{% endif %}
|
||||
|
||||
{% if (node.parent is not null and structure.parent.fullyQualifiedStructuralElementName != node.fullyQualifiedStructuralElementName) %}
|
||||
{{title_level}} Inherited from {{title_level}}
|
||||
[[{{structure.parent}}|{{structure.parent}}]]
|
||||
{% endif %}
|
||||
@@ -0,0 +1,26 @@
|
||||
{% for structure in structures|sort_asc if structure.tags['internal'] is not defined and (structure.tags['api'] is defined or structure.tags['api-advanced'] is defined or structure.tags['overwritable-hook'] is defined or structure.tags['extension-hook'] is defined ) %}
|
||||
{#{{ structure|raw }}#}
|
||||
|
||||
{% set structureName = structure|trim('\\', 'left') %}
|
||||
|
||||
<WRAP group box>
|
||||
<WRAP twothirds column >
|
||||
==== {{ structureName }} ====
|
||||
</WRAP>{# twothirds column#}
|
||||
|
||||
<WRAP third column>
|
||||
{% if structure.deprecated %}<wrap danger>deprecated</wrap>{% endif %}
|
||||
{% if structure.abstract %}<wrap warning>abstract</wrap>{% endif %}
|
||||
{% if structure.final %}<wrap notice>final</wrap>{% endif %}
|
||||
{% if (node.parent is not null and structure.parent.fullyQualifiedStructuralElementName != node.fullyQualifiedStructuralElementName) %}<wrap notice>inherited</wrap> {% endif %}
|
||||
{% include 'includes/wrap-tags.txt.twig' with {structure:structure, wrap: 'safety', wrapTags: ['api', 'api-advanced', 'overwritable-hook', 'extension-hook']} %}
|
||||
</WRAP>{# third column#}
|
||||
|
||||
|
||||
{{ structure.summary|raw }}
|
||||
[[{{structureName}}|More informations]]
|
||||
|
||||
</WRAP>{# group #}
|
||||
|
||||
{% endfor %}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
{% if title_level is not defined %}
|
||||
{%- set title_level='==' -%}
|
||||
{% endif %}
|
||||
{% for tagName,tags in structure.tags if tagName in ['link', 'see'] %}
|
||||
{% if loop.first %}
|
||||
{{title_level}} See also {{title_level}}
|
||||
{% endif %}
|
||||
{% for tag in tags %}
|
||||
{%- set linkTag = tag.reference|trim('\\', 'left') -%}
|
||||
{% if not('()' in linkTag or '$' in linkTag or node.name in linkTag or '::' in linkTag ) %}
|
||||
{%- set linkTag = linkTag|lower -%}
|
||||
{% elseif node.name~'::' in linkTag %}
|
||||
{%- set linkTag = linkTag|replace({(node.name~'::'): '#'})|lower -%}
|
||||
{% elseif '::' in linkTag -%}
|
||||
{%- set linkTag = linkTag|replace({'::': '#'})|lower -%}
|
||||
{% else %}
|
||||
{%- set linkTag = '#' ~ linkTag|lower -%}
|
||||
{%- endif %}
|
||||
|
||||
{% if loop.length > 1 %} * {% endif %}{% if tag.reference is not empty -%}
|
||||
[[{{linkTag}}|{{ (tag.reference)|trim('\\', 'left') }}]] {% if tag.description|trim is not empty %}: {{ tag.description|trim('\\', 'left') }} {% endif %}
|
||||
{%- else -%}
|
||||
{#{{ tag.description|trim('\\', 'left') }}#}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
@@ -0,0 +1,56 @@
|
||||
{% if tag is not defined -%}
|
||||
{# Do not display @api if @api-advanced is also present #}
|
||||
{%- set tag = "api" -%}
|
||||
{%- endif %}
|
||||
|
||||
{% if hidden_by is not defined -%}
|
||||
{# Do not display @api if @api-advanced is also present #}
|
||||
{%- set hidden_by = {"api" : "api-advanced"} -%}
|
||||
{%- endif %}
|
||||
|
||||
|
||||
|
||||
{% for method in methods|sort_asc
|
||||
if (method.visibility == 'public')
|
||||
and (
|
||||
method.tags[tag] is defined
|
||||
and (
|
||||
hidden_by[tag] is not defined or method.tags[hidden_by[tag]] is not defined
|
||||
)
|
||||
)
|
||||
%}
|
||||
{%- if loop.first %}
|
||||
{% if tag == 'api' %}
|
||||
===== API synthesis =====
|
||||
<WRAP>
|
||||
List of the public API methods.
|
||||
When manipulating {{ node.name }}, You can call those methods:
|
||||
</WRAP>
|
||||
{% elseif tag == 'api-advanced' %}
|
||||
===== Advanced API synthesis =====
|
||||
<WRAP>
|
||||
List of advanced API methods
|
||||
Beware they usage is recommended to advanced users only.
|
||||
</WRAP>
|
||||
{% elseif tag == 'overwritable-hook' %}
|
||||
===== overwritable-hook synthesis =====
|
||||
<WRAP >When inheriting from {{ node.name }},
|
||||
you can overwrite those methods in order to add custom logic:
|
||||
</WRAP>
|
||||
{% elseif tag == 'extension-hook' %}
|
||||
===== extension-hook synthesis =====
|
||||
<WRAP >
|
||||
When inheriting from {{ node.name }},
|
||||
you can extend the behaviour of iTop by implementing:
|
||||
</WRAP>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% set sanitizedMethod = method|trim('\\', 'left')|replace({(node.name~'::'): ''}) %}
|
||||
{% if '::' in sanitizedMethod -%}
|
||||
{%- if node.tags['phpdoc-tuning-exclude-inherited'] is not defined %}
|
||||
* [[{{sanitizedMethod|replace({'::': '#'})|lower}}|↪{{sanitizedMethod}}]] — {{ method.summary|replace({"\n":""})|raw }}
|
||||
{% endif %}
|
||||
{%- else %}
|
||||
* [[#{{sanitizedMethod}}|{{sanitizedMethod}}]] — {{ method.summary|replace({"\n":""})|raw }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
@@ -0,0 +1,20 @@
|
||||
{% if title_level is not defined %}
|
||||
{% set title_level = '==' %}
|
||||
{% endif %}
|
||||
|
||||
|
||||
{%- for tagName,tags in structure.tags if tagName in tagsWithDescription -%}
|
||||
{%- for tag in tags -%}
|
||||
{%- if tag.description is not empty -%}
|
||||
{%- if WRAP is defined -%}
|
||||
<WRAP {{WRAP}}>
|
||||
{%- endif -%}
|
||||
{{title_level}} {{ tagName }} {{title_level}}
|
||||
{{ tag.description|escape }}
|
||||
{%- if WRAP is defined -%}
|
||||
</WRAP>
|
||||
{%- endif -%}
|
||||
{%- endif -%}
|
||||
{%- endfor -%}
|
||||
{%- endfor -%}
|
||||
|
||||
22
.doc/phpdoc-templates/combodo-wiki/includes/tags.txt.twig
Normal file
22
.doc/phpdoc-templates/combodo-wiki/includes/tags.txt.twig
Normal file
@@ -0,0 +1,22 @@
|
||||
{% if title_level is not defined %}
|
||||
{% set title_level='=====' %}
|
||||
{% endif %}
|
||||
|
||||
{% if blacklist is not defined %}
|
||||
{% set blacklist =['link', 'see', 'abstract', 'example', 'method', 'property', 'property-read', 'property-write', 'package', 'subpackage', 'api', 'api-advanced', 'todo', 'code-example'] %}
|
||||
{% endif %}
|
||||
{% if hidden_by is not defined -%}
|
||||
{# Do not display @api if @api-advanced is also present #}
|
||||
{%- set hidden_by = {"api" : "api-advanced"} -%}
|
||||
{%- endif %}
|
||||
|
||||
{#^ {% for tagName,tags in structure.tags if tagName not in blacklist -%}#}
|
||||
{#{{ tagName }} ^#}
|
||||
{#{%- endfor %}#}
|
||||
|
||||
{% for tagName,tags in structure.tags if tagName not in blacklist and (hidden_by[tagName] is not defined or structure.tags[hidden_by[tagName]] is not defined) %}
|
||||
{%- if loop.first %}
|
||||
{{title_level}} Tags {{title_level}}
|
||||
{% endif %}
|
||||
^ {{ tagName }} | {% for tag in tags %}{{ tag.version ? tag.version ~ ' ' : '' }}{{ tag.description}}{% endfor %} |
|
||||
{% endfor %}
|
||||
24
.doc/phpdoc-templates/combodo-wiki/includes/used-by.txt.twig
Normal file
24
.doc/phpdoc-templates/combodo-wiki/includes/used-by.txt.twig
Normal file
@@ -0,0 +1,24 @@
|
||||
{% if title_level is not defined %}
|
||||
{% set title_level='' %}
|
||||
{% endif %}
|
||||
{% for tagName,tags in structure.tags if tagName in ['used-by'] %}
|
||||
{% if loop.first %}
|
||||
{{title_level}} Used by {{title_level}}
|
||||
{% endif %}
|
||||
{% for tag in tags %}
|
||||
{% if loop.length > 1 %} * {% endif %}{{ tag.reference ?: tag.link }} : {{ tag.description ?: tag.reference }}
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
{#{% for tagName,tags in method.tags if tagName in ['uses'] %}#}
|
||||
{#{% if loop.first %}#}
|
||||
{#<dt>Uses</dt>#}
|
||||
{#{% endif %}#}
|
||||
{#{% for tag in tags %}#}
|
||||
{#<dd>{{ tag.reference|raw }}</dd>#}
|
||||
{#{% endfor %}#}
|
||||
{#{% endfor %}#}
|
||||
24
.doc/phpdoc-templates/combodo-wiki/includes/uses.txt.twig
Normal file
24
.doc/phpdoc-templates/combodo-wiki/includes/uses.txt.twig
Normal file
@@ -0,0 +1,24 @@
|
||||
{% if title_level is not defined %}
|
||||
{% set title_level='' %}
|
||||
{% endif %}
|
||||
{% for tagName,tags in structure.tags if tagName in ['uses'] %}
|
||||
{% if loop.first %}
|
||||
{{title_level}} Uses {{title_level}}
|
||||
{% endif %}
|
||||
{% for tag in tags %}
|
||||
{% if loop.length > 1 %} * {% endif %}{{ tag.reference ?: tag.link }} : {{ tag.description ?: tag.reference }}
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
{#{% for tagName,tags in method.tags if tagName in ['uses'] %}#}
|
||||
{#{% if loop.first %}#}
|
||||
{#<dt>Uses</dt>#}
|
||||
{#{% endif %}#}
|
||||
{#{% for tag in tags %}#}
|
||||
{#<dd>{{ tag.reference|raw }}</dd>#}
|
||||
{#{% endfor %}#}
|
||||
{#{% endfor %}#}
|
||||
@@ -0,0 +1,11 @@
|
||||
{% if wrap is not defined -%}
|
||||
{% set wrap = 'notice' %}
|
||||
{%- endif -%}
|
||||
{% if hidden_by is not defined -%}
|
||||
{# Do not display @api if @api-advanced is also present #}
|
||||
{%- set hidden_by = {"api" : "api-advanced"} -%}
|
||||
{%- endif %}
|
||||
|
||||
{%- for tagName,tags in structure.tags if tagName in wrapTags and (hidden_by[tagName] is not defined or structure.tags[hidden_by[tagName]] is not defined) %}
|
||||
<wrap {{wrap}}>{{tagName}}</wrap>
|
||||
{% endfor %}
|
||||
121
.doc/phpdoc-templates/combodo-wiki/interface.txt.twig
Normal file
121
.doc/phpdoc-templates/combodo-wiki/interface.txt.twig
Normal file
@@ -0,0 +1,121 @@
|
||||
{% extends 'layout.txt.twig' %}
|
||||
|
||||
{% block content %}
|
||||
<wrap button>[[start|🔙 Back]]</wrap>
|
||||
|
||||
{% if node.tags['internal'] is defined %}
|
||||
====== {{ node.name }} ======
|
||||
<WRAP alert>This interface is "internal", and thus is not documented!</WRAP>
|
||||
{% elseif node.tags['api'] is not defined and node.tags['api-advanced'] is not defined and node.tags['overwritable-hook'] is not defined and node.tags['extension-hook'] is not defined %}
|
||||
====== {{ node.name }} ======
|
||||
<WRAP alert>This interface is neither "api", "overwritable-hook" or "extension-hook", and thus is not documented!</WRAP>
|
||||
{% else %}
|
||||
|
||||
====== {{ node.name }} ======
|
||||
|
||||
{% if node.deprecated %}<wrap danger>deprecated</wrap>{% endif %}
|
||||
{% if node.abstract %}<wrap warning>abstract</wrap>{% endif %}
|
||||
{% if node.final %}<wrap notice>final</wrap>{% endif %}
|
||||
{% include 'includes/wrap-tags.txt.twig' with {structure:node, wrap: 'safety', wrapTags: ['api', 'api-advanced', 'overwritable-hook', 'extension-hook']} %}
|
||||
|
||||
|
||||
|
||||
{% if node.deprecated %}
|
||||
=== **<del>Deprecated</del>**===
|
||||
//{{ node.tags.deprecated[0].description }}//
|
||||
{% endif %}
|
||||
|
||||
|
||||
== {{ node.summary|replace({"\n":""})|raw }} ==
|
||||
<html>{{ node.description|markdown|raw }}</html>
|
||||
|
||||
|
||||
{% include 'includes/code-examples.txt.twig' with {structure:node, title_level: '====='} %}
|
||||
|
||||
|
||||
{% set class = node.parent %}
|
||||
{% block hierarchy_element %}
|
||||
|
||||
{% if class and class.name is defined and class.name|trim != '' %}
|
||||
==== parent ====
|
||||
{% set child = class %}
|
||||
{% set class = class.parent %}
|
||||
{{ block('hierarchy_element') }}
|
||||
[[{{ child.name }}|{{ child.name }}]]
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% for interface in node.interfaces|sort_asc %}
|
||||
{% if loop.first %}
|
||||
==== Implements ====
|
||||
{% endif %}
|
||||
{% if loop.length > 1 %} * {% endif %}{{ interface.fullyQualifiedStructuralElementName ?: interface }}
|
||||
{% endfor %}
|
||||
|
||||
|
||||
{% for trait in node.usedTraits|sort_asc %}
|
||||
{% if loop.first %}
|
||||
==== Uses traits ====
|
||||
{% endif %}
|
||||
{% if loop.length > 1 %} * {% endif %}{{ trait.fullyQualifiedStructuralElementName ?: trait }}
|
||||
{% endfor %}
|
||||
|
||||
|
||||
{% include 'includes/see-also.txt.twig' with {structure:node, title_level: '==='} %}
|
||||
|
||||
{% include 'includes/tags.txt.twig' with {structure:node, title_level: '=====', blacklist: ['link', 'see', 'abstract', 'example', 'method', 'property', 'property-read', 'property-write', 'package', 'subpackage', 'phpdoc-tuning-exclude-inherited', 'api', 'api-advanced', 'overwritable-hook', 'extension-hook', 'copyright', 'license', 'code-example']} %}
|
||||
|
||||
|
||||
{% set methods = node.inheritedMethods.merge(node.methods) %}
|
||||
{% include 'includes/tag-synthesys.txt.twig' with {methods:methods, tag:'api'} %}
|
||||
{% include 'includes/tag-synthesys.txt.twig' with {methods:methods, tag:'api-advanced'} %}
|
||||
{% include 'includes/tag-synthesys.txt.twig' with {methods:methods, tag:'overwritable-hook'} %}
|
||||
{% include 'includes/tag-synthesys.txt.twig' with {methods:methods, tag:'extension-hook'} %}
|
||||
|
||||
<WRAP clear />
|
||||
|
||||
|
||||
{% for method in methods|sort_asc if method.visibility == 'public' %}
|
||||
{%- if loop.first %}
|
||||
===== Public methods =====
|
||||
{% endif %}
|
||||
{{ block('method') }}
|
||||
{% endfor %}
|
||||
{% for method in methods|sort_asc if method.visibility == 'protected' %}
|
||||
{%- if loop.first %}
|
||||
===== Protected methods =====
|
||||
{% endif %}
|
||||
{{ block('method') }}
|
||||
{% endfor %}
|
||||
|
||||
|
||||
|
||||
{% set constants = node.inheritedConstants.merge(node.constants) %}
|
||||
{% if constants|length > 0 %}
|
||||
===== Constants =====
|
||||
{% for constant in constants|sort_asc %}
|
||||
{{ block('constant') }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
|
||||
{#{% set properties = node.inheritedProperties.merge(node.properties) %}#}
|
||||
{#{% for property in properties|sort_asc if property.visibility == 'public' %}#}
|
||||
{#{%- if loop.first %}#}
|
||||
{#===== Public properties =====#}
|
||||
{#{% endif %}#}
|
||||
{#{{ block('property') }}#}
|
||||
{#{% endfor %}#}
|
||||
{#{% for property in properties|sort_asc if property.visibility == 'protected' %}#}
|
||||
{#{%- if loop.first %}#}
|
||||
{#===== Protected properties =====#}
|
||||
{#{% endif %}#}
|
||||
{#{{ block('property') }}#}
|
||||
{#{% endfor %}#}
|
||||
|
||||
|
||||
{%- endif %} {#{% elseif node.tags['xxx'] is not defined and ... #}
|
||||
|
||||
<wrap button>[[start|🔙 Back]]</wrap>
|
||||
{% endblock %}
|
||||
5
.doc/phpdoc-templates/combodo-wiki/layout.txt.twig
Normal file
5
.doc/phpdoc-templates/combodo-wiki/layout.txt.twig
Normal file
@@ -0,0 +1,5 @@
|
||||
{% use 'elements/constant.txt.twig' %}
|
||||
{% use 'elements/property.txt.twig' %}
|
||||
{% use 'elements/method.txt.twig' %}
|
||||
|
||||
{% block content %}{% endblock %}
|
||||
51
.doc/phpdoc-templates/combodo-wiki/namespace.txt.twig
Normal file
51
.doc/phpdoc-templates/combodo-wiki/namespace.txt.twig
Normal file
@@ -0,0 +1,51 @@
|
||||
{% extends 'layout.txt.twig' %}
|
||||
|
||||
{% block content %}
|
||||
{% set namespace = project.namespace %}
|
||||
{{ block('sidebarNamespaces') }}
|
||||
|
||||
{#{{ node.parent|raw }}#}
|
||||
{#====== {{ node.parent.fullyQualifiedStructuralElementName }}{{ node.name }} ======#}
|
||||
|
||||
{% if node.children|length > 0 %}
|
||||
=====Namespaces=====
|
||||
{% include 'includes/namespace-structure-toc.html.twig' with {structures: node.children} %}
|
||||
----
|
||||
{% endif %}
|
||||
|
||||
{% if node.traits|length > 0 %}
|
||||
===== Traits =====
|
||||
{% include 'includes/namespace-structure-toc.html.twig' with {structures: node.traits} %}
|
||||
----
|
||||
{%- endif %}
|
||||
|
||||
{% if node.interfaces|length > 0 %}
|
||||
===== Interfaces =====
|
||||
{% include 'includes/namespace-structure-toc.html.twig' with {structures: node.interfaces} %}
|
||||
----
|
||||
{% endif %}
|
||||
|
||||
{% if node.classes|length > 0 %}
|
||||
===== Classes =====
|
||||
{% include 'includes/namespace-structure-toc.html.twig' with {structures: node.classes} %}
|
||||
----
|
||||
{% endif %}
|
||||
|
||||
|
||||
|
||||
{#{% if node.constants|length > 0 %}#}
|
||||
{#===== Constants =====#}
|
||||
{#{% for constant in node.constants|sort_asc %}#}
|
||||
{# {{ block('constant') }}#}
|
||||
{#{% endfor %}#}
|
||||
{#{% endif %}#}
|
||||
|
||||
{#{% if node.functions|length > 0 %}#}
|
||||
{#===== Functions =====#}
|
||||
|
||||
{#{% for method in node.functions|sort_asc %}#}
|
||||
{# {{ block('method') }}#}
|
||||
{#{% endfor %}#}
|
||||
{#{% endif %}#}
|
||||
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,49 @@
|
||||
|
||||
====== Deprecated elements ======
|
||||
|
||||
{#{% for element in project.indexes.elements if element.deprecated %}#}
|
||||
{#{% if element.file.path != previousPath %}#}
|
||||
{#<li><a href="#{{ element.file.path }}"><i class="icon-file"></i> {{ element.file.path }}</a></li>#}
|
||||
{#{% endif %}#}
|
||||
{#{% set previousPath = element.file.path %}#}
|
||||
{#{% endfor %}#}
|
||||
|
||||
{% for element in project.indexes.elements if element.deprecated %}
|
||||
{% if element.file.path != previousPath %}
|
||||
{% if previousPath %}
|
||||
</WRAP>{# group #}
|
||||
{% endif %}
|
||||
{#<a name="{{ element.file.path }}" id="{{ element.file.path }}"></a>#}
|
||||
===== {{ element.file.path }} ({{ element.tags.deprecated.count }} found)=====
|
||||
|
||||
<WRAP group >
|
||||
<WRAP third column >
|
||||
Element
|
||||
</WRAP>{# third column#}
|
||||
<WRAP third column >
|
||||
Line
|
||||
</WRAP>{# third column#}
|
||||
<WRAP third column >
|
||||
Description
|
||||
</WRAP>{# third column#}
|
||||
|
||||
{% endif %}
|
||||
{% for tag in element.tags.deprecated %}
|
||||
<WRAP group >
|
||||
<WRAP third column >
|
||||
{{ element.fullyQualifiedStructuralElementName }}
|
||||
</WRAP>{# third column#}
|
||||
<WRAP third column >
|
||||
{{ element.line }}
|
||||
</WRAP>{# third column#}
|
||||
<WRAP third column >
|
||||
{{ tag.description }}
|
||||
</WRAP>{# third column#}
|
||||
|
||||
{% endfor %}
|
||||
</WRAP>{# group #}
|
||||
{% set previousPath = element.file.path %}
|
||||
{% else %}
|
||||
<WRAP info>No deprecated elements have been found in this project.</WRAP>
|
||||
{% endfor %}
|
||||
|
||||
27
.doc/phpdoc-templates/combodo-wiki/template.xml
Normal file
27
.doc/phpdoc-templates/combodo-wiki/template.xml
Normal file
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<template>
|
||||
<author>Bruno DA SILVA</author>
|
||||
<email>contact [at] combodo.com</email>
|
||||
<version>1.0.0</version>
|
||||
<copyright>Combodo 2018</copyright>
|
||||
<description><![CDATA[
|
||||
|
||||
Forked from the clean theme of https://github.com/phpDocumentor/phpDocumentor2 provided under the MIT licence.
|
||||
The original work is copyright "Mike van Riel".
|
||||
|
||||
------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
To improve performance you can add the following to your .htaccess:
|
||||
|
||||
<ifModule mod_deflate.c>
|
||||
<filesMatch "\.(js|css|html)$">
|
||||
SetOutputFilter DEFLATE
|
||||
</filesMatch>
|
||||
</ifModule>
|
||||
]]></description>
|
||||
<transformations>
|
||||
<transformation writer="twig" query="namespace" source="templates/combodo-wiki/namespace.txt.twig" artifact="start.txt"/>
|
||||
<transformation writer="twig" query="indexes.classes" source="templates/combodo-wiki/class.txt.twig" artifact="{{name}}.txt"/>
|
||||
<transformation writer="twig" query="indexes.interfaces" source="templates/combodo-wiki/interface.txt.twig" artifact="{{name}}.txt" />
|
||||
</transformations>
|
||||
</template>
|
||||
9
.gitflow
Normal file
9
.gitflow
Normal file
@@ -0,0 +1,9 @@
|
||||
[gitflow "branch"]
|
||||
master = master
|
||||
develop = develop
|
||||
[gitflow "prefix"]
|
||||
feature = feature/
|
||||
release = release/
|
||||
hotfix = hotfix/
|
||||
versiontag =
|
||||
support = support/
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -33,7 +33,8 @@ test/vendor/*
|
||||
!/.idea/inspectionProfiles
|
||||
!/.idea/inspectionProfiles/*
|
||||
|
||||
|
||||
#phpdocumentor temp file
|
||||
ast.dump
|
||||
|
||||
# CMake
|
||||
cmake-build-*/
|
||||
@@ -121,3 +122,4 @@ local.properties
|
||||
.cache-main
|
||||
.scala_dependencies
|
||||
.worksheet
|
||||
|
||||
|
||||
12
.idea/codeStyles/Project.xml
generated
12
.idea/codeStyles/Project.xml
generated
@@ -1,5 +1,11 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<code_scheme name="Project" version="173">
|
||||
<option name="LINE_SEPARATOR" value=" " />
|
||||
<option name="RIGHT_MARGIN" value="320" />
|
||||
<HTMLCodeStyleSettings>
|
||||
<option name="HTML_DO_NOT_INDENT_CHILDREN_OF" value="html,body,thead,tbody,tfoot,script,style" />
|
||||
<option name="HTML_DO_NOT_ALIGN_CHILDREN_OF_MIN_LINES" value="4" />
|
||||
</HTMLCodeStyleSettings>
|
||||
<PHPCodeStyleSettings>
|
||||
<option name="CONCAT_SPACES" value="false" />
|
||||
<option name="PHPDOC_BLANK_LINE_BEFORE_TAGS" value="true" />
|
||||
@@ -20,6 +26,7 @@
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="PHP">
|
||||
<option name="RIGHT_MARGIN" value="320" />
|
||||
<option name="BLANK_LINES_AFTER_PACKAGE" value="1" />
|
||||
<option name="BRACE_STYLE" value="2" />
|
||||
<option name="ELSE_ON_NEW_LINE" value="true" />
|
||||
@@ -41,5 +48,10 @@
|
||||
<option name="SMART_TABS" value="true" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="XML">
|
||||
<indentOptions>
|
||||
<option name="USE_TAB_CHARACTER" value="true" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
</code_scheme>
|
||||
</component>
|
||||
2
.idea/encodings.xml
generated
2
.idea/encodings.xml
generated
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding">
|
||||
<component name="Encoding" defaultCharsetForPropertiesFiles="UTF-8">
|
||||
<file url="PROJECT" charset="UTF-8" />
|
||||
</component>
|
||||
</project>
|
||||
44
.idea/inspectionProfiles/Combodo.xml
generated
Normal file
44
.idea/inspectionProfiles/Combodo.xml
generated
Normal file
@@ -0,0 +1,44 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Combodo" />
|
||||
<inspection_tool class="InconsistentLineSeparators" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="MysqlParsingInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="PhpIncludeInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="PhpMethodParametersCountMismatchInspection" enabled="true" level="ERROR" enabled_by_default="true" />
|
||||
<inspection_tool class="PhpTooManyParametersInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="limit" value="7" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="PhpUndefinedClassInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="DONT_REPORT_MULTI_RESOLVE" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="PhpUndefinedMethodInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="PhpUnhandledExceptionInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="PhpUnusedLocalVariableInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
||||
<option name="DONT_REPORT_INSIDE_LIST" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="PhpUnusedParameterInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
||||
<option name="DONT_REPORT_ABSTRACT_CLASS" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="SqlAddNotNullColumnInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlAmbiguousColumnInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlAutoIncrementDuplicateInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlCheckUsingColumnsInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlConstantConditionInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlDeprecateTypeInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlDerivedTableAliasInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlDialectInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlDropIndexedColumnInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlIdentifierInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlInsertValuesInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlNoDataSourceInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlNullComparisonInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlPostgresqlSelectFromProcedureInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlResolveInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlShouldBeInGroupByInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlSideEffectsInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlSignatureInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlStorageInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlTypeInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlUnusedVariableInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
</profile>
|
||||
</component>
|
||||
155
.idea/inspectionProfiles/Project_Default.xml
generated
155
.idea/inspectionProfiles/Project_Default.xml
generated
@@ -1,154 +1,19 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="BladeControlDirectives" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="CheckEmptyScriptTag" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="CheckImageSize" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="CheckNodeTest" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="CheckTagEmptyBody" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="CheckValidXmlInScriptTagBody" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="CoffeeScriptArgumentsOutsideFunction" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="CoffeeScriptFunctionSignatures" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="CoffeeScriptInfiniteLoop" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="CoffeeScriptLiteralNotFunction" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="CoffeeScriptSillyAssignment" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="CoffeeScriptSwitchStatementWithNoDefaultBranch" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="CoffeeScriptUnusedLocalSymbols" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="ComposeFileStructure" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="CssFloatPxLength" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="CssInvalidAtRule" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="CssInvalidCharsetRule" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="CssInvalidElement" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="CssInvalidFunction" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="CssInvalidHtmlTagReference" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="CssInvalidImport" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="CssInvalidMediaFeature" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="CssInvalidPropertyValue" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="CssInvalidPseudoSelector" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="CssMissingComma" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="CssNegativeValue" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="CssNoGenericFontName" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="CssOptimizeSimilarProperties" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="CssOverwrittenProperties" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="CssRedundantUnit" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="CssUnitlessNumber" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="CssUnknownProperty" enabled="false" level="WARNING" enabled_by_default="false">
|
||||
<option name="myCustomPropertiesEnabled" value="false" />
|
||||
<option name="myIgnoreVendorSpecificProperties" value="false" />
|
||||
<option name="myCustomPropertiesList">
|
||||
<value>
|
||||
<list size="0" />
|
||||
</value>
|
||||
</option>
|
||||
<inspection_tool class="InconsistentLineSeparators" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="PhpIncludeInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="PhpMethodParametersCountMismatchInspection" enabled="true" level="ERROR" enabled_by_default="true" />
|
||||
<inspection_tool class="PhpTooManyParametersInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="limit" value="7" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="CssUnknownTarget" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="CssUnresolvedClass" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="CssUnresolvedCustomProperty" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="CssUnresolvedCustomPropertySet" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="CssUnusedSymbol" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="CucumberExamplesColon" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="CucumberMissedExamples" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="CucumberTableInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="CucumberUndefinedStep" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="DockerFileArgumentCount" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="DuplicateKeyInSection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="DuplicateSectionInFile" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="EmptyEventHandler" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="FileHeaderInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="GherkinBrokenTableInspection" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="GherkinMisplacedBackground" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="HamlNestedTagContent" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="HardwiredNamespacePrefix" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="HtmlDeprecatedTag" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="HtmlExtraClosingTag" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="HtmlFormInputWithoutLabel" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="HtmlMissingClosingTag" enabled="false" level="INFORMATION" enabled_by_default="false" />
|
||||
<inspection_tool class="HtmlPresentationalElement" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="HtmlUnknownAnchorTarget" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="HtmlUnknownAttribute" enabled="false" level="WARNING" enabled_by_default="false">
|
||||
<option name="myValues">
|
||||
<value>
|
||||
<list size="0" />
|
||||
</value>
|
||||
</option>
|
||||
<option name="myCustomValuesEnabled" value="true" />
|
||||
<inspection_tool class="PhpUndefinedClassInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="DONT_REPORT_MULTI_RESOLVE" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="HtmlUnknownBooleanAttribute" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="HtmlUnknownTag" enabled="false" level="WARNING" enabled_by_default="false">
|
||||
<option name="myValues">
|
||||
<value>
|
||||
<list size="6">
|
||||
<item index="0" class="java.lang.String" itemvalue="nobr" />
|
||||
<item index="1" class="java.lang.String" itemvalue="noembed" />
|
||||
<item index="2" class="java.lang.String" itemvalue="comment" />
|
||||
<item index="3" class="java.lang.String" itemvalue="noscript" />
|
||||
<item index="4" class="java.lang.String" itemvalue="embed" />
|
||||
<item index="5" class="java.lang.String" itemvalue="script" />
|
||||
</list>
|
||||
</value>
|
||||
</option>
|
||||
<option name="myCustomValuesEnabled" value="true" />
|
||||
<inspection_tool class="PhpUnhandledExceptionInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="PhpUnusedParameterInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
||||
<option name="DONT_REPORT_ABSTRACT_CLASS" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="HtmlUnknownTarget" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="ImplicitTypeConversion" enabled="false" level="WARNING" enabled_by_default="false">
|
||||
<option name="BITS" value="1720" />
|
||||
<option name="FLAG_EXPLICIT_CONVERSION" value="true" />
|
||||
<option name="IGNORE_NODESET_TO_BOOLEAN_VIA_STRING" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="IndexZeroUsage" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="JSLastCommaInArrayLiteral" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="JSLastCommaInObjectLiteral" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="JSUnresolvedFunction" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="JSUnresolvedVariable" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="LossyEncoding" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="MissingSinceTagDocInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="MysqlParsingInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="NonAsciiCharacters" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="PhpDocMissingReturnTagInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="PhpDocMissingThrowsInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="PhpIncludeInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="PhpRedundantClosingTagInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="PhpUndefinedClassConstantInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="PhpUndefinedClassInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="PhpUndefinedConstantInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="PhpUndefinedFieldInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="PhpUndefinedFunctionInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="PhpUndefinedGotoLabelInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="PhpUndefinedMethodInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="PhpUndefinedNamespaceInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="PhpUnusedParameterInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="RedundantTypeConversion" enabled="false" level="WARNING" enabled_by_default="false">
|
||||
<option name="CHECK_ANY" value="false" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="RequiredAttributes" enabled="false" level="WARNING" enabled_by_default="false">
|
||||
<option name="myAdditionalRequiredHtmlAttributes" value="" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="SqlAddNotNullColumnInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlAmbiguousColumnInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlAutoIncrementDuplicateInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlCheckUsingColumnsInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlConstantConditionInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlDeprecateTypeInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlDerivedTableAliasInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlDialectInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlDropIndexedColumnInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlIdentifierInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlInsertValuesInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlNoDataSourceInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlNullComparisonInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlPostgresqlSelectFromProcedureInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlResolveInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlShouldBeInGroupByInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlSignatureInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlStorageInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlTypeInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlUnusedVariableInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="TaskProblemsInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="TypeScriptPreferShortImport" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="XmlDefaultAttributeValue" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="XmlUnboundNsPrefix" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="XmlUnusedNamespaceDeclaration" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="XsltUnusedDeclaration" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="XsltVariableShadowing" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
</profile>
|
||||
</component>
|
||||
6
.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
6
.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<settings>
|
||||
<option name="PROJECT_PROFILE" value="Combodo" />
|
||||
<version value="1.0" />
|
||||
</settings>
|
||||
</component>
|
||||
47
.make/release/update-versions.php
Normal file
47
.make/release/update-versions.php
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
/*******************************************************************************
|
||||
* Tool to automate version update before release
|
||||
*
|
||||
* Will update version in the following files :
|
||||
*
|
||||
* * datamodels/2.x/.../module.*.php
|
||||
* * datamodels/2.x/version.xml
|
||||
* * css/css-variables.scss $version
|
||||
*
|
||||
* Usage :
|
||||
* `php .make\release\update-versions.php "2.7.0-rc"`
|
||||
*
|
||||
* @since 2.7.0
|
||||
******************************************************************************/
|
||||
|
||||
|
||||
|
||||
require_once (__DIR__.'/../../approot.inc.php');
|
||||
require_once (__DIR__.DIRECTORY_SEPARATOR.'update.classes.inc.php');
|
||||
|
||||
|
||||
|
||||
/** @var \FileVersionUpdater[] $aFilesUpdaters */
|
||||
$aFilesUpdaters = array(
|
||||
new iTopVersionFileUpdater(),
|
||||
new CssVariablesFileUpdater(),
|
||||
new DatamodelsModulesFiles(),
|
||||
);
|
||||
|
||||
if (count($argv) === 1)
|
||||
{
|
||||
echo '/!\ You must pass the new version as parameter';
|
||||
exit(1);
|
||||
}
|
||||
$sVersionLabel = $argv[1];
|
||||
if (empty($sVersionLabel))
|
||||
{
|
||||
echo 'Version passed as parameter is empty !';
|
||||
exit(2);
|
||||
}
|
||||
|
||||
foreach ($aFilesUpdaters as $oFileVersionUpdater)
|
||||
{
|
||||
$oFileVersionUpdater->UpdateAllFiles($sVersionLabel);
|
||||
}
|
||||
36
.make/release/update-xml.php
Normal file
36
.make/release/update-xml.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
/*******************************************************************************
|
||||
* Tool to automate datamodel version update in XML
|
||||
*
|
||||
* Will update version in the following files :
|
||||
*
|
||||
* datamodels/2.x/.../datamodel.*.xml
|
||||
*
|
||||
* Usage :
|
||||
* `php .make\release\update-xml.php "1.7"`
|
||||
*
|
||||
* @since 2.7.0
|
||||
******************************************************************************/
|
||||
|
||||
|
||||
|
||||
require_once (__DIR__.'/../../approot.inc.php');
|
||||
require_once (__DIR__.DIRECTORY_SEPARATOR.'update.classes.inc.php');
|
||||
|
||||
|
||||
|
||||
if (count($argv) === 1)
|
||||
{
|
||||
echo '/!\ You must pass the new version as parameter';
|
||||
exit(1);
|
||||
}
|
||||
$sVersionLabel = $argv[1];
|
||||
if (empty($sVersionLabel))
|
||||
{
|
||||
echo 'Version passed as parameter is empty !';
|
||||
exit(2);
|
||||
}
|
||||
|
||||
$oFileVersionUpdater = new DatamodelsXmlFiles();
|
||||
$oFileVersionUpdater->UpdateAllFiles($sVersionLabel);
|
||||
169
.make/release/update.classes.inc.php
Normal file
169
.make/release/update.classes.inc.php
Normal file
@@ -0,0 +1,169 @@
|
||||
<?php
|
||||
|
||||
/*******************************************************************************
|
||||
* Classes for updater tools
|
||||
*
|
||||
* @see update-versions.php
|
||||
* @see update-xml.php
|
||||
******************************************************************************/
|
||||
|
||||
|
||||
|
||||
require_once (__DIR__.'/../../approot.inc.php');
|
||||
|
||||
|
||||
|
||||
|
||||
abstract class FileVersionUpdater
|
||||
{
|
||||
/**
|
||||
* @return string[] full path of files to modify
|
||||
*/
|
||||
abstract public function GetFiles();
|
||||
|
||||
/**
|
||||
* Warnign : will consume lots of memory on larger files !
|
||||
*
|
||||
* @param string $sVersionLabel
|
||||
* @param string $sFileContent
|
||||
* @param string $sFileFullPath
|
||||
*
|
||||
* @return string file content with replaced values
|
||||
*/
|
||||
abstract public function UpdateFileContent($sVersionLabel, $sFileContent, $sFileFullPath);
|
||||
|
||||
public function UpdateAllFiles($sVersionLabel)
|
||||
{
|
||||
$aFilesToUpdate = $this->GetFiles();
|
||||
$sFileUpdaterName = get_class($this);
|
||||
echo "# Updater : $sFileUpdaterName\n";
|
||||
foreach ($aFilesToUpdate as $sFileToUpdateFullPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
$sCurrentFileContent = file_get_contents($sFileToUpdateFullPath);
|
||||
$sNewFileContent = $this->UpdateFileContent($sVersionLabel, $sCurrentFileContent, $sFileToUpdateFullPath);
|
||||
file_put_contents($sFileToUpdateFullPath, $sNewFileContent);
|
||||
echo " - $sFileToUpdateFullPath : OK !\n";
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
echo " - $sFileToUpdateFullPath : Error :(\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
abstract class AbstractSingleFileVersionUpdater extends FileVersionUpdater
|
||||
{
|
||||
private $sFileToUpdate;
|
||||
|
||||
public function __construct($sFileToUpdate)
|
||||
{
|
||||
$this->sFileToUpdate = $sFileToUpdate;
|
||||
}
|
||||
|
||||
public function GetFiles()
|
||||
{
|
||||
return array(APPROOT.$this->sFileToUpdate);
|
||||
}
|
||||
}
|
||||
|
||||
class iTopVersionFileUpdater extends AbstractSingleFileVersionUpdater
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct('datamodels/2.x/version.xml');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function UpdateFileContent($sVersionLabel, $sFileContent, $sFileFullPath)
|
||||
{
|
||||
return preg_replace(
|
||||
'/(<version>)[^<]*(<\/version>)/',
|
||||
'${1}'.$sVersionLabel.'${2}',
|
||||
$sFileContent
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class CssVariablesFileUpdater extends AbstractSingleFileVersionUpdater
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct('css/css-variables.scss');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function UpdateFileContent($sVersionLabel, $sFileContent, $sFileFullPath)
|
||||
{
|
||||
return preg_replace(
|
||||
'/(\$version: "v)[^"]*(";)/',
|
||||
'${1}'.$sVersionLabel.'${2}',
|
||||
$sFileContent
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class AbstractGlobFileVersionUpdater extends FileVersionUpdater
|
||||
{
|
||||
protected $sGlobPattern;
|
||||
|
||||
public function __construct($sGlobPattern)
|
||||
{
|
||||
$this->sGlobPattern = $sGlobPattern;
|
||||
}
|
||||
|
||||
public function GetFiles()
|
||||
{
|
||||
return glob($this->sGlobPattern);
|
||||
}
|
||||
}
|
||||
|
||||
class DatamodelsModulesFiles extends AbstractGlobFileVersionUpdater
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct(APPROOT.'datamodels/2.x/*/module.*.php');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function UpdateFileContent($sVersionLabel, $sFileContent, $sFileFullPath)
|
||||
{
|
||||
$sModulePath = realpath($sFileFullPath);
|
||||
$sModuleFileName = basename($sModulePath, 1);
|
||||
$sModuleName = preg_replace('/[^.]+\.([^.]+)\.php/', '$1', $sModuleFileName);
|
||||
|
||||
return preg_replace(
|
||||
"/('$sModuleName\/)[^']+(')/",
|
||||
'${1}'.$sVersionLabel.'${2}',
|
||||
$sFileContent
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class DatamodelsXmlFiles extends AbstractGlobFileVersionUpdater
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct(APPROOT.'datamodels/2.x/*/datamodel.*.xml');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function UpdateFileContent($sVersionLabel, $sFileContent, $sFileFullPath)
|
||||
{
|
||||
return preg_replace(
|
||||
'/(<itop_design .* version=")[^"]+(">)/',
|
||||
'${1}'.$sVersionLabel.'${2}',
|
||||
$sFileContent
|
||||
);
|
||||
}
|
||||
}
|
||||
141
README.md
Normal file
141
README.md
Normal file
@@ -0,0 +1,141 @@
|
||||
<p align="center"><a href="https://www.combodo.com/itop-193" target="_blank">
|
||||
<img src="https://www.combodo.com/logos/logo-itop.svg">
|
||||
</a></p>
|
||||
|
||||
|
||||
# iTop - ITSM & CMDB
|
||||
|
||||
iTop stands for *IT Operations Portal*.
|
||||
It is a complete open source, ITIL, web based service management tool including a fully customizable CMDB, a helpdesk system and a document management tool.
|
||||
iTop also offers mass import tools and web services to integrate with your IT
|
||||
|
||||
## Features
|
||||
- Fully configurable [Configuration Management (CMDB)][10]
|
||||
- [HelpDesk][11] and Incident Management
|
||||
- [Service and Contract Management][12]
|
||||
- [Change][13] Management
|
||||
- Configurable [SLA][14] Management
|
||||
- Graphical [impact analysis][15]
|
||||
- [CSV import][16] tool for any data
|
||||
- Consistency [audit][17] to check data quality
|
||||
- [Data synchronization][18] (for data federation)
|
||||
|
||||
|
||||
## Resources
|
||||
|
||||
- [iTop Forums][1]: for support request
|
||||
- [iTop Tickets][2]: for feature requests and bug reports
|
||||
- [Releases download][3]
|
||||
- [iTop documentation][4] for iTop and official extensions
|
||||
- [iTop extensions][5] for discovering and installing extensions
|
||||
|
||||
|
||||
## Releases
|
||||
### Version 2.6
|
||||
- [Changes since the previous version][58]
|
||||
- [New features][59]
|
||||
- [Migration notes][60]
|
||||
- [Download iTop 2.6.3][61]
|
||||
|
||||
|
||||
### Version 2.5
|
||||
- [Changes since the previous version][54]
|
||||
- [New features][55]
|
||||
- [Migration notes][56]
|
||||
- [Download iTop 2.5.1][57]
|
||||
|
||||
|
||||
### Version 2.4
|
||||
- [Changes since the previous version][50]
|
||||
- [New features][51]
|
||||
- [Migration notes][52]
|
||||
- [Download iTop 2.4.1][53]
|
||||
|
||||
|
||||
# About Us
|
||||
|
||||
iTop development is sponsored, led and supported by [Combodo][0].
|
||||
|
||||
|
||||
# Contributors
|
||||
|
||||
We would like to give a special thank you to the people from the community who contributed to this project, including:
|
||||
- Alves, David
|
||||
- Beck, Pedro
|
||||
- Bilger, Jean-François
|
||||
- Bostoen, Jeffrey
|
||||
- Cardoso, Anderson
|
||||
- Cassaro, Bruno
|
||||
- Casteleyn, Thomas
|
||||
- Castro, Randall Badilla
|
||||
- Colantoni, Maria Laura
|
||||
- Dvořák, Lukáš
|
||||
- Goethals, Stefan
|
||||
- Gumble, David
|
||||
- Hippler, Lars
|
||||
- Khamit, Shamil
|
||||
- Kincel, Martin
|
||||
- Konečný, Kamil
|
||||
- Kunin, Vladimir
|
||||
- Lassiter, Dennis
|
||||
- Lucas, Jonathan
|
||||
- Malik, Remie
|
||||
- Rosenke, Stephan
|
||||
- Seki, Shoji
|
||||
- Shilov, Vladimir
|
||||
- Tulio, Marco
|
||||
- Turrubiates, Miguel
|
||||
|
||||
#### Aliases
|
||||
- chifu1234
|
||||
- cprobst
|
||||
- Karkoff1212
|
||||
- larhip
|
||||
- Laura
|
||||
- Purple Grape
|
||||
- Schlobinux
|
||||
- theBigOne
|
||||
- ulmerspatz
|
||||
|
||||
#### Companies
|
||||
- Hardis
|
||||
- ITOMIG
|
||||
|
||||
|
||||
|
||||
[0]: https://www.combodo.com
|
||||
|
||||
[1]: https://sourceforge.net/p/itop/discussion/
|
||||
[2]: https://sourceforge.net/p/itop/tickets/
|
||||
[3]: https://sourceforge.net/projects/itop/files/itop/
|
||||
[4]: https://www.itophub.io/wiki
|
||||
[5]: https://store.itophub.io/en_US/
|
||||
|
||||
|
||||
|
||||
[10]: https://www.itophub.io/wiki/page?id=2_5_0%3Adatamodel%3Astart#configuration_management_cmdb
|
||||
[11]: https://www.itophub.io/wiki/page?id=2_5_0%3Adatamodel%3Astart#ticketing
|
||||
[12]: https://www.itophub.io/wiki/page?id=2_5_0%3Adatamodel%3Astart#service_management
|
||||
[13]: https://www.itophub.io/wiki/page?id=2_5_0%3Adatamodel%3Astart#change_management
|
||||
[14]: https://www.itophub.io/wiki/page?id=2_5_0%3Aimplementation%3Astart#service_level_agreements_and_targets
|
||||
[15]: https://www.itophub.io/wiki/page?id=2_5_0%3Auser%3Aactions#relations
|
||||
[16]: https://www.itophub.io/wiki/page?id=2_5_0%3Auser%3Abulk_modify#uploading_data
|
||||
[17]: https://www.itophub.io/wiki/page?id=2_5_0%3Aadmin%3Aaudit
|
||||
[18]: https://www.itophub.io/wiki/page?id=2_5_0%3Aadvancedtopics%3Adata_synchro_overview
|
||||
|
||||
|
||||
|
||||
[50]: https://www.itophub.io/wiki/page?id=2_4_0:release:change_log
|
||||
[51]: https://www.itophub.io/wiki/page?id=2_4_0:release:2_4_whats_new
|
||||
[52]: https://www.itophub.io/wiki/page?id=2_4_0:install:230_to_240_migration_notes
|
||||
[53]: https://sourceforge.net/projects/itop/files/itop/2.4.1
|
||||
|
||||
[54]: https://www.itophub.io/wiki/page?id=2_5_0:release:change_log
|
||||
[55]: https://www.itophub.io/wiki/page?id=2_5_0:release:2_5_whats_new
|
||||
[56]: https://www.itophub.io/wiki/page?id=2_5_0:install:240_to_250_migration_notes
|
||||
[57]: https://sourceforge.net/projects/itop/files/itop/2.5.1
|
||||
|
||||
[58]: https://www.itophub.io/wiki/page?id=2_6_0:release:change_log
|
||||
[59]: https://www.itophub.io/wiki/page?id=2_6_0:release:2_6_whats_new
|
||||
[60]: https://www.itophub.io/wiki/page?id=2_6_0:install:250_to_260_migration_notes
|
||||
[61]: https://sourceforge.net/projects/itop/files/itop/2.6.3
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
// Copyright (C) 2010-2018 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -20,7 +20,7 @@
|
||||
/**
|
||||
* Class ApplicationContext
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @copyright Copyright (C) 2010-2018 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
@@ -31,6 +31,12 @@ require_once(APPROOT."/application/utils.inc.php");
|
||||
*/
|
||||
interface iDBObjectURLMaker
|
||||
{
|
||||
/**
|
||||
* @param string $sClass
|
||||
* @param string $iId
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function MakeObjectURL($sClass, $iId);
|
||||
}
|
||||
|
||||
@@ -39,6 +45,13 @@ interface iDBObjectURLMaker
|
||||
*/
|
||||
class iTopStandardURLMaker implements iDBObjectURLMaker
|
||||
{
|
||||
/**
|
||||
* @param string $sClass
|
||||
* @param string $iId
|
||||
*
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function MakeObjectURL($sClass, $iId)
|
||||
{
|
||||
$sPage = DBObject::ComputeStandardUIPage($sClass);
|
||||
@@ -53,6 +66,13 @@ class iTopStandardURLMaker implements iDBObjectURLMaker
|
||||
*/
|
||||
class PortalURLMaker implements iDBObjectURLMaker
|
||||
{
|
||||
/**
|
||||
* @param string $sClass
|
||||
* @param string $iId
|
||||
*
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function MakeObjectURL($sClass, $iId)
|
||||
{
|
||||
$sAbsoluteUrl = utils::GetAbsoluteUrlAppRoot();
|
||||
@@ -74,10 +94,20 @@ class PortalURLMaker implements iDBObjectURLMaker
|
||||
*/
|
||||
class ApplicationContext
|
||||
{
|
||||
public static $m_sUrlMakerClass = null;
|
||||
protected static $m_aPluginProperties = null;
|
||||
protected static $aDefaultValues; // Cache shared among all instances
|
||||
|
||||
protected $aNames;
|
||||
protected $aValues;
|
||||
protected static $aDefaultValues; // Cache shared among all instances
|
||||
|
||||
|
||||
/**
|
||||
* ApplicationContext constructor.
|
||||
*
|
||||
* @param bool $bReadContext
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function __construct($bReadContext = true)
|
||||
{
|
||||
$this->aNames = array(
|
||||
@@ -89,11 +119,13 @@ class ApplicationContext
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the context directly in the PHP parameters (either POST or GET)
|
||||
* return nothing
|
||||
*/
|
||||
|
||||
/**
|
||||
* Read the context directly in the PHP parameters (either POST or GET)
|
||||
* return nothing
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function ReadContext()
|
||||
{
|
||||
if (!isset(self::$aDefaultValues))
|
||||
@@ -110,20 +142,26 @@ class ApplicationContext
|
||||
}
|
||||
// Hmm, there must be a better (more generic) way to handle the case below:
|
||||
// When there is only one possible (allowed) organization, the context must be
|
||||
// fixed to this org
|
||||
// fixed to this org unless there is only one organization in the system then
|
||||
// no filter is applied
|
||||
if ($sName == 'org_id')
|
||||
{
|
||||
if (MetaModel::IsValidClass('Organization'))
|
||||
{
|
||||
$oSearchFilter = new DBObjectSearch('Organization');
|
||||
$oSearchFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', true);
|
||||
$oSet = new CMDBObjectSet($oSearchFilter);
|
||||
$iCount = $oSet->CountWithLimit(2);
|
||||
if ($iCount == 1)
|
||||
if ($iCount > 1)
|
||||
{
|
||||
// Only one possible value for org_id, set it in the context
|
||||
$oOrg = $oSet->Fetch();
|
||||
self::$aDefaultValues[$sName] = $oOrg->GetKey();
|
||||
$oSearchFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', true);
|
||||
$oSet = new CMDBObjectSet($oSearchFilter);
|
||||
$iCount = $oSet->CountWithLimit(2);
|
||||
if ($iCount == 1)
|
||||
{
|
||||
// Only one possible value for org_id, set it in the context
|
||||
$oOrg = $oSet->Fetch();
|
||||
self::$aDefaultValues[$sName] = $oOrg->GetKey();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -131,12 +169,15 @@ class ApplicationContext
|
||||
}
|
||||
$this->aValues = self::$aDefaultValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current value for the given parameter
|
||||
* @param string $sParamName Name of the parameter to read
|
||||
* @return mixed The value for this parameter
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns the current value for the given parameter
|
||||
*
|
||||
* @param string $sParamName Name of the parameter to read
|
||||
* @param string $defaultValue
|
||||
*
|
||||
* @return mixed The value for this parameter
|
||||
*/
|
||||
public function GetCurrentValue($sParamName, $defaultValue = '')
|
||||
{
|
||||
if (isset($this->aValues[$sParamName]))
|
||||
@@ -148,7 +189,7 @@ class ApplicationContext
|
||||
|
||||
/**
|
||||
* Returns the context as string with the format name1=value1&name2=value2....
|
||||
* return string The context as a string to be appended to an href property
|
||||
* @return string The context as a string to be appended to an href property
|
||||
*/
|
||||
public function GetForLink()
|
||||
{
|
||||
@@ -162,7 +203,7 @@ class ApplicationContext
|
||||
|
||||
/**
|
||||
* Returns the context as sequence of input tags to be inserted inside a <form> tag
|
||||
* return string The context as a sequence of <input type="hidden" /> tags
|
||||
* @return string The context as a sequence of <input type="hidden" /> tags
|
||||
*/
|
||||
public function GetForForm()
|
||||
{
|
||||
@@ -176,7 +217,7 @@ class ApplicationContext
|
||||
|
||||
/**
|
||||
* Returns the context as a hash array 'parameter_name' => value
|
||||
* return array The context information
|
||||
* @return array The context information
|
||||
*/
|
||||
public function GetAsHash()
|
||||
{
|
||||
@@ -199,8 +240,7 @@ class ApplicationContext
|
||||
/**
|
||||
* Removes the specified parameter from the context, for example when the same parameter
|
||||
* is already a search parameter
|
||||
* @param string $sParamName Name of the parameter to remove
|
||||
* @return none
|
||||
* @param string $sParamName Name of the parameter to remove
|
||||
*/
|
||||
public function Reset($sParamName)
|
||||
{
|
||||
@@ -212,6 +252,11 @@ class ApplicationContext
|
||||
|
||||
/**
|
||||
* Initializes the given object with the default values provided by the context
|
||||
*
|
||||
* @param \DBObject $oObj
|
||||
*
|
||||
* @throws \Exception
|
||||
* @throws \CoreUnexpectedValue
|
||||
*/
|
||||
public function InitObjectFromContext(DBObject &$oObj)
|
||||
{
|
||||
@@ -238,13 +283,11 @@ class ApplicationContext
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static $m_sUrlMakerClass = null;
|
||||
|
||||
/**
|
||||
* Set the current application url provider
|
||||
* @param sClass string Class implementing iDBObjectURLMaker
|
||||
* @return void
|
||||
* @param string $sClass Class implementing iDBObjectURLMaker
|
||||
* @return string
|
||||
*/
|
||||
public static function SetUrlMakerClass($sClass = 'iTopStandardURLMaker')
|
||||
{
|
||||
@@ -278,7 +321,14 @@ class ApplicationContext
|
||||
|
||||
/**
|
||||
* Get the current application url provider
|
||||
*
|
||||
* @param string $sObjClass
|
||||
* @param string $sObjKey
|
||||
* @param null $sUrlMakerClass
|
||||
* @param bool $bWithNavigationContext
|
||||
*
|
||||
* @return string the name of the class
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function MakeObjectUrl($sObjClass, $sObjKey, $sUrlMakerClass = null, $bWithNavigationContext = true)
|
||||
{
|
||||
@@ -306,8 +356,6 @@ class ApplicationContext
|
||||
}
|
||||
}
|
||||
|
||||
protected static $m_aPluginProperties = null;
|
||||
|
||||
/**
|
||||
* Load plugin properties for the current session
|
||||
* @return void
|
||||
@@ -326,9 +374,9 @@ class ApplicationContext
|
||||
|
||||
/**
|
||||
* Set plugin properties
|
||||
* @param sPluginClass string Class implementing any plugin interface
|
||||
* @param sProperty string Name of the property
|
||||
* @param value scalar Value (numeric or string)
|
||||
* @param string $sPluginClass Class implementing any plugin interface
|
||||
* @param string $sProperty Name of the property
|
||||
* @param mixed $value Value (numeric or string)
|
||||
* @return void
|
||||
*/
|
||||
public static function SetPluginProperty($sPluginClass, $sProperty, $value)
|
||||
@@ -341,7 +389,7 @@ class ApplicationContext
|
||||
|
||||
/**
|
||||
* Get plugin properties
|
||||
* @param sPluginClass string Class implementing any plugin interface
|
||||
* @param string $sPluginClass Class implementing any plugin interface
|
||||
* @return array of sProperty=>value pairs
|
||||
*/
|
||||
public static function GetPluginProperties($sPluginClass)
|
||||
@@ -359,4 +407,3 @@ class ApplicationContext
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
require_once(APPROOT.'application/newsroomprovider.class.inc.php');
|
||||
|
||||
/**
|
||||
* Management of application plugins
|
||||
*
|
||||
@@ -122,7 +124,8 @@ interface iApplicationUIExtension
|
||||
* Sorry, the verb has been reserved. You must implement it, but it is not called as of now.
|
||||
*
|
||||
* @param DBObject $oObject The object being displayed
|
||||
* @return type desc
|
||||
*
|
||||
* @return string[] desc
|
||||
*/
|
||||
public function EnumUsedAttributes($oObject); // Not yet implemented
|
||||
|
||||
@@ -362,7 +365,7 @@ interface iPopupMenuExtension
|
||||
* Base class for the various types of custom menus
|
||||
*
|
||||
* @package Extensibility
|
||||
* @internal
|
||||
* @api
|
||||
* @since 2.0
|
||||
*/
|
||||
abstract class ApplicationPopupMenuItem
|
||||
@@ -375,8 +378,10 @@ abstract class ApplicationPopupMenuItem
|
||||
protected $aCssClasses;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* Constructor
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @param string $sUID The unique identifier of this menu in iTop... make sure you pass something unique enough
|
||||
* @param string $sLabel The display label of the menu (must be localized)
|
||||
* @param array $aCssClasses The CSS classes to add to the menu
|
||||
@@ -441,8 +446,9 @@ abstract class ApplicationPopupMenuItem
|
||||
|
||||
/**
|
||||
* Returns the components to create a popup menu item in HTML
|
||||
* @return Hash A hash array: array('label' => , 'url' => , 'target' => , 'onclick' => )
|
||||
* @ignore
|
||||
*
|
||||
* @return array A hash array: array('label' => , 'url' => , 'target' => , 'onclick' => )
|
||||
* @ignore
|
||||
*/
|
||||
abstract public function GetMenuItem();
|
||||
|
||||
@@ -505,6 +511,9 @@ class JSPopupMenuItem extends ApplicationPopupMenuItem
|
||||
|
||||
/**
|
||||
* Class for adding an item that triggers some Javascript code
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @param string $sUID The unique identifier of this menu in iTop... make sure you pass something unique enough
|
||||
* @param string $sLabel The display label of the menu (must be localized)
|
||||
* @param string $sJSCode In case the menu consists in executing some havascript code inside the page, pass it here. If supplied $sURL ans $sTarget will be ignored
|
||||
@@ -759,11 +768,15 @@ interface iRestServiceProvider
|
||||
* @return array An array of hash 'verb' => verb, 'description' => description
|
||||
*/
|
||||
public function ListOperations($sVersion);
|
||||
|
||||
/**
|
||||
* Enumerate services delivered by this class
|
||||
*
|
||||
* @param string $sVersion The version (e.g. 1.0) supported by the services
|
||||
* @param string $sVerb
|
||||
* @param array $aParams
|
||||
*
|
||||
* @return RestResult The standardized result structure (at least a message)
|
||||
* @throws Exception in case of internal failure.
|
||||
*/
|
||||
public function ExecOperation($sVersion, $sVerb, $aParams);
|
||||
}
|
||||
@@ -870,7 +883,7 @@ class RestUtils
|
||||
* @param StdClass $oData Structured input data. Must contain the entry defined by sParamName.
|
||||
* @param string $sParamName Name of the parameter to fetch from the input data
|
||||
*
|
||||
* @return string
|
||||
* @return mixed parameter value if present
|
||||
* @throws Exception If the parameter is missing
|
||||
* @api
|
||||
*/
|
||||
@@ -893,7 +906,8 @@ class RestUtils
|
||||
* @param StdClass $oData Structured input data.
|
||||
* @param string $sParamName Name of the parameter to fetch from the input data
|
||||
* @param mixed $default Default value if the parameter is not found in the input data
|
||||
* @return void
|
||||
*
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
* @api
|
||||
*/
|
||||
@@ -937,7 +951,8 @@ class RestUtils
|
||||
* @param string $sClass Name of the class
|
||||
* @param StdClass $oData Structured input data.
|
||||
* @param string $sParamName Name of the parameter to fetch from the input data
|
||||
* @return An array of class => list of attributes (see RestResultWithObjects::AddObject that uses it)
|
||||
*
|
||||
* @return array of class => list of attributes (see RestResultWithObjects::AddObject that uses it)
|
||||
* @throws Exception
|
||||
* @api
|
||||
*/
|
||||
@@ -1120,7 +1135,6 @@ class RestUtils
|
||||
{
|
||||
// OQL
|
||||
$oSearch = DBObjectSearch::FromOQL($key);
|
||||
$oObjectSet = new DBObjectSet($oSearch);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1169,6 +1183,14 @@ class RestUtils
|
||||
}
|
||||
$value = DBObjectSet::FromArray($sLnkClass, $aLinks);
|
||||
}
|
||||
elseif ($oAttDef instanceof AttributeTagSet)
|
||||
{
|
||||
if (!is_array($value))
|
||||
{
|
||||
throw new Exception("A tag set must be defined by an array of tag codes");
|
||||
}
|
||||
$value = $oAttDef->FromJSONToValue($value);
|
||||
}
|
||||
else
|
||||
{
|
||||
$value = $oAttDef->FromJSONToValue($value);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -21,6 +21,7 @@ require_once(APPROOT.'application/dashlet.class.inc.php');
|
||||
require_once(APPROOT.'core/modelreflection.class.inc.php');
|
||||
|
||||
/**
|
||||
*
|
||||
* A user editable dashboard page
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2017 Combodo SARL
|
||||
@@ -49,6 +50,11 @@ abstract class Dashboard
|
||||
$this->sId = $sId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $sXml
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function FromXml($sXml)
|
||||
{
|
||||
$this->aCells = array(); // reset the content of the dashboard
|
||||
@@ -100,10 +106,10 @@ abstract class Dashboard
|
||||
$oCellsList = $oCellsNode->getElementsByTagName('cell');
|
||||
$aCellOrder = array();
|
||||
$iCellRank = 0;
|
||||
/** @var \DOMElement $oCellNode */
|
||||
foreach($oCellsList as $oCellNode)
|
||||
{
|
||||
$aDashletList = array();
|
||||
$oCellRank = $oCellNode->getElementsByTagName('rank')->item(0);
|
||||
$oCellRank = $oCellNode->getElementsByTagName('rank')->item(0);
|
||||
if ($oCellRank)
|
||||
{
|
||||
$iCellRank = (float)$oCellRank->textContent;
|
||||
@@ -113,6 +119,7 @@ abstract class Dashboard
|
||||
$oDashletList = $oDashletsNode->getElementsByTagName('dashlet');
|
||||
$iRank = 0;
|
||||
$aDashletOrder = array();
|
||||
/** @var \DOMElement $oDomNode */
|
||||
foreach($oDashletList as $oDomNode)
|
||||
{
|
||||
$oRank = $oDomNode->getElementsByTagName('rank')->item(0);
|
||||
@@ -145,6 +152,11 @@ abstract class Dashboard
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \DOMElement $oDomNode
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function InitDashletFromDOMNode($oDomNode)
|
||||
{
|
||||
$sId = $oDomNode->getAttribute('id');
|
||||
@@ -152,7 +164,8 @@ abstract class Dashboard
|
||||
|
||||
// Test if dashlet can be instanciated, otherwise (uninstalled, broken, ...) we display a placeholder
|
||||
$sClass = static::GetDashletClassFromType($sDashletType);
|
||||
$oNewDashlet = new $sClass($this->oMetaModel, $sId);
|
||||
/** @var \Dashlet $oNewDashlet */
|
||||
$oNewDashlet = new $sClass($this->oMetaModel, $sId);
|
||||
$oNewDashlet->SetDashletType($sDashletType);
|
||||
$oNewDashlet->FromDOMNode($oDomNode);
|
||||
|
||||
@@ -163,8 +176,17 @@ abstract class Dashboard
|
||||
{
|
||||
return ($aItem1['rank'] > $aItem2['rank']) ? +1 : -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Error handler to turn XML loading warnings into exceptions
|
||||
*
|
||||
* @param $errno
|
||||
* @param $errstr
|
||||
* @param $errfile
|
||||
* @param $errline
|
||||
*
|
||||
* @return bool
|
||||
* @throws \DOMException
|
||||
*/
|
||||
public static function ErrorHandler($errno, $errstr, $errfile, $errline)
|
||||
{
|
||||
@@ -194,8 +216,12 @@ abstract class Dashboard
|
||||
return $sXml;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \DOMElement $oDefinition
|
||||
*/
|
||||
public function ToDOMNode($oDefinition)
|
||||
{
|
||||
/** @var \DOMDocument $oDoc */
|
||||
$oDoc = $oDefinition->ownerDocument;
|
||||
|
||||
$oNode = $oDoc->createElement('layout', $this->sLayoutClass);
|
||||
@@ -227,6 +253,7 @@ abstract class Dashboard
|
||||
$iDashletRank = 0;
|
||||
$oDashletsNode = $oDoc->createElement('dashlets');
|
||||
$oCellNode->appendChild($oDashletsNode);
|
||||
/** @var \Dashlet $oDashlet */
|
||||
foreach ($aCell as $oDashlet)
|
||||
{
|
||||
$oNode = $oDoc->createElement('dashlet');
|
||||
@@ -256,6 +283,7 @@ abstract class Dashboard
|
||||
{
|
||||
$sDashletClass = $aDashletParams['dashlet_class'];
|
||||
$sId = $aDashletParams['dashlet_id'];
|
||||
/** @var \Dashlet $oNewDashlet */
|
||||
$oNewDashlet = new $sDashletClass($this->oMetaModel, $sId);
|
||||
if (isset($aDashletParams['dashlet_type']))
|
||||
{
|
||||
@@ -318,31 +346,28 @@ abstract class Dashboard
|
||||
$this->iAutoReloadSec = max(MetaModel::GetConfig()->Get('min_reload_interval'), (int)$iAutoReloadSec);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Dashlet $oDashlet
|
||||
*/
|
||||
public function AddDashlet($oDashlet)
|
||||
{
|
||||
$sId = $this->GetNewDashletId();
|
||||
$oDashlet->SetId($sId);
|
||||
$this->aCells[] = array($oDashlet);
|
||||
}
|
||||
|
||||
public function Render($oPage, $bEditMode = false, $aExtraParams = array())
|
||||
{
|
||||
$oPage->add('<h1>'.htmlentities(Dict::S($this->sTitle), ENT_QUOTES, 'UTF-8', false).'</h1>');
|
||||
$oLayout = new $this->sLayoutClass;
|
||||
$oLayout->Render($oPage, $this->aCells, $bEditMode, $aExtraParams);
|
||||
if (!$bEditMode)
|
||||
{
|
||||
$oPage->add_linked_script('../js/dashlet.js');
|
||||
$oPage->add_linked_script('../js/dashboard.js');
|
||||
}
|
||||
}
|
||||
|
||||
public function RenderProperties($oPage)
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage *
|
||||
* @param array $aExtraParams
|
||||
*
|
||||
* @throws \ReflectionException
|
||||
*/
|
||||
public function RenderProperties($oPage, $aExtraParams = array())
|
||||
{
|
||||
// menu to pick a layout and edit other properties of the dashboard
|
||||
$oPage->add('<div class="ui-widget-content ui-corner-all"><div class="ui-widget-header ui-corner-all" style="text-align:center; padding: 2px;">'.Dict::S('UI:DashboardEdit:Properties').'</div>');
|
||||
$sUrl = utils::GetAbsoluteUrlAppRoot();
|
||||
|
||||
|
||||
$oPage->add('<div style="text-align:center">'.Dict::S('UI:DashboardEdit:Layout').'</div>');
|
||||
$oPage->add('<div id="select_layout" style="text-align:center">');
|
||||
foreach( get_declared_classes() as $sLayoutClass)
|
||||
@@ -360,13 +385,13 @@ abstract class Dashboard
|
||||
}
|
||||
}
|
||||
$oPage->add('</div>');
|
||||
|
||||
|
||||
$oForm = new DesignerForm();
|
||||
|
||||
$oField = new DesignerHiddenField('dashboard_id', '', $this->sId);
|
||||
$oForm->AddField($oField);
|
||||
|
||||
$oField = new DesignerLongTextField('dashboard_title', Dict::S('UI:DashboardEdit:DashboardTitle'), $this->sTitle);
|
||||
$oField = new DesignerTextField('dashboard_title', Dict::S('UI:DashboardEdit:DashboardTitle'), $this->sTitle);
|
||||
$oForm->AddField($oField);
|
||||
|
||||
$oField = new DesignerBooleanField('auto_reload', Dict::S('UI:DashboardEdit:AutoReload'), $this->bAutoReload);
|
||||
@@ -377,8 +402,8 @@ abstract class Dashboard
|
||||
$oForm->AddField($oField);
|
||||
|
||||
|
||||
$this->SetFormParams($oForm);
|
||||
$oForm->RenderAsPropertySheet($oPage, false, '.itop-dashboard');
|
||||
$this->SetFormParams($oForm, $aExtraParams);
|
||||
$oForm->RenderAsPropertySheet($oPage, false, '.itop-dashboard');
|
||||
|
||||
$oPage->add('</div>');
|
||||
|
||||
@@ -422,8 +447,28 @@ abstract class Dashboard
|
||||
EOF
|
||||
);
|
||||
}
|
||||
|
||||
public function RenderDashletsSelection($oPage)
|
||||
|
||||
/**
|
||||
* @param \iTopWebPage $oPage
|
||||
* @param bool $bEditMode
|
||||
* @param array $aExtraParams
|
||||
* @param bool $bCanEdit
|
||||
*/
|
||||
public function Render($oPage, $bEditMode = false, $aExtraParams = array(), $bCanEdit = true)
|
||||
{
|
||||
$oPage->add('<div class="dashboard-title-line"><div class="dashboard-title">'.htmlentities(Dict::S($this->sTitle), ENT_QUOTES, 'UTF-8', false).'</div></div>');
|
||||
|
||||
$oLayout = new $this->sLayoutClass;
|
||||
/** @var \DashboardLayoutMultiCol $oLayout */
|
||||
$oLayout->Render($oPage, $this->aCells, $bEditMode, $aExtraParams);
|
||||
if (!$bEditMode)
|
||||
{
|
||||
$oPage->add_linked_script('../js/dashlet.js');
|
||||
$oPage->add_linked_script('../js/dashboard.js');
|
||||
}
|
||||
}
|
||||
|
||||
public function RenderDashletsSelection(WebPage $oPage)
|
||||
{
|
||||
// Toolbox/palette to drag and drop dashlets
|
||||
$oPage->add('<div class="ui-widget-content ui-corner-all"><div class="ui-widget-header ui-corner-all" style="text-align:center; padding: 2px;">'.Dict::S('UI:DashboardEdit:Dashlets').'</div>');
|
||||
@@ -441,7 +486,7 @@ EOF
|
||||
$oPage->add_ready_script("$('.dashlet_icon').draggable({helper: 'clone', appendTo: 'body', zIndex: 10000, revert:'invalid'});");
|
||||
}
|
||||
|
||||
public function RenderDashletsProperties($oPage)
|
||||
public function RenderDashletsProperties(WebPage $oPage, $aExtraParams = array())
|
||||
{
|
||||
// Toolbox/palette to edit the properties of each dashlet
|
||||
$oPage->add('<div class="ui-widget-content ui-corner-all"><div class="ui-widget-header ui-corner-all" style="text-align:center; padding: 2px;">'.Dict::S('UI:DashboardEdit:DashletProperties').'</div>');
|
||||
@@ -449,15 +494,15 @@ EOF
|
||||
$oPage->add('<div id="dashlet_properties" style="text-align:center">');
|
||||
foreach($this->aCells as $aCell)
|
||||
{
|
||||
/** @var \Dashlet $oDashlet */
|
||||
foreach($aCell as $oDashlet)
|
||||
{
|
||||
$sId = $oDashlet->GetID();
|
||||
$sClass = get_class($oDashlet);
|
||||
if ($oDashlet->IsVisible())
|
||||
{
|
||||
$oPage->add('<div class="dashlet_properties" id="dashlet_properties_'.$sId.'" style="display:none">');
|
||||
$oForm = $oDashlet->GetForm();
|
||||
$this->SetFormParams($oForm);
|
||||
$this->SetFormParams($oForm, $aExtraParams);
|
||||
$oForm->RenderAsPropertySheet($oPage, false, '.itop-dashboard');
|
||||
$oPage->add('</div>');
|
||||
}
|
||||
@@ -472,6 +517,7 @@ EOF
|
||||
* Return an array of dashlets available for selection.
|
||||
*
|
||||
* @return array
|
||||
* @throws \ReflectionException
|
||||
*/
|
||||
protected function GetAvailableDashlets()
|
||||
{
|
||||
@@ -505,6 +551,7 @@ EOF
|
||||
$iNewId = 0;
|
||||
foreach($this->aCells as $aDashlets)
|
||||
{
|
||||
/** @var \Dashlet $oDashlet */
|
||||
foreach($aDashlets as $oDashlet)
|
||||
{
|
||||
$iNewId = max($iNewId, (int)$oDashlet->GetID());
|
||||
@@ -512,8 +559,14 @@ EOF
|
||||
}
|
||||
return $iNewId + 1;
|
||||
}
|
||||
|
||||
abstract protected function SetFormParams($oForm);
|
||||
|
||||
/**
|
||||
* @param $oForm
|
||||
* @param array $aExtraParams
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
abstract protected function SetFormParams($oForm, $aExtraParams = array());
|
||||
|
||||
public static function GetDashletClassFromType($sType, $oFactory = null)
|
||||
{
|
||||
@@ -523,11 +576,22 @@ EOF
|
||||
}
|
||||
return 'DashletUnknown';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function GetId()
|
||||
{
|
||||
return $this->sId;
|
||||
}
|
||||
}
|
||||
|
||||
class RuntimeDashboard extends Dashboard
|
||||
{
|
||||
protected $bCustomized;
|
||||
private $sDefinitionFile = '';
|
||||
private $sReloadURL = null;
|
||||
|
||||
|
||||
public function __construct($sId)
|
||||
{
|
||||
@@ -540,10 +604,17 @@ class RuntimeDashboard extends Dashboard
|
||||
{
|
||||
$this->bCustomized = $bCustomized;
|
||||
}
|
||||
|
||||
protected function SetFormParams($oForm)
|
||||
|
||||
/**
|
||||
* @param \DesignerForm $oForm
|
||||
*
|
||||
* @param array $aExtraParams
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function SetFormParams($oForm, $aExtraParams = array())
|
||||
{
|
||||
$oForm->SetSubmitParams(utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php', array('operation' => 'update_dashlet_property'));
|
||||
$oForm->SetSubmitParams(utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php', array('operation' => 'update_dashlet_property', 'extra_params' => $aExtraParams));
|
||||
}
|
||||
|
||||
public function Save()
|
||||
@@ -587,41 +658,265 @@ class RuntimeDashboard extends Dashboard
|
||||
utils::PopArchiveMode();
|
||||
}
|
||||
}
|
||||
|
||||
public function RenderEditionTools($oPage)
|
||||
|
||||
/**
|
||||
* @param string $sDashboardFile file name relative to the current module folder
|
||||
* @param string $sDashBoardId code of the dashboard either menu_id or <class>__<attcode>
|
||||
*
|
||||
* @return null|RuntimeDashboard
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
*/
|
||||
public static function GetDashboard($sDashboardFile, $sDashBoardId)
|
||||
{
|
||||
$bCustomized = false;
|
||||
|
||||
if (!appUserPreferences::GetPref('display_original_dashboard_'.$sDashBoardId, false))
|
||||
{
|
||||
// Search for an eventual user defined dashboard
|
||||
$oUDSearch = new DBObjectSearch('UserDashboard');
|
||||
$oUDSearch->AddCondition('user_id', UserRights::GetUserId(), '=');
|
||||
$oUDSearch->AddCondition('menu_code', $sDashBoardId, '=');
|
||||
$oUDSet = new DBObjectSet($oUDSearch);
|
||||
if ($oUDSet->Count() > 0)
|
||||
{
|
||||
// Assuming there is at most one couple {user, menu}!
|
||||
$oUserDashboard = $oUDSet->Fetch();
|
||||
$sDashboardDefinition = $oUserDashboard->Get('contents');
|
||||
$bCustomized = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
$sDashboardDefinition = @file_get_contents($sDashboardFile);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$sDashboardDefinition = @file_get_contents($sDashboardFile);
|
||||
}
|
||||
|
||||
if ($sDashboardDefinition !== false)
|
||||
{
|
||||
$oDashboard = new RuntimeDashboard($sDashBoardId);
|
||||
$oDashboard->FromXml($sDashboardDefinition);
|
||||
$oDashboard->SetCustomFlag($bCustomized);
|
||||
$oDashboard->SetDefinitionFile($sDashboardFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oDashboard = null;
|
||||
}
|
||||
return $oDashboard;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \iTopWebPage $oPage
|
||||
* @param bool $bEditMode
|
||||
* @param array $aExtraParams (class and id of the current object
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function Render($oPage, $bEditMode = false, $aExtraParams = array(), $bCanEdit = true)
|
||||
{
|
||||
if (!isset($aExtraParams['query_params']) && isset($aExtraParams['this->class']))
|
||||
{
|
||||
$oObj = MetaModel::GetObject($aExtraParams['this->class'], $aExtraParams['this->id']);
|
||||
$aRenderParams = array('query_params' => $oObj->ToArgsForQuery());
|
||||
}
|
||||
else
|
||||
{
|
||||
$aRenderParams = $aExtraParams;
|
||||
}
|
||||
|
||||
parent::Render($oPage, $bEditMode, $aRenderParams);
|
||||
|
||||
if (isset($aExtraParams['query_params']['this->object()']))
|
||||
{
|
||||
/** @var \DBObject $oObj */
|
||||
$oObj = $aExtraParams['query_params']['this->object()'];
|
||||
$aAjaxParams = array('this->class' => get_class($oObj), 'this->id' => $oObj->GetKey());
|
||||
}
|
||||
else
|
||||
{
|
||||
$aAjaxParams = $aExtraParams;
|
||||
}
|
||||
if (!$bEditMode && !$oPage->IsPrintableVersion())
|
||||
{
|
||||
$sId = $this->GetId();
|
||||
$sDivId = preg_replace('/[^a-zA-Z0-9_]/', '', $sId);
|
||||
if ($this->GetAutoReload())
|
||||
{
|
||||
$sFile = addslashes($this->GetDefinitionFile());
|
||||
$sExtraParams = json_encode($aAjaxParams);
|
||||
$iReloadInterval = 1000 * $this->GetAutoReloadInterval();
|
||||
$sReloadURL = $this->GetReloadURL();
|
||||
$oPage->add_script(
|
||||
<<<EOF
|
||||
if (typeof(AutoReloadDashboardId$sDivId) !== 'undefined')
|
||||
{
|
||||
clearInterval(AutoReloadDashboardId$sDivId);
|
||||
delete AutoReloadDashboardId$sDivId;
|
||||
}
|
||||
|
||||
AutoReloadDashboardId$sDivId = setInterval("ReloadDashboard$sDivId();", $iReloadInterval);
|
||||
|
||||
function ReloadDashboard$sDivId()
|
||||
{
|
||||
// Do not reload when a dialog box is active
|
||||
if (!($('.ui-dialog:visible').length > 0) && $('.dashboard_contents#$sDivId').is(':visible'))
|
||||
{
|
||||
$('.dashboard_contents#$sDivId').block();
|
||||
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php',
|
||||
{ operation: 'reload_dashboard', dashboard_id: '$sId', file: '$sFile', extra_params: $sExtraParams, reload_url: '$sReloadURL'},
|
||||
function(data){
|
||||
$('.dashboard_contents#$sDivId').html(data);
|
||||
$('.dashboard_contents#$sDivId').unblock();
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
EOF
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oPage->add_script(
|
||||
<<<EOF
|
||||
if (typeof(AutoReloadDashboardId$sDivId) !== 'undefined')
|
||||
{
|
||||
clearInterval(AutoReloadDashboardId$sDivId);
|
||||
delete AutoReloadDashboardId$sDivId;
|
||||
}
|
||||
EOF
|
||||
);
|
||||
}
|
||||
|
||||
if ($bCanEdit)
|
||||
{
|
||||
$this->RenderSelector($oPage, $aAjaxParams);
|
||||
$this->RenderEditionTools($oPage, $aAjaxParams);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \iTopWebPage $oPage
|
||||
* @param array $aAjaxParams
|
||||
*/
|
||||
protected function RenderSelector($oPage, $aAjaxParams = array())
|
||||
{
|
||||
$sId = $this->GetId();
|
||||
$sDivId = preg_replace('/[^a-zA-Z0-9_]/', '', $sId);
|
||||
$sExtraParams = json_encode($aAjaxParams);
|
||||
|
||||
$sSelectorHtml = '<div class="dashboard-selector">';
|
||||
if ($this->HasCustomDashboard())
|
||||
{
|
||||
$bStandardSelected = appUserPreferences::GetPref('display_original_dashboard_'.$sId, false);
|
||||
$sStandard = Dict::S('UI:Toggle:StandardDashboard');
|
||||
$sSelectorHtml .= '<div class="selector-label">'.$sStandard.'</div>';
|
||||
$sSelectorHtml .= '<label class="switch"><input type="checkbox" onchange="ToggleDashboardSelector'.$sDivId.'();" '.($bStandardSelected ? '' : 'checked').'><span class="slider round"></span></label></input></label>';
|
||||
$sCustom = Dict::S('UI:Toggle:CustomDashboard');
|
||||
$sSelectorHtml .= '<div class="selector-label">'.$sCustom.'</div>';
|
||||
|
||||
}
|
||||
$sSelectorHtml .= '</div>';
|
||||
$sSelectorHtml = addslashes($sSelectorHtml);
|
||||
$sFile = addslashes($this->GetDefinitionFile());
|
||||
$sReloadURL = $this->GetReloadURL();
|
||||
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
$('.dashboard-title').after('$sSelectorHtml');
|
||||
EOF
|
||||
);
|
||||
|
||||
$oPage->add_script(
|
||||
<<<EOF
|
||||
function ToggleDashboardSelector$sDivId()
|
||||
{
|
||||
$('.dashboard_contents#$sDivId').block();
|
||||
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php',
|
||||
{ operation: 'toggle_dashboard', dashboard_id: '$sId', file: '$sFile', extra_params: $sExtraParams, reload_url: '$sReloadURL' },
|
||||
function(data) {
|
||||
$('.dashboard_contents#$sDivId').html(data);
|
||||
$('.dashboard_contents#$sDivId').unblock();
|
||||
}
|
||||
);
|
||||
}
|
||||
EOF
|
||||
);
|
||||
}
|
||||
|
||||
protected function HasCustomDashboard()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Search for an eventual user defined dashboard
|
||||
$oUDSearch = new DBObjectSearch('UserDashboard');
|
||||
$oUDSearch->AddCondition('user_id', UserRights::GetUserId(), '=');
|
||||
$oUDSearch->AddCondition('menu_code', $this->GetId(), '=');
|
||||
$oUDSet = new DBObjectSet($oUDSearch);
|
||||
|
||||
return ($oUDSet->Count() > 0);
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param array $aExtraParams
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function RenderEditionTools(WebPage $oPage, $aExtraParams)
|
||||
{
|
||||
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.iframe-transport.js');
|
||||
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.fileupload.js');
|
||||
$sEditMenu = "<td><span id=\"DashboardMenu\"><ul><li><img src=\"../images/pencil-menu.png\"><ul>";
|
||||
$sEditMenu = "<div id=\"DashboardMenu\"><ul><li><img src=\"../images/pencil-menu.png\"><ul>";
|
||||
|
||||
$aActions = array();
|
||||
$oEdit = new JSPopupMenuItem('UI:Dashboard:Edit', Dict::S('UI:Dashboard:Edit'), "return EditDashboard('{$this->sId}')");
|
||||
$aActions[$oEdit->GetUID()] = $oEdit->GetMenuItem();
|
||||
$sFile = addslashes($this->sDefinitionFile);
|
||||
$sJSExtraParams = json_encode($aExtraParams);
|
||||
$bCanEdit = true;
|
||||
if ($this->HasCustomDashboard())
|
||||
{
|
||||
$bCanEdit = !appUserPreferences::GetPref('display_original_dashboard_'.$this->GetId(), false);
|
||||
}
|
||||
if ($bCanEdit)
|
||||
{
|
||||
$oEdit = new JSPopupMenuItem('UI:Dashboard:Edit', Dict::S('UI:Dashboard:Edit'), "return EditDashboard('{$this->sId}', '$sFile', $sJSExtraParams)");
|
||||
$aActions[$oEdit->GetUID()] = $oEdit->GetMenuItem();
|
||||
}
|
||||
|
||||
if ($this->bCustomized)
|
||||
{
|
||||
$oRevert = new JSPopupMenuItem('UI:Dashboard:RevertConfirm', Dict::S('UI:Dashboard:Revert'),
|
||||
"if (confirm('".addslashes(Dict::S('UI:Dashboard:RevertConfirm'))."')) return RevertDashboard('{$this->sId}'); else return false");
|
||||
"if (confirm('".addslashes(Dict::S('UI:Dashboard:RevertConfirm'))."')) return RevertDashboard('{$this->sId}', $sJSExtraParams); else return false");
|
||||
$aActions[$oRevert->GetUID()] = $oRevert->GetMenuItem();
|
||||
}
|
||||
utils::GetPopupMenuItems($oPage, iPopupMenuExtension::MENU_DASHBOARD_ACTIONS, $this, $aActions);
|
||||
$sEditMenu .= $oPage->RenderPopupMenuItems($aActions);
|
||||
|
||||
|
||||
$sEditMenu = addslashes($sEditMenu);
|
||||
//$sEditBtn = addslashes('<div style="display: inline-block; height: 55px; width:200px;vertical-align:center;line-height:60px;text-align:left;"><button onclick="EditDashboard(\''.$this->sId.'\');">Edit This Page</button></div>');
|
||||
$sReloadURL = $this->GetReloadURL();
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
$('#logOffBtn').parent().before('$sEditMenu');
|
||||
$('.dashboard-title').after('$sEditMenu');
|
||||
$('#DashboardMenu>ul').popupmenu();
|
||||
|
||||
EOF
|
||||
);
|
||||
$oPage->add_script(
|
||||
<<<EOF
|
||||
function EditDashboard(sId)
|
||||
function EditDashboard(sId, sDashboardFile, aExtraParams)
|
||||
{
|
||||
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', {operation: 'dashboard_editor', id: sId},
|
||||
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', {operation: 'dashboard_editor', id: sId, file: sDashboardFile, extra_params: aExtraParams, reload_url: '$sReloadURL'},
|
||||
function(data)
|
||||
{
|
||||
$('body').append(data);
|
||||
@@ -629,12 +924,12 @@ function EditDashboard(sId)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
function RevertDashboard(sId)
|
||||
function RevertDashboard(sId, aExtraParams)
|
||||
{
|
||||
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', {operation: 'revert_dashboard', dashboard_id: sId},
|
||||
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', {operation: 'revert_dashboard', dashboard_id: sId, extra_params: aExtraParams, reload_url: '$sReloadURL'},
|
||||
function(data)
|
||||
{
|
||||
$('body').append(data);
|
||||
location.reload();
|
||||
}
|
||||
);
|
||||
return false;
|
||||
@@ -643,9 +938,14 @@ EOF
|
||||
);
|
||||
}
|
||||
|
||||
public function RenderProperties($oPage)
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
*
|
||||
* @throws \ReflectionException
|
||||
*/
|
||||
public function RenderProperties($oPage, $aExtraParams = array())
|
||||
{
|
||||
parent::RenderProperties($oPage);
|
||||
parent::RenderProperties($oPage, $aExtraParams);
|
||||
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
@@ -676,16 +976,36 @@ EOF
|
||||
}
|
||||
|
||||
|
||||
public function RenderEditor($oPage)
|
||||
/**
|
||||
* @param \iTopWebPage $oPage
|
||||
*
|
||||
* @param array $aExtraParams
|
||||
*
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \ReflectionException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function RenderEditor($oPage, $aExtraParams = array())
|
||||
{
|
||||
if (isset($aExtraParams['this->class']))
|
||||
{
|
||||
$oObj = MetaModel::GetObject($aExtraParams['this->class'], $aExtraParams['this->id']);
|
||||
$aRenderParams = array('query_params' => $oObj->ToArgsForQuery());
|
||||
}
|
||||
else
|
||||
{
|
||||
$aRenderParams = $aExtraParams;
|
||||
}
|
||||
$sJSExtraParams = json_encode($aExtraParams);
|
||||
$oPage->add('<div id="dashboard_editor">');
|
||||
$oPage->add('<div class="ui-layout-center">');
|
||||
$this->Render($oPage, true);
|
||||
$this->Render($oPage, true, $aRenderParams);
|
||||
$oPage->add('</div>');
|
||||
$oPage->add('<div class="ui-layout-east">');
|
||||
$this->RenderProperties($oPage);
|
||||
$this->RenderProperties($oPage, $aExtraParams);
|
||||
$this->RenderDashletsSelection($oPage);
|
||||
$this->RenderDashletsProperties($oPage);
|
||||
$this->RenderDashletsProperties($oPage, $aExtraParams);
|
||||
$oPage->add('</div>');
|
||||
$oPage->add('<div id="event_bus"/>'); // For exchanging messages between the panes, same as in the designer
|
||||
$oPage->add('</div>');
|
||||
@@ -699,7 +1019,9 @@ EOF
|
||||
$sAutoReload = $this->bAutoReload ? 'true' : 'false';
|
||||
$sAutoReloadSec = (string) $this->iAutoReloadSec;
|
||||
$sTitle = addslashes($this->sTitle);
|
||||
$sFile = addslashes($this->GetDefinitionFile());
|
||||
$sUrl = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php';
|
||||
$sReloadURL = $this->GetReloadURL();
|
||||
|
||||
$sExitConfirmationMessage = addslashes(Dict::S('UI:NavigateAwayConfirmationMessage'));
|
||||
$sCancelConfirmationMessage = addslashes(Dict::S('UI:CancelConfirmationMessage'));
|
||||
@@ -729,7 +1051,7 @@ $('#dashboard_editor').dialog({
|
||||
}
|
||||
}
|
||||
window.bLeavingOnUserAction = true;
|
||||
oDashboard.save();
|
||||
oDashboard.save($(this));
|
||||
} },
|
||||
{ text: "$sCancelButtonLabel", click: function() {
|
||||
var oDashboard = $('.itop-dashboard').data('itopRuntimedashboard');
|
||||
@@ -751,8 +1073,8 @@ $('#dashboard_editor').dialog({
|
||||
$('#dashboard_editor .ui-layout-center').runtimedashboard({
|
||||
dashboard_id: '$sId', layout_class: '$sLayoutClass', title: '$sTitle',
|
||||
auto_reload: $sAutoReload, auto_reload_sec: $sAutoReloadSec,
|
||||
submit_to: '$sUrl', submit_parameters: {operation: 'save_dashboard'},
|
||||
render_to: '$sUrl', render_parameters: {operation: 'render_dashboard'},
|
||||
submit_to: '$sUrl', submit_parameters: {operation: 'save_dashboard', file: '$sFile', extra_params: $sJSExtraParams, reload_url: '$sReloadURL'},
|
||||
render_to: '$sUrl', render_parameters: {operation: 'render_dashboard', file: '$sFile', extra_params: $sJSExtraParams, reload_url: '$sReloadURL'},
|
||||
new_dashlet_parameters: {operation: 'new_dashlet'}
|
||||
});
|
||||
|
||||
@@ -835,7 +1157,8 @@ EOF
|
||||
$sParentId = $aParentMenu['parent'];
|
||||
$aParentMenu = $aParentMenus[$sParentId];
|
||||
}
|
||||
$oParentMenu = $aParentMenu['node'];
|
||||
/** @var \MenuNode $oParentMenu */
|
||||
$oParentMenu = $aParentMenu['node'];
|
||||
if ($oMenu->IsEnabled() && $oParentMenu->IsEnabled())
|
||||
{
|
||||
$sMenuLabel = $oMenu->GetTitle();
|
||||
@@ -890,6 +1213,7 @@ EOF
|
||||
{
|
||||
$oSubForm = new DesignerForm();
|
||||
$oMetaModel = new ModelReflectionRuntime();
|
||||
/** @var \Dashlet $oDashlet */
|
||||
$oDashlet = new $sDashletClass($oMetaModel, 0);
|
||||
$oDashlet->GetPropertiesFieldsFromOQL($oSubForm, $sOQL);
|
||||
|
||||
@@ -900,7 +1224,11 @@ EOF
|
||||
|
||||
return $oForm;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param $sOQL
|
||||
*/
|
||||
public static function GetDashletCreationDlgFromOQL($oPage, $sOQL)
|
||||
{
|
||||
$oPage->add('<div id="dashlet_creation_dlg">');
|
||||
@@ -947,4 +1275,30 @@ $('#dashlet_creation_dlg').dialog({
|
||||
EOF
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function GetDefinitionFile()
|
||||
{
|
||||
return $this->sDefinitionFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sDefinitionFile
|
||||
*/
|
||||
public function SetDefinitionFile($sDefinitionFile)
|
||||
{
|
||||
$this->sDefinitionFile = $sDefinitionFile;
|
||||
}
|
||||
|
||||
public function GetReloadURL()
|
||||
{
|
||||
return $this->sReloadURL;
|
||||
}
|
||||
|
||||
public function SetReloadURL($sReloadURL)
|
||||
{
|
||||
$this->sReloadURL = $sReloadURL;
|
||||
}
|
||||
}
|
||||
@@ -59,6 +59,7 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
|
||||
$bNoVisibleFound = true;
|
||||
while($idx < count($aKeys) && $bNoVisibleFound)
|
||||
{
|
||||
/** @var \Dashlet $oDashlet */
|
||||
$oDashlet = $aDashlets[$aKeys[$idx]];
|
||||
if ($oDashlet->IsVisible())
|
||||
{
|
||||
@@ -98,7 +99,13 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
|
||||
return $aCells;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param $aCells
|
||||
* @param bool $bEditMode
|
||||
* @param array $aExtraParams
|
||||
*/
|
||||
public function Render($oPage, $aCells, $bEditMode = false, $aExtraParams = array())
|
||||
{
|
||||
// Trim the list of cells to remove the invisible/empty ones at the end of the array
|
||||
@@ -122,6 +129,7 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
|
||||
$aDashlets = $aCells[$iCellIdx];
|
||||
if (count($aDashlets) > 0)
|
||||
{
|
||||
/** @var \Dashlet $oDashlet */
|
||||
foreach($aDashlets as $oDashlet)
|
||||
{
|
||||
if ($oDashlet->IsVisible())
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.5">
|
||||
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.6">
|
||||
<portals>
|
||||
<portal id="legacy_portal" _delta="define">
|
||||
<url>portal/index.php</url>
|
||||
|
||||
@@ -184,6 +184,10 @@ class DataTable
|
||||
*/
|
||||
public function GetAsHTMLTableRows(WebPage $oPage, $iPageSize, $aColumns, $sSelectMode, $bViewLink, $aExtraParams)
|
||||
{
|
||||
if ($iPageSize < 1)
|
||||
{
|
||||
$iPageSize = -1; // convention: no pagination
|
||||
}
|
||||
$aAttribs = $this->GetHTMLTableConfig($aColumns, $sSelectMode, $bViewLink);
|
||||
$aValues = $this->GetHTMLTableValues($aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams);
|
||||
|
||||
@@ -222,14 +226,21 @@ class DataTable
|
||||
}
|
||||
|
||||
$sCombo = '<select class="pagesize">';
|
||||
for($iPage = 1; $iPage < 5; $iPage++)
|
||||
if($iPageSize < 1)
|
||||
{
|
||||
$iNbItems = $iPage * $iDefaultPageSize;
|
||||
$sSelected = ($iNbItems == $iPageSize) ? 'selected="selected"' : '';
|
||||
$sCombo .= "<option $sSelected value=\"$iNbItems\">$iNbItems</option>";
|
||||
$sCombo .= "<option selected=\"selected\" value=\"-1\">".Dict::S('UI:Pagination:All')."</option>";
|
||||
}
|
||||
$sSelected = ($iPageSize < 1) ? 'selected="selected"' : '';
|
||||
$sCombo .= "<option $sSelected value=\"-1\">".Dict::S('UI:Pagination:All')."</option>";
|
||||
else
|
||||
{
|
||||
for($iPage = 1; $iPage < 5; $iPage++)
|
||||
{
|
||||
$iNbItems = $iPage * $iDefaultPageSize;
|
||||
$sSelected = ($iNbItems == $iPageSize) ? 'selected="selected"' : '';
|
||||
$sCombo .= "<option $sSelected value=\"$iNbItems\">$iNbItems</option>";
|
||||
}
|
||||
$sCombo .= "<option value=\"-1\">".Dict::S('UI:Pagination:All')."</option>";
|
||||
}
|
||||
|
||||
$sCombo .= '</select>';
|
||||
|
||||
$sPages = Dict::S('UI:Pagination:PagesLabel');
|
||||
@@ -577,8 +588,8 @@ EOF
|
||||
|
||||
public function UpdatePager(WebPage $oPage, $iDefaultPageSize, $iStart)
|
||||
{
|
||||
$iPageSize = ($iDefaultPageSize < 1) ? 1 : $iDefaultPageSize;
|
||||
$iPageIndex = 1 + floor($iStart / $iPageSize);
|
||||
$iPageSize = $iDefaultPageSize;
|
||||
$iPageIndex = 0;
|
||||
$sHtml = $this->GetPager($oPage, $iPageSize, $iDefaultPageSize, $iPageIndex);
|
||||
$oPage->add_ready_script("$('#pager{$this->iListId}').html('".json_encode($sHtml)."');");
|
||||
if ($iDefaultPageSize < 1)
|
||||
@@ -756,6 +767,10 @@ class DataTableSettings implements Serializable
|
||||
{
|
||||
foreach($this->aClassAliases as $sAlias => $sClass)
|
||||
{
|
||||
if (!isset($this->aColumns[$sAlias]))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
foreach($this->aColumns[$sAlias] as $sAttCode => $aData)
|
||||
{
|
||||
// Remove non-existent columns
|
||||
@@ -771,7 +786,7 @@ class DataTableSettings implements Serializable
|
||||
$aTempData = array();
|
||||
foreach($aList as $sAttCode => $oAttDef)
|
||||
{
|
||||
if ( (!array_key_exists($sAttCode, $this->aColumns[$sAlias])) && (!$oAttDef instanceof AttributeLinkSet))
|
||||
if ( (!array_key_exists($sAttCode, $this->aColumns[$sAlias])) && (!($oAttDef instanceof AttributeLinkedSet || $oAttDef instanceof AttributeDashboard)))
|
||||
{
|
||||
$aFieldData = $this->GetFieldData($sAlias, $sAttCode, $oAttDef, false /* bChecked */, 'none');
|
||||
if ($aFieldData) $aTempData[$aFieldData['label']] = $aFieldData;
|
||||
@@ -932,4 +947,4 @@ class DataTableSettings implements Serializable
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -220,9 +220,26 @@ class DisplayBlock
|
||||
$aExtraParams['currentId'] = $sId;
|
||||
$sExtraParams = addslashes(str_replace('"', "'", json_encode($aExtraParams))); // JSON encode, change the style of the quotes and escape them
|
||||
|
||||
if (isset($aExtraParams['query_params']))
|
||||
{
|
||||
$aQueryParams = $aExtraParams['query_params'];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isset($aExtraParams['this->id']) && isset($aExtraParams['this->class']))
|
||||
{
|
||||
$sClass = $aExtraParams['this->class'];
|
||||
$iKey = $aExtraParams['this->id'];
|
||||
$oObj = MetaModel::GetObject($sClass, $iKey);
|
||||
$aQueryParams = array('this->object()' => $oObj);
|
||||
}
|
||||
else
|
||||
{
|
||||
$aQueryParams = array();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$sFilter = $this->m_oFilter->serialize(); // Used either for asynchronous or auto_reload
|
||||
$sFilter = addslashes($this->m_oFilter->serialize(false, $aQueryParams)); // Used either for asynchronous or auto_reload
|
||||
if (!$this->m_bAsynchronous)
|
||||
{
|
||||
// render now
|
||||
@@ -314,20 +331,31 @@ class DisplayBlock
|
||||
* @throws MySQLException
|
||||
* @throws Exception
|
||||
*/
|
||||
public function GetRenderContent(WebPage $oPage, $aExtraParams = array(), $sId)
|
||||
public function GetRenderContent(WebPage $oPage, $aExtraParams, $sId)
|
||||
{
|
||||
$sHtml = '';
|
||||
// Add the extra params into the filter if they make sense for such a filter
|
||||
$bDoSearch = utils::ReadParam('dosearch', false);
|
||||
$aQueryParams = array();
|
||||
if (isset($aExtraParams['query_params']))
|
||||
{
|
||||
$aQueryParams = $aExtraParams['query_params'];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isset($aExtraParams['this->id']) && isset($aExtraParams['this->class']))
|
||||
{
|
||||
$sClass = $aExtraParams['this->class'];
|
||||
$iKey = $aExtraParams['this->id'];
|
||||
$oObj = MetaModel::GetObject($sClass, $iKey);
|
||||
$aQueryParams = array('this->object()' => $oObj);
|
||||
}
|
||||
}
|
||||
if ($this->m_oSet == null)
|
||||
{
|
||||
$aQueryParams = array();
|
||||
if (isset($aExtraParams['query_params']))
|
||||
{
|
||||
$aQueryParams = $aExtraParams['query_params'];
|
||||
}
|
||||
|
||||
// In case of search, the context filtering is done by the search itself
|
||||
if (($this->m_sStyle != 'links') && ($this->m_sStyle != 'search'))
|
||||
if (($this->m_sStyle != 'links') && ($this->m_sStyle != 'search') && ($this->m_sStyle != 'list_search'))
|
||||
{
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sClass = $this->m_oFilter->GetClass();
|
||||
@@ -457,14 +485,25 @@ class DisplayBlock
|
||||
$oSubsetSearch = $this->m_oFilter->DeepClone();
|
||||
$oCondition = new BinaryExpression($oGroupByExp, '=', new ScalarExpression($aValues[$iRow]));
|
||||
$oSubsetSearch->AddConditionExpression($oCondition);
|
||||
$sFilter = urlencode($oSubsetSearch->serialize());
|
||||
if (isset($aExtraParams['query_params']))
|
||||
{
|
||||
$aQueryParams = $aExtraParams['query_params'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$aQueryParams = array();
|
||||
}
|
||||
$sFilter = rawurlencode($oSubsetSearch->serialize(false, $aQueryParams));
|
||||
|
||||
$aData[] = array ('group' => $aLabels[$iRow],
|
||||
'value' => "<a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/UI.php?operation=search&dosearch=1&$sParams&filter=$sFilter\">$iCount</a>"); // TO DO: add the context information
|
||||
}
|
||||
$aAttribs =array(
|
||||
'group' => array('label' => $sGroupByLabel, 'description' => ''),
|
||||
'value' => array('label'=> Dict::S('UI:GroupBy:'.$sAggregationFunction), 'description' => Dict::Format('UI:GroupBy:'.$sAggregationFunction.'+', $sAggregationAttr))
|
||||
'value' => array(
|
||||
'label' => Dict::S('UI:GroupBy:'.$sAggregationFunction),
|
||||
'description' => Dict::Format('UI:GroupBy:'.$sAggregationFunction.'+', $sAggregationAttr),
|
||||
),
|
||||
);
|
||||
$sFormat = isset($aExtraParams['format']) ? $aExtraParams['format'] : 'UI:Pagination:HeaderNoSelection';
|
||||
$sHtml .= $oPage->GetP(Dict::Format($sFormat, $iTotalCount));
|
||||
@@ -580,6 +619,7 @@ class DisplayBlock
|
||||
}
|
||||
break;
|
||||
|
||||
case 'list_search':
|
||||
case 'list':
|
||||
$aClasses = $this->m_oSet->GetSelectedClasses();
|
||||
$aAuthorizedClasses = array();
|
||||
@@ -662,7 +702,7 @@ class DisplayBlock
|
||||
'breadcrumb_label' => MetaModel::GetName($this->m_oSet->GetClass()),
|
||||
'breadcrumb_max_count' => utils::GetConfig()->Get('breadcrumb.max_count'),
|
||||
'breadcrumb_instance_id' => MetaModel::GetConfig()->GetItopInstanceid(),
|
||||
'breadcrumb_icon' => utils::GetAbsoluteUrlAppRoot().'images/breadcrumb-search.png'
|
||||
'breadcrumb_icon' => utils::GetAbsoluteUrlAppRoot().'images/breadcrumb-search.png',
|
||||
));
|
||||
|
||||
$oPage->add_ready_script("$('body').trigger('update_history.itop', [$seventAttachedData])");
|
||||
@@ -715,7 +755,7 @@ class DisplayBlock
|
||||
$sClass = $this->m_oFilter->GetClass();
|
||||
$oAppContext = new ApplicationContext();
|
||||
$bContextFilter = isset($aExtraParams['context_filter']) ? isset($aExtraParams['context_filter']) != 0 : false;
|
||||
if ($bContextFilter)
|
||||
if ($bContextFilter && is_null($this->m_oSet))
|
||||
{
|
||||
foreach($oAppContext->GetNames() as $sFilterCode)
|
||||
{
|
||||
@@ -734,7 +774,7 @@ class DisplayBlock
|
||||
$this->m_oSet->SetShowObsoleteData($this->m_bShowObsoleteData);
|
||||
}
|
||||
$iCount = $this->m_oSet->Count();
|
||||
$sHyperlink = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.urlencode($this->m_oFilter->serialize());
|
||||
$sHyperlink = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.rawurlencode($this->m_oFilter->serialize());
|
||||
$sHtml .= '<p><a class="actions" href="'.$sHyperlink.'">';
|
||||
// Note: border set to 0 due to various browser interpretations (IE9 adding a 2px border)
|
||||
$sHtml .= MetaModel::GetClassIcon($sClass, true, 'float;left;margin-right:10px;border:0;');
|
||||
@@ -823,7 +863,7 @@ class DisplayBlock
|
||||
}
|
||||
$sHyperlink = utils::GetAbsoluteUrlAppRoot()
|
||||
.'pages/UI.php?operation=search&'.$oAppContext->GetForLink()
|
||||
.'&filter='.urlencode($oSingleGroupByValueFilter->serialize());
|
||||
.'&filter='.rawurlencode($oSingleGroupByValueFilter->serialize());
|
||||
$aCounts[$sStateValue] = "<a href=\"$sHyperlink\">{$aCounts[$sStateValue]}</a>";
|
||||
}
|
||||
}
|
||||
@@ -832,7 +872,7 @@ class DisplayBlock
|
||||
$sHtml .= '<tr><td>'.implode('</td><td>', $aCounts).'</td></tr></table></div>';
|
||||
// Title & summary
|
||||
$iCount = $this->m_oSet->Count();
|
||||
$sHyperlink = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.urlencode($this->m_oFilter->serialize());
|
||||
$sHyperlink = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.rawurlencode($this->m_oFilter->serialize());
|
||||
$sHtml .= '<h1>'.Dict::S(str_replace('_', ':', $sTitle)).'</h1>';
|
||||
$sHtml .= '<a class="summary" href="'.$sHyperlink.'">'.Dict::Format(str_replace('_', ':', $sLabel), $iCount).'</a>';
|
||||
$sHtml .= '<div style="clear:both;"></div>';
|
||||
@@ -843,7 +883,7 @@ class DisplayBlock
|
||||
|
||||
$sCsvFile = strtolower($this->m_oFilter->GetClass()).'.csv';
|
||||
$sDownloadLink = utils::GetAbsoluteUrlAppRoot().'webservices/export.php?expression='.urlencode($this->m_oFilter->ToOQL(true)).'&format=csv&filename='.urlencode($sCsvFile);
|
||||
$sLinkToToggle = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.urlencode($this->m_oFilter->serialize()).'&format=csv';
|
||||
$sLinkToToggle = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.rawurlencode($this->m_oFilter->serialize()).'&format=csv';
|
||||
// Pass the parameters via POST, since expression may be very long
|
||||
$aParamsToPost = array(
|
||||
'expression' => $this->m_oFilter->ToOQL(true),
|
||||
@@ -913,10 +953,10 @@ class DisplayBlock
|
||||
|
||||
$sChartType = isset($aExtraParams['chart_type']) ? $aExtraParams['chart_type'] : 'pie';
|
||||
$sTitle = isset($aExtraParams['chart_title']) ? '<h1 style="text-align:center">'.htmlentities(Dict::S($aExtraParams['chart_title']), ENT_QUOTES, 'UTF-8').'</h1>' : '';
|
||||
$sHtml = "$sTitle<div style=\"height:200px;width:100%\" id=\"my_chart_$sId{$iChartCounter}\"><div style=\"height:200px;line-height:200px;vertical-align:center;text-align:center;width:100%\"><img src=\"../images/indicator.gif\"></div></div>\n";
|
||||
$sHtml = "$sTitle<div style=\"height:200px;width:100%\" class=\"dashboard_chart\" id=\"my_chart_$sId{$iChartCounter}\"><div style=\"height:200px;line-height:200px;vertical-align:center;text-align:center;width:100%\"><img src=\"../images/indicator.gif\"></div></div>\n";
|
||||
$sGroupBy = isset($aExtraParams['group_by']) ? $aExtraParams['group_by'] : '';
|
||||
$sGroupByExpr = isset($aExtraParams['group_by_expr']) ? '¶ms[group_by_expr]='.$aExtraParams['group_by_expr'] : '';
|
||||
$sFilter = $this->m_oFilter->serialize();
|
||||
$sFilter = $this->m_oFilter->serialize(false, $aQueryParams);
|
||||
$oContext = new ApplicationContext();
|
||||
$sContextParam = $oContext->GetForLink();
|
||||
$sAggregationFunction = isset($aExtraParams['aggregation_function']) ? $aExtraParams['aggregation_function'] : '';
|
||||
@@ -927,11 +967,11 @@ class DisplayBlock
|
||||
|
||||
if (isset($aExtraParams['group_by_label']))
|
||||
{
|
||||
$sUrl = json_encode(utils::GetAbsoluteUrlAppRoot()."pages/ajax.render.php?operation=chart¶ms[group_by]=$sGroupBy{$sGroupByExpr}¶ms[group_by_label]={$aExtraParams['group_by_label']}¶ms[chart_type]=$sChartType¶ms[currentId]=$sId{$iChartCounter}¶ms[order_direction]=$sOrderDirection¶ms[order_by]=$sOrderBy¶ms[limit]=$sLimit¶ms[aggregation_function]=$sAggregationFunction¶ms[aggregation_attribute]=$sAggregationAttr&id=$sId{$iChartCounter}&filter=".urlencode($sFilter).'&'.$sContextParam);
|
||||
$sUrl = json_encode(utils::GetAbsoluteUrlAppRoot()."pages/ajax.render.php?operation=chart¶ms[group_by]=$sGroupBy{$sGroupByExpr}¶ms[group_by_label]={$aExtraParams['group_by_label']}¶ms[chart_type]=$sChartType¶ms[currentId]=$sId{$iChartCounter}¶ms[order_direction]=$sOrderDirection¶ms[order_by]=$sOrderBy¶ms[limit]=$sLimit¶ms[aggregation_function]=$sAggregationFunction¶ms[aggregation_attribute]=$sAggregationAttr&id=$sId{$iChartCounter}&filter=".rawurlencode($sFilter).'&'.$sContextParam);
|
||||
}
|
||||
else
|
||||
{
|
||||
$sUrl = json_encode(utils::GetAbsoluteUrlAppRoot()."pages/ajax.render.php?operation=chart¶ms[group_by]=$sGroupBy{$sGroupByExpr}¶ms[chart_type]=$sChartType¶ms[currentId]=$sId{$iChartCounter}¶ms[order_direction]=$sOrderDirection¶ms[order_by]=$sOrderBy¶ms[limit]=$sLimit¶ms[aggregation_function]=$sAggregationFunction¶ms[aggregation_attribute]=$sAggregationAttr&id=$sId{$iChartCounter}&filter=".urlencode($sFilter).'&'.$sContextParam);
|
||||
$sUrl = json_encode(utils::GetAbsoluteUrlAppRoot()."pages/ajax.render.php?operation=chart¶ms[group_by]=$sGroupBy{$sGroupByExpr}¶ms[chart_type]=$sChartType¶ms[currentId]=$sId{$iChartCounter}¶ms[order_direction]=$sOrderDirection¶ms[order_by]=$sOrderBy¶ms[limit]=$sLimit¶ms[aggregation_function]=$sAggregationFunction¶ms[aggregation_attribute]=$sAggregationAttr&id=$sId{$iChartCounter}&filter=".rawurlencode($sFilter).'&'.$sContextParam);
|
||||
}
|
||||
|
||||
$oPage->add_ready_script(
|
||||
@@ -971,7 +1011,7 @@ EOF
|
||||
$oSubsetSearch = $this->m_oFilter->DeepClone();
|
||||
$oCondition = new BinaryExpression($oGroupByExp, '=', new ScalarExpression($sValue));
|
||||
$oSubsetSearch->AddConditionExpression($oCondition);
|
||||
$aURLs[] = utils::GetAbsoluteUrlAppRoot()."pages/UI.php?operation=search&format=html&filter=".urlencode($oSubsetSearch->serialize()).'&'.$sContextParam;
|
||||
$aURLs[] = utils::GetAbsoluteUrlAppRoot()."pages/UI.php?operation=search&format=html&filter=".rawurlencode($oSubsetSearch->serialize()).'&'.$sContextParam;
|
||||
}
|
||||
$sJSURLs = json_encode($aURLs);
|
||||
}
|
||||
@@ -989,6 +1029,7 @@ EOF
|
||||
$sJson = json_encode($aValues);
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
|
||||
var chart = c3.generate({
|
||||
bindto: d3.select('#my_chart_$sId'),
|
||||
data: {
|
||||
@@ -1036,6 +1077,12 @@ var chart = c3.generate({
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (typeof(charts) === "undefined")
|
||||
{
|
||||
charts = [];
|
||||
}
|
||||
charts.push(chart);
|
||||
EOF
|
||||
);
|
||||
break;
|
||||
@@ -1074,6 +1121,12 @@ var chart = c3.generate({
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (typeof(charts) === "undefined")
|
||||
{
|
||||
charts = [];
|
||||
}
|
||||
charts.push(chart);
|
||||
EOF
|
||||
);
|
||||
break;
|
||||
@@ -1122,16 +1175,26 @@ EOF
|
||||
}
|
||||
if (($bAutoReload) && ($this->m_sStyle != 'search')) // Search form do NOT auto-reload
|
||||
{
|
||||
$sFilter = $this->m_oFilter->serialize(); // Used either for asynchronous or auto_reload
|
||||
$sExtraParams = addslashes(str_replace('"', "'", json_encode($aExtraParams))); // JSON encode, change the style of the quotes and escape them
|
||||
// Used either for asynchronous or auto_reload
|
||||
// does a json_encode twice to get a string usable as function parameter
|
||||
$sFilterBefore = $this->m_oFilter->serialize();
|
||||
$sFilter = json_encode($sFilterBefore);
|
||||
$sExtraParams = json_encode(json_encode($aExtraParams));
|
||||
|
||||
$oPage->add_script('if (typeof window.oAutoReloadBlock == "undefined") {
|
||||
window.oAutoReloadBlock = {};
|
||||
}
|
||||
if (typeof window.oAutoReloadBlock[\''.$sId.'\'] != "undefined") {
|
||||
clearInterval(window.oAutoReloadBlock[\''.$sId.'\']);
|
||||
}
|
||||
window.oAutoReloadBlock[\''.$sId.'\'] = setInterval("ReloadBlock(\''.$sId.'\', \''.$this->m_sStyle.'\', \''.$sFilter.'\', \"'.$sExtraParams.'\")", '.$iReloadInterval.');');
|
||||
$oPage->add_script(
|
||||
<<<JS
|
||||
if (typeof window.oAutoReloadBlock == "undefined") {
|
||||
window.oAutoReloadBlock = {};
|
||||
}
|
||||
if (typeof window.oAutoReloadBlock['$sId'] != "undefined") {
|
||||
clearInterval(window.oAutoReloadBlock['$sId']);
|
||||
}
|
||||
|
||||
window.oAutoReloadBlock['$sId'] = setInterval(function() {
|
||||
ReloadBlock('$sId', '{$this->m_sStyle}', $sFilter, $sExtraParams);
|
||||
}, '$iReloadInterval');
|
||||
JS
|
||||
);
|
||||
}
|
||||
|
||||
return $sHtml;
|
||||
@@ -1391,7 +1454,7 @@ class HistoryBlock extends DisplayBlock
|
||||
default:
|
||||
if ($bTruncated)
|
||||
{
|
||||
$sFilter = $this->m_oFilter->serialize();
|
||||
$sFilter = htmlentities($this->m_oFilter->serialize(), ENT_QUOTES, 'UTF-8');
|
||||
$sHtml .= '<div id="history_container"><p>';
|
||||
$sHtml .= Dict::Format('UI:TruncatedResults', $this->iLimitCount, $oSet->Count());
|
||||
$sHtml .= ' ';
|
||||
@@ -1669,6 +1732,7 @@ class MenuBlock extends DisplayBlock
|
||||
*/
|
||||
}
|
||||
$this->AddMenuSeparator($aActions);
|
||||
/** @var \iApplicationUIExtension $oExtensionInstance */
|
||||
foreach (MetaModel::EnumPlugins('iApplicationUIExtension') as $oExtensionInstance)
|
||||
{
|
||||
$oSet->Rewind();
|
||||
@@ -1764,6 +1828,7 @@ class MenuBlock extends DisplayBlock
|
||||
}
|
||||
|
||||
$this->AddMenuSeparator($aActions);
|
||||
/** @var \iApplicationUIExtension $oExtensionInstance */
|
||||
foreach (MetaModel::EnumPlugins('iApplicationUIExtension') as $oExtensionInstance)
|
||||
{
|
||||
$oSet->Rewind();
|
||||
|
||||
@@ -378,9 +378,9 @@ $('#$sDialogId').dialog({
|
||||
}
|
||||
}
|
||||
} },
|
||||
{ text: "$sCancelButtonLabel", click: function() { KillAllMenus(); $(this).dialog( "close" ); $(this).remove(); } },
|
||||
{ text: "$sCancelButtonLabel", click: function() { $(this).dialog( "close" ); $(this).remove(); } },
|
||||
],
|
||||
close: function() { KillAllMenus(); $(this).remove(); }
|
||||
close: function() { $(this).remove(); }
|
||||
});
|
||||
var oForm = $('#$sDialogId form');
|
||||
var sFormId = oForm.attr('id');
|
||||
@@ -682,6 +682,7 @@ class DesignerFormField
|
||||
protected $sLabel;
|
||||
protected $sCode;
|
||||
protected $defaultValue;
|
||||
/** @var \DesignerForm $oForm */
|
||||
protected $oForm;
|
||||
protected $bMandatory;
|
||||
protected $bReadOnly;
|
||||
@@ -707,8 +708,11 @@ class DesignerFormField
|
||||
{
|
||||
return $this->sCode;
|
||||
}
|
||||
|
||||
public function SetForm($oForm)
|
||||
|
||||
/**
|
||||
* @param \DesignerForm $oForm
|
||||
*/
|
||||
public function SetForm(\DesignerForm $oForm)
|
||||
{
|
||||
$this->oForm = $oForm;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -50,6 +50,9 @@ class LoginWebPage extends NiceWebPage
|
||||
self::$sHandlerClass = $sClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \LoginWebPage
|
||||
*/
|
||||
public static function NewLoginWebPage()
|
||||
{
|
||||
return new self::$sHandlerClass;
|
||||
@@ -153,7 +156,7 @@ class LoginWebPage extends NiceWebPage
|
||||
$this->add("<table>\n");
|
||||
$sForgotPwd = $this->EnableResetPassword() ? $this->ForgotPwdLink() : '';
|
||||
$this->add("<tr><td style=\"text-align:right\"><label for=\"user\">".Dict::S('UI:Login:UserNamePrompt').":</label></td><td style=\"text-align:left\"><input id=\"user\" type=\"text\" name=\"auth_user\" value=\"".htmlentities($sAuthUser, ENT_QUOTES, 'UTF-8')."\" /></td></tr>\n");
|
||||
$this->add("<tr><td style=\"text-align:right\"><label for=\"pwd\">".Dict::S('UI:Login:PasswordPrompt').":</label></td><td style=\"text-align:left\"><input id=\"pwd\" type=\"password\" name=\"auth_pwd\" value=\"".htmlentities($sAuthPwd, ENT_QUOTES, 'UTF-8')."\" /></td></tr>\n");
|
||||
$this->add("<tr><td style=\"text-align:right\"><label for=\"pwd\">".Dict::S('UI:Login:PasswordPrompt').":</label></td><td style=\"text-align:left\"><input id=\"pwd\" type=\"password\" autocomplete=\"off\" name=\"auth_pwd\" value=\"".htmlentities($sAuthPwd, ENT_QUOTES, 'UTF-8')."\" /></td></tr>\n");
|
||||
$this->add("<tr><td colspan=\"2\" class=\"center v-spacer\"><span class=\"btn_border\"><input type=\"submit\" value=\"".Dict::S('UI:Button:Login')."\" /></span></td></tr>\n");
|
||||
if (strlen($sForgotPwd) > 0)
|
||||
{
|
||||
@@ -381,7 +384,7 @@ EOF
|
||||
else
|
||||
{
|
||||
// Trash the token and change the password
|
||||
$oUser->Set('reset_pwd_token', '');
|
||||
$oUser->Set('reset_pwd_token', new ormPassword());
|
||||
$oUser->AllowWrite(true);
|
||||
$oUser->SetPassword($sNewPwd); // Does record the change into the DB
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
@@ -84,14 +84,11 @@ class ApplicationMenu
|
||||
{
|
||||
// Build menus from module handlers
|
||||
//
|
||||
foreach(get_declared_classes() as $sPHPClass)
|
||||
{
|
||||
if (is_subclass_of($sPHPClass, 'ModuleHandlerAPI'))
|
||||
{
|
||||
$aCallSpec = array($sPHPClass, 'OnMenuCreation');
|
||||
call_user_func($aCallSpec);
|
||||
}
|
||||
}
|
||||
/** @var \ModuleHandlerApiInterface $oPHPClass */
|
||||
foreach(MetaModel::EnumPlugins('ModuleHandlerApiInterface') as $oPHPClass)
|
||||
{
|
||||
$oPHPClass::OnMenuCreation();
|
||||
}
|
||||
|
||||
// Build menus from the menus themselves (e.g. the ShortcutContainerMenuNode will do that)
|
||||
//
|
||||
@@ -125,9 +122,11 @@ class ApplicationMenu
|
||||
}
|
||||
|
||||
/**
|
||||
* Check wether a menu Id is enabled or not
|
||||
* Check whether a menu Id is enabled or not
|
||||
*
|
||||
* @param $sMenuId
|
||||
* @throws DictExceptionMissingString
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
static public function CheckMenuIdEnabled($sMenuId)
|
||||
{
|
||||
@@ -167,7 +166,9 @@ class ApplicationMenu
|
||||
}
|
||||
else
|
||||
{
|
||||
$sParentId = self::$aMenusIndex[$iParentIndex]['node']->GetMenuId();
|
||||
/** @var \MenuNode $oNode */
|
||||
$oNode = self::$aMenusIndex[$iParentIndex]['node'];
|
||||
$sParentId = $oNode->GetMenuId();
|
||||
self::$aMenusIndex[$iParentIndex]['children'][] = array ('rank' => $fRank, 'index' => $index);
|
||||
}
|
||||
|
||||
@@ -181,7 +182,9 @@ class ApplicationMenu
|
||||
else
|
||||
{
|
||||
// the menu already exists, let's combine the conditions that make it visible
|
||||
self::$aMenusIndex[$index]['node']->AddCondition($oMenuNode);
|
||||
/** @var \MenuNode $oNode */
|
||||
$oNode = self::$aMenusIndex[$index]['node'];
|
||||
$oNode->AddCondition($oMenuNode);
|
||||
}
|
||||
|
||||
return $index;
|
||||
@@ -198,7 +201,7 @@ class ApplicationMenu
|
||||
|
||||
/**
|
||||
* Entry point to display the whole menu into the web page, used by iTopWebPage
|
||||
* @param $oPage
|
||||
* @param \iTopWebPage $oPage
|
||||
* @param $aExtraParams
|
||||
* @throws DictExceptionMissingString
|
||||
*/
|
||||
@@ -208,6 +211,7 @@ class ApplicationMenu
|
||||
// Sort the root menu based on the rank
|
||||
usort(self::$aRootMenus, array('ApplicationMenu', 'CompareOnRank'));
|
||||
$iAccordion = 0;
|
||||
$iActiveAccordion = $iAccordion;
|
||||
$iActiveMenu = self::GetMenuIndexById(self::GetActiveNodeId());
|
||||
foreach(self::$aRootMenus as $aMenu)
|
||||
{
|
||||
@@ -221,16 +225,18 @@ class ApplicationMenu
|
||||
$oPage->AddToMenu('</ul>');
|
||||
if ($bActive)
|
||||
{
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
// Accordion Menu
|
||||
$("#accordion").css({display:'block'}).accordion({ header: "h3", navigation: true, heightStyle: "content", collapsible: true, active: $iAccordion, icons: false, animate:true }); // collapsible will be enabled once the item will be selected
|
||||
EOF
|
||||
);
|
||||
$iActiveAccordion = $iAccordion;
|
||||
}
|
||||
$oPage->AddToMenu('</div>');
|
||||
$iAccordion++;
|
||||
}
|
||||
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
// Accordion Menu
|
||||
$("#accordion").css({display:'block'}).accordion({ header: "h3", heightStyle: "content", collapsible: true, active: $iActiveAccordion, icons: false, animate: true }); // collapsible will be enabled once the item will be selected
|
||||
EOF
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -264,7 +270,7 @@ EOF
|
||||
|
||||
/**
|
||||
* Handles the display of the sub-menus (called recursively if necessary)
|
||||
* @param WebPage $oPage
|
||||
* @param \iTopWebPage $oPage
|
||||
* @param array $aMenus
|
||||
* @param array $aExtraParams
|
||||
* @param int $iActiveMenu
|
||||
@@ -287,7 +293,8 @@ EOF
|
||||
$sHyperlink = $oMenu->GetHyperlink($aExtraParams);
|
||||
if ($sHyperlink != '')
|
||||
{
|
||||
$oPage->AddToMenu('<li id="'.utils::GetSafeId('AccordionMenu_'.$oMenu->GetMenuID()).'" '.$sCSSClass.'><a href="'.$oMenu->GetHyperlink($aExtraParams).'">'.$oMenu->GetTitle().'</a></li>');
|
||||
$sTitle = utils::HtmlEntities($oMenu->GetTitle());
|
||||
$oPage->AddToMenu('<li id="'.utils::GetSafeId('AccordionMenu_'.$oMenu->GetMenuID()).'" '.$sCSSClass.'><a href="'.$oMenu->GetHyperlink($aExtraParams).'">'.$sTitle.'</a></li>');
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -356,6 +363,7 @@ EOF
|
||||
static public function GetMenuIndexById($sTitle)
|
||||
{
|
||||
$index = -1;
|
||||
/** @var MenuNode[] $aMenu */
|
||||
foreach(self::$aMenusIndex as $aMenu)
|
||||
{
|
||||
if ($aMenu['node']->GetMenuId() == $sTitle)
|
||||
@@ -837,7 +845,7 @@ class OQLMenuNode extends MenuNode
|
||||
|
||||
/**
|
||||
* Set some extra parameters to be passed to the display block to fine tune its appearence
|
||||
* @param Hash $aParams paramCode => value. See DisplayBlock::GetDisplay for the meaning of the parameters
|
||||
* @param array $aParams paramCode => value. See DisplayBlock::GetDisplay for the meaning of the parameters
|
||||
*/
|
||||
public function SetParameters($aParams)
|
||||
{
|
||||
@@ -898,7 +906,7 @@ class OQLMenuNode extends MenuNode
|
||||
$oBlock->Display($oPage, 0);
|
||||
}
|
||||
|
||||
$oPage->add("<p class=\"page-header\">$sIcon ".Dict::S($sTitle)."</p>");
|
||||
$oPage->add("<p class=\"page-header\">$sIcon ".utils::HtmlEntities(Dict::S($sTitle))."</p>");
|
||||
|
||||
$aParams = array_merge(array('table_id' => $sUsageId), $aExtraParams);
|
||||
$oBlock = new DisplayBlock($oSearch, 'list', false /* Asynchronous */, $aParams);
|
||||
@@ -950,7 +958,7 @@ class SearchMenuNode extends MenuNode
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WebPage $oPage
|
||||
* @param \iTopWebPage $oPage
|
||||
* @param array $aExtraParams
|
||||
* @return mixed|void
|
||||
* @throws DictExceptionMissingString
|
||||
@@ -1054,7 +1062,9 @@ class NewObjectMenuNode extends MenuNode
|
||||
|
||||
/**
|
||||
* @param string[] $aExtraParams
|
||||
*
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function GetHyperlink($aExtraParams)
|
||||
{
|
||||
@@ -1143,37 +1153,11 @@ class DashboardMenuNode extends MenuNode
|
||||
*/
|
||||
public function GetDashboard()
|
||||
{
|
||||
$sDashboardDefinition = @file_get_contents($this->sDashboardFile);
|
||||
if ($sDashboardDefinition !== false)
|
||||
{
|
||||
$bCustomized = false;
|
||||
|
||||
// Search for an eventual user defined dashboard, overloading the existing one
|
||||
$oUDSearch = new DBObjectSearch('UserDashboard');
|
||||
$oUDSearch->AddCondition('user_id', UserRights::GetUserId(), '=');
|
||||
$oUDSearch->AddCondition('menu_code', $this->sMenuId, '=');
|
||||
$oUDSet = new DBObjectSet($oUDSearch);
|
||||
if ($oUDSet->Count() > 0)
|
||||
{
|
||||
// Assuming there is at most one couple {user, menu}!
|
||||
$oUserDashboard = $oUDSet->Fetch();
|
||||
$sDashboardDefinition = $oUserDashboard->Get('contents');
|
||||
$bCustomized = true;
|
||||
|
||||
}
|
||||
$oDashboard = new RuntimeDashboard($this->sMenuId);
|
||||
$oDashboard->FromXml($sDashboardDefinition);
|
||||
$oDashboard->SetCustomFlag($bCustomized);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oDashboard = null;
|
||||
}
|
||||
return $oDashboard;
|
||||
return RuntimeDashboard::GetDashboard($this->sDashboardFile, $this->sMenuId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WebPage $oPage
|
||||
* @param \iTopWebPage $oPage
|
||||
* @param string[] $aExtraParams
|
||||
* @throws CoreException
|
||||
* @throws Exception
|
||||
@@ -1186,38 +1170,9 @@ class DashboardMenuNode extends MenuNode
|
||||
{
|
||||
$sDivId = preg_replace('/[^a-zA-Z0-9_]/', '', $this->sMenuId);
|
||||
$oPage->add('<div class="dashboard_contents" id="'.$sDivId.'">');
|
||||
$oDashboard->SetReloadURL($this->GetHyperlink($aExtraParams));
|
||||
$oDashboard->Render($oPage, false, $aExtraParams);
|
||||
$oPage->add('</div>');
|
||||
$oDashboard->RenderEditionTools($oPage);
|
||||
|
||||
if ($oDashboard->GetAutoReload())
|
||||
{
|
||||
$sId = $this->sMenuId;
|
||||
$sExtraParams = json_encode($aExtraParams);
|
||||
$iReloadInterval = 1000 * $oDashboard->GetAutoReloadInterval();
|
||||
$oPage->add_script(
|
||||
<<<EOF
|
||||
setInterval("ReloadDashboard('$sDivId');", $iReloadInterval);
|
||||
|
||||
function ReloadDashboard(sDivId)
|
||||
{
|
||||
var oExtraParams = $sExtraParams;
|
||||
// Do not reload when a dialog box is active
|
||||
if (!($('.ui-dialog:visible').length > 0))
|
||||
{
|
||||
$('.dashboard_contents#'+sDivId).block();
|
||||
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php',
|
||||
{ operation: 'reload_dashboard', dashboard_id: '$sId', extra_params: oExtraParams},
|
||||
function(data){
|
||||
$('.dashboard_contents#'+sDivId).html(data);
|
||||
$('.dashboard_contents#'+sDivId).unblock();
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
EOF
|
||||
);
|
||||
}
|
||||
|
||||
$bEdit = utils::ReadParam('edit', false);
|
||||
if ($bEdit)
|
||||
|
||||
159
application/newsroomprovider.class.inc.php
Normal file
159
application/newsroomprovider.class.inc.php
Normal file
@@ -0,0 +1,159 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2015 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
/**
|
||||
* A provider for messages to be displayed in the iTop Newsroom
|
||||
*/
|
||||
interface iNewsroomProvider
|
||||
{
|
||||
/**
|
||||
* Inject the current configuration in the provider
|
||||
* @param Config $oConfig
|
||||
* @return void
|
||||
*/
|
||||
public function SetConfig(Config $oConfig);
|
||||
|
||||
/**
|
||||
* Tells if this provider is enabled for the given user
|
||||
* @param User $oUser The user for who to check if the provider is applicable.
|
||||
* return bool
|
||||
*/
|
||||
public function IsApplicable(User $oUser = null);
|
||||
|
||||
/**
|
||||
* The human readable (localized) label for this provider
|
||||
* @return string
|
||||
*/
|
||||
public function GetLabel();
|
||||
|
||||
/**
|
||||
* The URL to query (from the browser, using jsonp) to fetch all unread messages
|
||||
* @return string
|
||||
*/
|
||||
public function GetFetchURL();
|
||||
|
||||
/**
|
||||
* The URL to navigate to in order to display all messages
|
||||
* @return string
|
||||
*/
|
||||
public function GetViewAllURL();
|
||||
|
||||
/**
|
||||
* The URL to query(from the browser, using jsonp) to mark all unread messages as read
|
||||
* @return string
|
||||
*/
|
||||
public function GetMarkAllAsReadURL();
|
||||
|
||||
/**
|
||||
* Return the URL to configure the preferences for this provider or null is there is nothing to configure
|
||||
* @return string|null
|
||||
*/
|
||||
public function GetPreferencesUrl();
|
||||
|
||||
/**
|
||||
* Return an array key => value to be replaced in URL of the messages
|
||||
* Example: '%itop_root%' => utils::GetAbsoluteUrlAppRoot();
|
||||
* @return string[]
|
||||
*/
|
||||
public function GetPlaceholders();
|
||||
|
||||
/**
|
||||
* The duration between to refreshes of the cache (in seconds)
|
||||
* @return int
|
||||
*/
|
||||
public function GetTTL();
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic implementation of a Newsroom provider, to be overloaded by your own provider implementation
|
||||
*
|
||||
*/
|
||||
abstract class NewsroomProviderBase implements iNewsroomProvider
|
||||
{
|
||||
/**
|
||||
* The current configuration parameters
|
||||
* @var Config
|
||||
*/
|
||||
protected $oConfig;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->oConfig = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see iNewsroomProvider::SetConfig()
|
||||
*/
|
||||
public function SetConfig(Config $oConfig)
|
||||
{
|
||||
$this->oConfig = $oConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see iNewsroomProvider::GetPreferencesUrl()
|
||||
*/
|
||||
public function GetPreferencesUrl()
|
||||
{
|
||||
return null; // No preferences
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see iNewsroomProvider::GetLabel()
|
||||
*/
|
||||
public abstract function GetLabel();
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see iNewsroomProvider::GetFetchURL()
|
||||
*/
|
||||
public abstract function GetFetchURL();
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see iNewsroomProvider::GetMarkAllURL()
|
||||
*/
|
||||
public abstract function GetMarkAllAsReadURL();
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see iNewsroomProvider::GetViewAllURL()
|
||||
*/
|
||||
public abstract function GetViewAllURL();
|
||||
|
||||
public function IsApplicable(User $oUser = null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see iNewsroomProvider::GetPlaceholders()
|
||||
*/
|
||||
public function GetPlaceholders()
|
||||
{
|
||||
return array(); // By default, empty set of placeholders
|
||||
}
|
||||
|
||||
public function GetTTL()
|
||||
{
|
||||
return 10*60; // Refresh every 10 minutes
|
||||
}
|
||||
}
|
||||
@@ -37,8 +37,15 @@ class NiceWebPage extends WebPage
|
||||
{
|
||||
parent::__construct($s_title, $bPrintable);
|
||||
$this->m_aReadyScripts = array();
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery-1.12.4.min.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery-migrate-1.4.1.min.js'); // Needed since many other plugins still rely on oldies like $.browser
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery-3.3.1.min.js');
|
||||
if(utils::IsDevelopmentEnvironment()) // Needed since many other plugins still rely on oldies like $.browser
|
||||
{
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery-migrate-3.0.1.dev.js');
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery-migrate-3.0.1.prod.min.js');
|
||||
}
|
||||
$this->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot().'css/ui-lightness/jquery-ui-1.11.4.custom.css');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery-ui-1.11.4.custom.min.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/utils.js');
|
||||
@@ -47,6 +54,7 @@ class NiceWebPage extends WebPage
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.tablesorter.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.tablesorter.pager.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.tablehover.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/table-selectable-lines.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/field_sorter.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/datatable.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.positionBy.js');
|
||||
@@ -61,6 +69,7 @@ class NiceWebPage extends WebPage
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_external_field.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_numeric.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_enum.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_tag_set.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_external_key.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_hierarchical_key.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_date_abstract.js');
|
||||
|
||||
@@ -35,7 +35,7 @@ class iTopPDF extends TCPDF
|
||||
|
||||
// Display the page number (right aligned)
|
||||
// Warning: the 'R'ight alignment does not work when using placeholders like $this->getAliasNumPage() or $this->getAliasNbPages()
|
||||
$this->MultiCell($iPageNumberWidth, 15, 'Page '.$this->page, 0, 'R', false, 0 /* $ln */, '', '', true, 0, false, true, 15, 'M' /* $valign */);
|
||||
$this->MultiCell($iPageNumberWidth, 15, Dict::Format('Core:BulkExport:PDF:PageNumber' ,$this->page), 0, 'R', false, 0 /* $ln */, '', '', true, 0, false, true, 15, 'M' /* $valign */);
|
||||
|
||||
// Branding logo
|
||||
$sBrandingIcon = APPROOT.'images/itop-logo.png';
|
||||
|
||||
@@ -807,7 +807,7 @@ EOF
|
||||
*/
|
||||
public function DoUpdateObjectFromPostedForm(DBObject $oObj, $aAttList = null)
|
||||
{
|
||||
$sTransactionId = utils::ReadPostedParam('transaction_id', '');
|
||||
$sTransactionId = utils::ReadPostedParam('transaction_id', '', 'transaction_id');
|
||||
if (!utils::IsTransactionValid($sTransactionId))
|
||||
{
|
||||
throw new TransactionException();
|
||||
|
||||
@@ -47,13 +47,12 @@ abstract class Query extends cmdbAbstractObject
|
||||
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 AttributeText("description", array("allowed_values"=>null, "sql"=>"description", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeText("fields", array("allowed_values"=>null, "sql"=>"fields", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('name', 'description', 'fields')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('details', array('name', 'description')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('description')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', array('name', 'description', 'fields')); // Criteria of the std search form
|
||||
MetaModel::Init_SetZListItems('standard_search', array('name', 'description')); // Criteria of the std search form
|
||||
MetaModel::Init_SetZListItems('default_search', array('name', 'description')); // Criteria of the default search form
|
||||
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
|
||||
}
|
||||
@@ -78,6 +77,9 @@ class QueryOQL extends Query
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeOQL("oql", array("allowed_values"=>null, "sql"=>"oql", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("fields", array("allowed_values"=>null, "sql"=>"fields", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
// Rolled back to AttributeText until AttributeQueryAttCodeSet can manage fields order correctly
|
||||
//MetaModel::Init_AddAttribute(new AttributeQueryAttCodeSet("fields", array("allowed_values"=>null,"max_items" => 1000, "query_field" => "oql", "sql"=>"fields", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array('oql'))));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('name', 'description', 'oql', 'fields')); // Attributes to be displayed for the complete details
|
||||
@@ -136,6 +138,41 @@ class QueryOQL extends Query
|
||||
}
|
||||
return $aFieldsMap;
|
||||
}
|
||||
|
||||
// Rolled back until 'fields' can be properly managed by AttributeQueryAttCodeSet
|
||||
//
|
||||
// public function ComputeValues()
|
||||
// {
|
||||
// parent::ComputeValues();
|
||||
//
|
||||
// // Remove unwanted attribute codes
|
||||
// $aChanges = $this->ListChanges();
|
||||
// if (isset($aChanges['fields']))
|
||||
// {
|
||||
// $oAttDef = MetaModel::GetAttributeDef(get_class($this), 'fields');
|
||||
// $aArgs = array('this' => $this);
|
||||
// $aAllowedValues = $oAttDef->GetAllowedValues($aArgs);
|
||||
//
|
||||
// /** @var \ormSet $oValue */
|
||||
// $oValue = $this->Get('fields');
|
||||
// $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('fields', $oValue);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
@@ -24,6 +24,26 @@
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
// This storage is freed on error (case of allowed memory exhausted)
|
||||
$sReservedMemory = str_repeat('*', 1024 * 1024);
|
||||
register_shutdown_function(function()
|
||||
{
|
||||
global $sReservedMemory;
|
||||
$sReservedMemory = null;
|
||||
if (!is_null($err = error_get_last()) && ($err['type'] == E_ERROR))
|
||||
{
|
||||
if (strpos($err['message'], 'Allowed memory size of') !== false)
|
||||
{
|
||||
$sLimit = ini_get('memory_limit');
|
||||
echo "<p>iTop: Allowed memory size of $sLimit exhausted, contact your administrator to increase memory_limit in php.ini</p>\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
echo "<p>iTop: An error occurred, check server error log for more information.</p>\n";
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
require_once(APPROOT.'/core/cmdbobject.class.inc.php');
|
||||
require_once(APPROOT.'/application/utils.inc.php');
|
||||
require_once(APPROOT.'/core/contexttag.class.inc.php');
|
||||
|
||||
@@ -399,6 +399,7 @@ class ObjectDetailsTemplate extends DisplayTemplate
|
||||
$aPlugInProperties = $aMatches[1];
|
||||
foreach($aPlugInProperties as $sPlugInClass)
|
||||
{
|
||||
/** @var \iApplicationUIExtension $oInstance */
|
||||
$oInstance = MetaModel::GetPlugins('iApplicationUIExtension', $sPlugInClass);
|
||||
if ($oInstance != null) // Safety check...
|
||||
{
|
||||
|
||||
@@ -119,7 +119,7 @@ class privUITransactionSession
|
||||
// Strictly speaking, the two lines below should be grouped together
|
||||
// by a critical section
|
||||
// sem_acquire($rSemIdentified);
|
||||
$id = str_replace(array('.', ' '), '', microtime()); //1 + count($_SESSION['transactions']);
|
||||
$id = static::GetUserPrefix() . str_replace(array('.', ' '), '', microtime()); //1 + count($_SESSION['transactions']);
|
||||
$_SESSION['transactions'][$id] = true;
|
||||
// sem_release($rSemIdentified);
|
||||
|
||||
@@ -174,6 +174,17 @@ class privUITransactionSession
|
||||
// sem_release($rSemIdentified);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string to prefix transaction ID with info from the current user.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected static function GetUserPrefix()
|
||||
{
|
||||
$sPrefix = 'u'.UserRights::GetUserId();
|
||||
return $sPrefix.'-';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -206,7 +217,7 @@ class privUITransactionFile
|
||||
throw new Exception('The directory "'.APPROOT.'data/transactions" must be writable to the application.');
|
||||
}
|
||||
self::CleanupOldTransactions();
|
||||
$id = basename(tempnam(APPROOT.'data/transactions', self::GetUserPrefix()));
|
||||
$id = basename(tempnam(APPROOT.'data/transactions', static::GetUserPrefix()));
|
||||
self::Info('GetNewTransactionId: Created transaction: '.$id);
|
||||
|
||||
return (string)$id;
|
||||
@@ -310,6 +321,11 @@ class privUITransactionFile
|
||||
return $aResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a prefix based on the user login instead of its ID for a better usage in tempnam()
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected static function GetUserPrefix()
|
||||
{
|
||||
$sPrefix = substr(UserRights::GetUser(), 0, 10);
|
||||
|
||||
@@ -208,6 +208,14 @@ class UIExtKeyWidget
|
||||
{
|
||||
// When there is only once choice, select it by default
|
||||
$sSelected = 'selected';
|
||||
if($value != $key)
|
||||
{
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
$('#$this->iId').attr('data-validate','dependencies');
|
||||
EOF
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -332,7 +340,8 @@ EOF
|
||||
if ( ($oCurrObject != null) && ($this->sAttCode != ''))
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef(get_class($oCurrObject), $this->sAttCode);
|
||||
$aArgs = array('this' => $oCurrObject);
|
||||
/** @var \DBObject $oCurrObject */
|
||||
$aArgs = $oCurrObject->ToArgsForQuery();
|
||||
$aParams = array('query_params' => $aArgs);
|
||||
$oSet = $oAttDef->GetAllowedValuesAsObjectSet($aArgs);
|
||||
$oFilter = $oSet->GetFilter();
|
||||
@@ -402,7 +411,7 @@ EOF
|
||||
// Current extkey value, so we can display event if it is not available anymore (eg. archived).
|
||||
$iCurrentExtKeyId = (is_null($oObj)) ? 0 : $oObj->Get($this->sAttCode);
|
||||
|
||||
$oBlock = new DisplayBlock($oFilter, 'list', false, array('query_params' => array('this' => $oObj, 'current_extkey_id' => $iCurrentExtKeyId)));
|
||||
$oBlock = new DisplayBlock($oFilter, 'list_search', false, array('query_params' => array('this' => $oObj, 'current_extkey_id' => $iCurrentExtKeyId)));
|
||||
$oBlock->Display($oP, $this->iId.'_results', array('this' => $oObj, 'cssCount'=> '#count_'.$this->iId, 'menu' => false, 'selection_mode' => true, 'selection_type' => 'single', 'table_id' => 'select_'.$this->sAttCode)); // Don't display the 'Actions' menu on the results
|
||||
}
|
||||
|
||||
|
||||
@@ -101,7 +101,7 @@ class UIHTMLEditorWidget
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
$('#$iId').bind('update', function(evt){
|
||||
BlockField('cke_$iId', $('#$iId').attr('disabled'));
|
||||
BlockField('cke_$iId', $('#$iId').prop('disabled'));
|
||||
//Delayed execution - ckeditor must be properly initialized before setting readonly
|
||||
var retryCount = 0;
|
||||
var oMe = $('#$iId');
|
||||
|
||||
@@ -286,11 +286,13 @@ class UILinksWidgetDirect
|
||||
* @param DBObject $oCurrentObj
|
||||
* @param $aAlreadyLinked
|
||||
*
|
||||
* @param array $aPrefillFormParam
|
||||
*
|
||||
* @throws \CoreException
|
||||
* @throws \Exception
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public function GetObjectsSelectionDlg($oPage, $oCurrentObj, $aAlreadyLinked)
|
||||
public function GetObjectsSelectionDlg($oPage, $oCurrentObj, $aAlreadyLinked, $aPrefillFormParam = array())
|
||||
{
|
||||
$sHtml = "<div class=\"wizContainer\" style=\"vertical-align:top;\">\n";
|
||||
|
||||
@@ -333,6 +335,8 @@ class UILinksWidgetDirect
|
||||
|
||||
$aArgs = array_merge($oCurrentObj->ToArgs('this'), $oFilter->GetInternalParams());
|
||||
$oFilter->SetInternalParams($aArgs);
|
||||
$aPrefillFormParam['filter'] = $oFilter;
|
||||
$oCurrentObj->PrefillForm('search', $aPrefillFormParam);
|
||||
}
|
||||
$oBlock = new DisplayBlock($oFilter, 'search', false);
|
||||
$sHtml .= $oBlock->GetDisplay($oPage, "SearchFormToAdd_{$this->sInputid}",
|
||||
@@ -359,13 +363,17 @@ class UILinksWidgetDirect
|
||||
|
||||
/**
|
||||
* Search for objects to be linked to the current object (i.e "remote" objects)
|
||||
*
|
||||
* @param WebPage $oP The page used for the output (usually an AjaxWebPage)
|
||||
* @param string $sRemoteClass Name of the "remote" class to perform the search on, must be a derived class of $this->sLinkedClass
|
||||
* @param array $aAlreadyLinked Array of indentifiers of objects which are already linke to the current object (or about to be linked)
|
||||
* @param DBObject $oCurrentObj The object currently being edited... if known...
|
||||
* @throws Exception
|
||||
* @param array $aPrefillFormParam
|
||||
*
|
||||
* @throws \CoreException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public function SearchObjectsToAdd(WebPage $oP, $sRemoteClass = '', $aAlreadyLinked = array(), $oCurrentObj = null)
|
||||
public function SearchObjectsToAdd(WebPage $oP, $sRemoteClass = '', $aAlreadyLinked = array(), $oCurrentObj = null, $aPrefillFormParam = array())
|
||||
{
|
||||
if ($sRemoteClass == '')
|
||||
{
|
||||
@@ -395,16 +403,19 @@ class UILinksWidgetDirect
|
||||
$oFilter->AddCondition('id', $oCurrentObj->GetKey(), '!=');
|
||||
}
|
||||
}
|
||||
if (count($aAlreadyLinked) > 0)
|
||||
{
|
||||
$oFilter->AddCondition('id', $aAlreadyLinked, 'NOTIN');
|
||||
}
|
||||
if ($oCurrentObj != null)
|
||||
{
|
||||
$this->SetSearchDefaultFromContext($oCurrentObj, $oFilter);
|
||||
|
||||
$aArgs = array_merge($oCurrentObj->ToArgs('this'), $oFilter->GetInternalParams());
|
||||
$oFilter->SetInternalParams($aArgs);
|
||||
|
||||
$aPrefillFormParam['filter'] = $oFilter;
|
||||
$oCurrentObj->PrefillForm('search', $aPrefillFormParam);
|
||||
}
|
||||
if (count($aAlreadyLinked) > 0)
|
||||
{
|
||||
$oFilter->AddCondition('id', $aAlreadyLinked, 'NOTIN');
|
||||
}
|
||||
$oBlock = new DisplayBlock($oFilter, 'list', false);
|
||||
$oBlock->Display($oP, "ResultsToAdd_{$this->sInputid}", array('menu' => false, 'cssCount'=> '#count_'.$this->sInputid , 'selection_mode' => true, 'table_id' => 'add_'.$this->sInputid)); // Don't display the 'Actions' menu on the results
|
||||
|
||||
@@ -73,17 +73,17 @@ class UIPasswordWidget
|
||||
$oPage->add_ready_script("$('#{$this->iId}_confirm').bind('keyup change', function(evt, sFormId) { return ValidatePasswordField('$this->iId', sFormId) } );"); // Bind to a custom event: validate
|
||||
$oPage->add_ready_script("$('#{$this->iId}').bind('update', function(evt, sFormId)
|
||||
{
|
||||
if ($(this).attr('disabled'))
|
||||
if ($(this).prop('disabled'))
|
||||
{
|
||||
$('#{$this->iId}_confirm').attr('disabled', 'disabled');
|
||||
$('#{$this->iId}_changed').attr('disabled', 'disabled');
|
||||
$('#{$this->iId}_reset').attr('disabled', 'disabled');
|
||||
$('#{$this->iId}_confirm').prop('disabled', true);
|
||||
$('#{$this->iId}_changed').prop('disabled', true);
|
||||
$('#{$this->iId}_reset').prop('disabled', true);
|
||||
}
|
||||
else
|
||||
{
|
||||
$('#{$this->iId}_confirm').removeAttr('disabled');
|
||||
$('#{$this->iId}_changed').removeAttr('disabled');
|
||||
$('#{$this->iId}_reset').removeAttr('disabled');
|
||||
$('#{$this->iId}_confirm').prop('disabled', false);
|
||||
$('#{$this->iId}_changed').prop('disabled', false);
|
||||
$('#{$this->iId}_reset').prop('disabled', false);
|
||||
}
|
||||
}
|
||||
);"); // Bind to a custom event: update to handle enabling/disabling
|
||||
|
||||
@@ -287,74 +287,84 @@ class utils
|
||||
*/
|
||||
protected static function Sanitize_Internal($value, $sSanitizationFilter)
|
||||
{
|
||||
switch($sSanitizationFilter)
|
||||
switch ($sSanitizationFilter)
|
||||
{
|
||||
case 'integer':
|
||||
$retValue = filter_var($value, FILTER_SANITIZE_NUMBER_INT);
|
||||
break;
|
||||
|
||||
$retValue = filter_var($value, FILTER_SANITIZE_NUMBER_INT);
|
||||
break;
|
||||
|
||||
case 'class':
|
||||
$retValue = $value;
|
||||
if (!MetaModel::IsValidClass($value))
|
||||
{
|
||||
$retValue = false;
|
||||
}
|
||||
break;
|
||||
$retValue = $value;
|
||||
if (!MetaModel::IsValidClass($value))
|
||||
{
|
||||
$retValue = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'string':
|
||||
$retValue = filter_var($value, FILTER_SANITIZE_SPECIAL_CHARS);
|
||||
break;
|
||||
|
||||
$retValue = filter_var($value, FILTER_SANITIZE_SPECIAL_CHARS);
|
||||
break;
|
||||
|
||||
case 'context_param':
|
||||
case 'parameter':
|
||||
case 'field_name':
|
||||
if (is_array($value))
|
||||
{
|
||||
$retValue = array();
|
||||
foreach($value as $key => $val)
|
||||
if (is_array($value))
|
||||
{
|
||||
$retValue[$key] = self::Sanitize_Internal($val, $sSanitizationFilter); // recursively check arrays
|
||||
if ($retValue[$key] === false)
|
||||
$retValue = array();
|
||||
foreach ($value as $key => $val)
|
||||
{
|
||||
$retValue = false;
|
||||
break;
|
||||
$retValue[$key] = self::Sanitize_Internal($val, $sSanitizationFilter); // recursively check arrays
|
||||
if ($retValue[$key] === false)
|
||||
{
|
||||
$retValue = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch($sSanitizationFilter)
|
||||
else
|
||||
{
|
||||
case 'transaction_id':
|
||||
// same as parameter type but keep the dot character
|
||||
// see N°1835 : when using file transaction_id on Windows you get *.tmp tokens
|
||||
// it must be included at the regexp beginning otherwise you'll get an invalid character error
|
||||
$retValue = filter_var($value, FILTER_VALIDATE_REGEXP,
|
||||
array("options" => array("regexp" => '/^[\. A-Za-z0-9_=-]*$/')));
|
||||
break;
|
||||
switch ($sSanitizationFilter)
|
||||
{
|
||||
case 'transaction_id':
|
||||
// same as parameter type but keep the dot character
|
||||
// see N°1835 : when using file transaction_id on Windows you get *.tmp tokens
|
||||
// it must be included at the regexp beginning otherwise you'll get an invalid character error
|
||||
$retValue = filter_var($value, FILTER_VALIDATE_REGEXP,
|
||||
array("options" => array("regexp" => '/^[\. A-Za-z0-9_=-]*$/')));
|
||||
break;
|
||||
|
||||
case 'parameter':
|
||||
$retValue = filter_var($value, FILTER_VALIDATE_REGEXP, array("options"=>array("regexp"=>'/^([ A-Za-z0-9_=-]|%3D|%2B|%2F)*$/'))); // the '=', '%3D, '%2B', '%2F' characters are used in serialized filters (starting 2.5, only the url encoded versions are presents, but the "=" is kept for BC)
|
||||
break;
|
||||
|
||||
case 'field_name':
|
||||
$retValue = filter_var($value, FILTER_VALIDATE_REGEXP, array("options"=>array("regexp"=>'/^[A-Za-z0-9_]+(->[A-Za-z0-9_]+)*$/'))); // att_code or att_code->name or AttCode->Name or AttCode->Key2->Name
|
||||
break;
|
||||
|
||||
case 'context_param':
|
||||
$retValue = filter_var($value, FILTER_VALIDATE_REGEXP, array("options"=>array("regexp"=>'/^[ A-Za-z0-9_=%:+-]*$/')));
|
||||
break;
|
||||
|
||||
case 'parameter':
|
||||
$retValue = filter_var($value, FILTER_VALIDATE_REGEXP,
|
||||
array("options" => array("regexp" => '/^[ A-Za-z0-9_=-]*$/'))); // the '=', '%3D, '%2B', '%2F'
|
||||
// characters are used in serialized filters (starting 2.5, only the url encoded versions are presents, but the "=" is kept for BC)
|
||||
break;
|
||||
|
||||
case 'field_name':
|
||||
$retValue = filter_var($value, FILTER_VALIDATE_REGEXP,
|
||||
array("options" => array("regexp" => '/^[A-Za-z0-9_]+(->[A-Za-z0-9_]+)*$/'))); // att_code or att_code->name or AttCode->Name or AttCode->Key2->Name
|
||||
break;
|
||||
|
||||
case 'context_param':
|
||||
$retValue = filter_var($value, FILTER_VALIDATE_REGEXP,
|
||||
array("options" => array("regexp" => '/^[ A-Za-z0-9_=%:+-]*$/')));
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
// For XML / HTML node identifiers
|
||||
case 'element_identifier':
|
||||
$retValue = preg_replace('/[^a-zA-Z0-9_]/', '', $value);
|
||||
break;
|
||||
|
||||
default:
|
||||
case 'raw_data':
|
||||
$retValue = $value;
|
||||
$retValue = $value;
|
||||
// Do nothing
|
||||
}
|
||||
return $retValue;
|
||||
|
||||
return $retValue;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -536,7 +546,7 @@ class utils
|
||||
/**
|
||||
* Returns a unique tmp id for the current upload based on the transaction system (db).
|
||||
*
|
||||
* Build as session_id() . '_' . static::GetNewTransactionId()
|
||||
* Build as static::GetNewTransactionId()
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
@@ -546,7 +556,7 @@ class utils
|
||||
{
|
||||
$sTransactionId = static::GetNewTransactionId();
|
||||
}
|
||||
return session_id() . '_' . $sTransactionId;
|
||||
return $sTransactionId;
|
||||
}
|
||||
|
||||
public static function ReadFromFile($sFileName)
|
||||
@@ -581,6 +591,18 @@ class utils
|
||||
}
|
||||
return $iReturn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the memory limit is at least what is required
|
||||
*
|
||||
* @param int $memoryLimit set limit in bytes
|
||||
* @param int $requiredLimit required limit in bytes
|
||||
* @return bool
|
||||
*/
|
||||
public static function IsMemoryLimitOk($memoryLimit, $requiredLimit)
|
||||
{
|
||||
return ($memoryLimit >= $requiredLimit) || ($memoryLimit == -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a value into a more friendly format (KB, MB, GB, TB) instead a juste a Bytes amount.
|
||||
@@ -725,7 +747,11 @@ class utils
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string The absolute URL to the application, including host and path
|
||||
* Returns the absolute URL to the application root path
|
||||
*
|
||||
* @return string The absolute URL to the application root, without the first slash
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
static public function GetAbsoluteUrlAppRoot()
|
||||
{
|
||||
@@ -754,7 +780,15 @@ class utils
|
||||
return $sUrl;
|
||||
}
|
||||
|
||||
static public function GetDefaultUrlAppRoot()
|
||||
/**
|
||||
* Builds an root url from the server's variables.
|
||||
* For most usages, when an root url is needed, use utils::GetAbsoluteUrlAppRoot() instead as uses this only as a fallback when the app_root_url conf parameter is not defined.
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
static public function GetDefaultUrlAppRoot()
|
||||
{
|
||||
// Build an absolute URL to this page on this server/port
|
||||
$sServerName = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : '';
|
||||
@@ -823,7 +857,7 @@ class utils
|
||||
|
||||
/**
|
||||
* Helper to handle the variety of HTTP servers
|
||||
* See #286 (fixed in [896]), and #634 (this fix)
|
||||
* See N°286 (fixed in [896]), and N°634 (this fix)
|
||||
*
|
||||
* Though the official specs says 'a non empty string', some servers like IIS do set it to 'off' !
|
||||
* nginx set it to an empty string
|
||||
@@ -1076,12 +1110,7 @@ class utils
|
||||
// $param is a DBObject
|
||||
$oObj = $param;
|
||||
$sOQL = "SELECT ".get_class($oObj)." WHERE id=".$oObj->GetKey();
|
||||
$oFilter = DBObjectSearch::FromOQL($sOQL);
|
||||
$sFilter = $oFilter->serialize();
|
||||
$sUrl = ApplicationContext::MakeObjectUrl(get_class($oObj), $oObj->GetKey());
|
||||
$sUIPage = cmdbAbstractObject::ComputeStandardUIPage(get_class($oObj));
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sContext = $oAppContext->GetForLink();
|
||||
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/tabularfieldsselector.js');
|
||||
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.dragtable.js');
|
||||
$oPage->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot().'css/dragtable.css');
|
||||
@@ -1101,21 +1130,29 @@ class utils
|
||||
break;
|
||||
|
||||
case iPopupMenuExtension::MENU_DASHBOARD_ACTIONS:
|
||||
// $param is a Dashboard
|
||||
$oAppContext = new ApplicationContext();
|
||||
$aParams = $oAppContext->GetAsHash();
|
||||
$sMenuId = ApplicationMenu::GetActiveNodeId();
|
||||
$sDlgTitle = addslashes(Dict::S('UI:ImportDashboardTitle'));
|
||||
$sDlgText = addslashes(Dict::S('UI:ImportDashboardText'));
|
||||
$sCloseBtn = addslashes(Dict::S('UI:Button:Cancel'));
|
||||
// $param is a Dashboard
|
||||
/** @var \RuntimeDashboard $oDashboard */
|
||||
$oDashboard = $param;
|
||||
$sDashboardId = $oDashboard->GetId();
|
||||
$sDashboardFile = $oDashboard->GetDefinitionFile();
|
||||
$sDlgTitle = addslashes(Dict::S('UI:ImportDashboardTitle'));
|
||||
$sDlgText = addslashes(Dict::S('UI:ImportDashboardText'));
|
||||
$sCloseBtn = addslashes(Dict::S('UI:Button:Cancel'));
|
||||
$sDashboardFileJS = addslashes($sDashboardFile);
|
||||
$sDashboardFileURL = urlencode($sDashboardFile);
|
||||
$sUploadDashboardTransactId = utils::GetNewTransactionId();
|
||||
$aResult = array(
|
||||
new SeparatorPopupMenuItem(),
|
||||
new URLPopupMenuItem('UI:ExportDashboard', Dict::S('UI:ExportDashBoard'), utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?operation=export_dashboard&id='.$sMenuId),
|
||||
new JSPopupMenuItem('UI:ImportDashboard', Dict::S('UI:ImportDashBoard'),
|
||||
"UploadDashboard({dashboard_id: '$sMenuId', title: '$sDlgTitle', text: '$sDlgText', close_btn: '$sCloseBtn', transaction: '$sUploadDashboardTransactId' })"),
|
||||
);
|
||||
break;
|
||||
$aResult = array(
|
||||
new SeparatorPopupMenuItem(),
|
||||
new URLPopupMenuItem('UI:ExportDashboard', Dict::S('UI:ExportDashBoard'), utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?operation=export_dashboard&id='.$sDashboardId.'&file='.$sDashboardFileURL),
|
||||
new JSPopupMenuItem('UI:ImportDashboard', Dict::S('UI:ImportDashBoard'), "UploadDashboard({dashboard_id: '$sDashboardId', file: '$sDashboardFileJS', title: '$sDlgTitle', text: '$sDlgText', close_btn: '$sCloseBtn', transaction: '$sUploadDashboardTransactId' })"),
|
||||
);
|
||||
if ($oDashboard->GetReloadURL())
|
||||
{
|
||||
$aResult[] = new SeparatorPopupMenuItem();
|
||||
$aResult[] = new URLPopupMenuItem('UI:Menu:PrintableVersion', Dict::S('UI:Menu:PrintableVersion'), $oDashboard->GetReloadURL().'&printable=1', '_blank');
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
// Unknown type of menu, do nothing
|
||||
@@ -1441,6 +1478,17 @@ class utils
|
||||
return htmlentities($sValue, ENT_QUOTES, 'UTF-8');
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to encapsulation iTop's html_entity_decode
|
||||
* @param string $sValue
|
||||
* @return string
|
||||
* @since 2.7.0
|
||||
*/
|
||||
public static function HtmlEntityDecode($sValue)
|
||||
{
|
||||
return html_entity_decode($sValue, ENT_QUOTES, 'UTF-8');
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a string containing some (valid) HTML markup to plain text
|
||||
* @param string $sHtml
|
||||
@@ -1482,7 +1530,7 @@ class utils
|
||||
static public function GetCSSFromSASS($sSassRelPath, $aImportPaths = null)
|
||||
{
|
||||
// Avoiding compilation if file is already a css file.
|
||||
if (preg_match('/\.css$/', $sSassRelPath))
|
||||
if (preg_match('/\.css(\?.*)?$/', $sSassRelPath))
|
||||
{
|
||||
return $sSassRelPath;
|
||||
}
|
||||
@@ -1990,4 +2038,14 @@ class utils
|
||||
$aHugeClasses = MetaModel::GetConfig()->Get('high_cardinality_classes');
|
||||
return in_array($sClass, $aHugeClasses);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if iTop is in a development environment (VCS vs build number)
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function IsDevelopmentEnvironment()
|
||||
{
|
||||
return ITOP_REVISION === 'svn';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -311,7 +311,10 @@ class WebPage implements Page
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a script (as an include, i.e. link) to the header of the page
|
||||
* Add a script (as an include, i.e. link) to the header of the page.<br>
|
||||
* Handles duplicates : calling twice with the same script will add the script only once
|
||||
*
|
||||
* @param string $s_linked_script
|
||||
*/
|
||||
public function add_linked_script($s_linked_script)
|
||||
{
|
||||
|
||||
@@ -154,7 +154,7 @@ class WizardHelper
|
||||
}
|
||||
else
|
||||
{
|
||||
// May happen for security reasons (portal, see ticket #1074)
|
||||
// May happen for security reasons (portal, see ticket N°1074)
|
||||
$oObj->Set($sAttCode, $value);
|
||||
}
|
||||
}
|
||||
@@ -174,6 +174,30 @@ class WizardHelper
|
||||
}
|
||||
$oObj->Set($sAttCode, $value);
|
||||
}
|
||||
else if ($oAttDef instanceof AttributeTagSet) // AttributeDate is derived from AttributeDateTime
|
||||
{
|
||||
if (is_null($value))
|
||||
{
|
||||
// happens if field is hidden (see N°1827)
|
||||
$value = array();
|
||||
}
|
||||
else
|
||||
{
|
||||
$value = json_decode($value, true);
|
||||
}
|
||||
$oTagSet = new ormTagSet(get_class($oObj), $sAttCode, $oAttDef->GetMaxItems());
|
||||
$oTagSet->SetValues($value['orig_value']);
|
||||
$oTagSet->ApplyDelta($value);
|
||||
$oObj->Set($sAttCode, $oTagSet);
|
||||
}
|
||||
else if ($oAttDef instanceof AttributeSet) // AttributeDate is derived from AttributeDateTime
|
||||
{
|
||||
$value = json_decode($value, true);
|
||||
$oTagSet = new ormSet(get_class($oObj), $sAttCode, $oAttDef->GetMaxItems());
|
||||
$oTagSet->SetValues($value['orig_value']);
|
||||
$oTagSet->ApplyDelta($value);
|
||||
$oObj->Set($sAttCode, $oTagSet);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oObj->Set($sAttCode, $value);
|
||||
@@ -205,11 +229,10 @@ class WizardHelper
|
||||
// this as to be handled as an array of objects
|
||||
// thus encoded in json like: [ { name:'link1', 'id': 123}, { name:'link2', 'id': 124}...]
|
||||
// NOT YET IMPLEMENTED !!
|
||||
$sLinkedClass = $oAttDef->GetLinkedClass();
|
||||
$oSet = $value;
|
||||
$aData = array();
|
||||
$aFields = $this->GetLinkedWizardStructure($oAttDef);
|
||||
while($oSet->fetch())
|
||||
while($oLinkedObj = $oSet->fetch())
|
||||
{
|
||||
foreach($aFields as $sLinkedAttCode)
|
||||
{
|
||||
|
||||
@@ -40,7 +40,7 @@ Class XLSXWriter
|
||||
|
||||
protected function tempFilename()
|
||||
{
|
||||
$filename = tempnam("/tmp", "xlsx_writer_");
|
||||
$filename = tempnam(SetupUtils::GettmpDir(), 'xlsx_writer_');
|
||||
$this->temp_files[] = $filename;
|
||||
return $filename;
|
||||
}
|
||||
|
||||
@@ -1,16 +1,22 @@
|
||||
{
|
||||
"require": {
|
||||
"php": ">=5.6.0",
|
||||
"ext-mysql": "*",
|
||||
"ext-ldap": "*",
|
||||
"ext-mcrypt": "*",
|
||||
"ext-cli": "*",
|
||||
"ext-soap": "*",
|
||||
"ext-json": "*",
|
||||
"ext-zip": "*",
|
||||
"ext-mysqli": "*",
|
||||
"ext-dom": "*",
|
||||
"ext-iconv": "*",
|
||||
"ext-gd": "*"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-libsodium": "Required to use the AttributeEncryptedString.",
|
||||
"ext-openssl": "Can be used as a polyfill if libsodium is not installed",
|
||||
"ext-mcrypt": "Can be used as a polyfill if either libsodium and openssl are not installed (libsodium and openssl are more secure)",
|
||||
"ext-ldap": "Required to use LDAP as an identity provider",
|
||||
"ext-posix": "Not required by the core, but some extensions uses it.",
|
||||
"ext-imap": "Required by the extension \"Mail to ticket automation\""
|
||||
},
|
||||
"config": {
|
||||
"platform": {
|
||||
"php": "5.6.0"
|
||||
|
||||
3054
composer.lock
generated
Normal file
3054
composer.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
105
contributing.md
Normal file
105
contributing.md
Normal file
@@ -0,0 +1,105 @@
|
||||
# Contributing to iTop
|
||||
|
||||
You want to contribute to iTop? Many thanks to you! 🎉 👍
|
||||
|
||||
Here are some guidelines that will help us integrate your work!
|
||||
|
||||
|
||||
## Contributions
|
||||
|
||||
### Subjects
|
||||
You are welcome to create pull requests on any of those subjects:
|
||||
|
||||
* 🐛 `:bug:` bug fix
|
||||
* 🔒 `:lock:` security
|
||||
* 🌐 `:globe_with_meridians:` translation / i18n / l10n
|
||||
|
||||
If you want to implement a **new feature**, please [create a corresponding ticket](https://sourceforge.net/p/itop/tickets/new/) for review.
|
||||
If you ever want to begin implementation, do so in a fork, and add a link to the corresponding commits in the ticket.
|
||||
|
||||
### License
|
||||
iTop is distributed under the AGPL-3.0 license (see the [license.txt] file),
|
||||
your code must comply with this license.
|
||||
|
||||
If you want to use another license, you may [create an extension][wiki new ext].
|
||||
|
||||
[license.txt]: https://github.com/Combodo/iTop/blob/develop/license.txt
|
||||
[wiki new ext]: https://www.itophub.io/wiki/page?id=latest%3Acustomization%3Astart#by_writing_your_own_extension
|
||||
|
||||
|
||||
## Branch model
|
||||
|
||||
TL;DR:
|
||||
> **create a fork from iTop main repository,
|
||||
> create a branch based on either release branch if present, or develop otherwise**
|
||||
|
||||
We are using the [GitFlow](https://nvie.com/posts/a-successful-git-branching-model/) branch model. That means we have in our repo those
|
||||
main branches:
|
||||
|
||||
- develop: ongoing development version
|
||||
- release/\*: if present, that means we are working on a beta version
|
||||
- master: previous stable version
|
||||
|
||||
For example, if no beta version is currently ongoing we could have:
|
||||
|
||||
- develop containing future 2.8.0 version
|
||||
- master containing 2.7.x maintenance version
|
||||
|
||||
In this example, when 2.8.0-beta is shipped that will become:
|
||||
|
||||
- develop: future 2.9.0 version
|
||||
- release/2.8: 2.8.0-beta
|
||||
- master: 2.7.x maintenance version
|
||||
|
||||
And when 2.8.0 final will be out:
|
||||
|
||||
- develop: future 2.9.0 version
|
||||
- master: 2.8.x maintenance version
|
||||
- support/2.7 : 2.7.x maintenance version
|
||||
|
||||
|
||||
## Coding
|
||||
|
||||
### PHP styleguide
|
||||
|
||||
Please follow [our guidelines](https://www.itophub.io/wiki/page?id=latest%3Acustomization%3Acoding_standards).
|
||||
|
||||
### 🌐 Translations
|
||||
|
||||
A [dedicated page](https://www.itophub.io/wiki/page?id=latest%3Acustomization%3Atranslation) is available in the official wiki.
|
||||
|
||||
### Tests
|
||||
|
||||
Please create tests that covers as much as possible the code you're submitting.
|
||||
|
||||
Our tests are located in the `test/` directory, containing a PHPUnit config file : `phpunit.xml.dist`.
|
||||
|
||||
### Git Commit Messages
|
||||
|
||||
* Describe the functional change instead of the technical modifications
|
||||
* Use the present tense ("Add feature" not "Added feature")
|
||||
* Use the imperative mood ("Move cursor to..." not "Moves cursor to...")
|
||||
* Limit the first line to 72 characters or less
|
||||
* Please start the commit message with an applicable emoji code (following the [Gitmoji guide](https://gitmoji.carloscuesta.me/)). For example :
|
||||
* 🌐 `:globe_with_meridians:` for translations
|
||||
* 🎨 `:art:` when improving the format/structure of the code
|
||||
* ⚡️ `:zap:` when improving performance
|
||||
* 🐛 `:bug:` when fixing a bug
|
||||
* 🔥 `:fire:` when removing code or files
|
||||
* 💚 `:green_heart:` when fixing the CI build
|
||||
* ✅ `:white_check_mark:` when adding tests
|
||||
* 🔒 `:lock:` when dealing with security
|
||||
* ⬆️ `:arrow_up:` when upgrading dependencies
|
||||
* ⬇️ `:arrow_down:` when downgrading dependencies
|
||||
* ♻️ `:recycle:` code refactoring
|
||||
* 💄 `:lipstick:` Updating the UI and style files.
|
||||
|
||||
## Pull request
|
||||
|
||||
When your code is working, please:
|
||||
|
||||
* stash as much as possible your commits,
|
||||
* rebase your branch on our repo last commit,
|
||||
* create a pull request.
|
||||
|
||||
Detailed procedure to work on fork and create PR is available [in GitHub help pages](https://help.github.com/articles/creating-a-pull-request-from-a-fork/).
|
||||
@@ -223,7 +223,14 @@ class ActionEmail extends ActionNotification
|
||||
return implode(', ', $aRecipients);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param \Trigger $oTrigger
|
||||
* @param array $aContextArgs
|
||||
*
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \CoreWarning
|
||||
*/
|
||||
public function DoExecute($oTrigger, $aContextArgs)
|
||||
{
|
||||
if (MetaModel::IsLogEnabledNotification())
|
||||
@@ -292,6 +299,14 @@ class ActionEmail extends ActionNotification
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Trigger $oTrigger
|
||||
* @param array $aContextArgs
|
||||
* @param \EventNotification $oLog
|
||||
*
|
||||
* @return string
|
||||
* @throws \CoreException
|
||||
*/
|
||||
protected function _DoExecute($oTrigger, $aContextArgs, &$oLog)
|
||||
{
|
||||
$sPreviousUrlMaker = ApplicationContext::SetUrlMakerClass();
|
||||
|
||||
@@ -150,7 +150,7 @@ abstract class AsyncTask extends DBObject
|
||||
public function GetRetryDelay($iErrorCode = null)
|
||||
{
|
||||
$iRetryDelay = 600;
|
||||
$aRetries = MetaModel::GetConfig()->Get('async_task_retries', array());
|
||||
$aRetries = MetaModel::GetConfig()->Get('async_task_retries');
|
||||
if (is_array($aRetries) && array_key_exists(get_class($this), $aRetries))
|
||||
{
|
||||
$aConfig = $aRetries[get_class($this)];
|
||||
@@ -162,7 +162,7 @@ abstract class AsyncTask extends DBObject
|
||||
public function GetMaxRetries($iErrorCode = null)
|
||||
{
|
||||
$iMaxRetries = 0;
|
||||
$aRetries = MetaModel::GetConfig()->Get('async_task_retries', array());
|
||||
$aRetries = MetaModel::GetConfig()->Get('async_task_retries');
|
||||
if (is_array($aRetries) && array_key_exists(get_class($this), $aRetries))
|
||||
{
|
||||
$aConfig = $aRetries[get_class($this)];
|
||||
@@ -381,6 +381,6 @@ class AsyncSendEmail extends AsyncTask
|
||||
case EMAIL_SEND_ERROR:
|
||||
return "Failed: ".implode(', ', $aIssues);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -29,6 +29,7 @@ MetaModel::IncludeModule('core/action.class.inc.php');
|
||||
MetaModel::IncludeModule('core/trigger.class.inc.php');
|
||||
MetaModel::IncludeModule('core/bulkexport.class.inc.php');
|
||||
MetaModel::IncludeModule('core/ownershiplock.class.inc.php');
|
||||
MetaModel::IncludeModule('core/tagsetfield.class.inc.php');
|
||||
MetaModel::IncludeModule('synchro/synchrodatasource.class.inc.php');
|
||||
MetaModel::IncludeModule('core/backgroundtask.class.inc.php');
|
||||
MetaModel::IncludeModule('core/inlineimage.class.inc.php');
|
||||
|
||||
@@ -242,6 +242,64 @@ class CMDBChangeOpSetAttributeScalar extends CMDBChangeOpSetAttribute
|
||||
return $sResult;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Record the modification of a tag set attribute
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
class CMDBChangeOpSetAttributeTagSet extends CMDBChangeOpSetAttribute
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "core/cmdb",
|
||||
"key_type" => "",
|
||||
"name_attcode" => "change",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_changeop_setatt_tagset",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeText("oldvalue", array("allowed_values"=>null, "sql"=>"oldvalue", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("newvalue", array("allowed_values"=>null, "sql"=>"newvalue", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('date', 'userinfo', 'attcode', 'oldvalue', 'newvalue')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('date', 'userinfo', 'attcode', 'oldvalue', 'newvalue')); // Attributes to be displayed for a list
|
||||
}
|
||||
|
||||
/**
|
||||
* Describe (as a text string) the modifications corresponding to this change
|
||||
*/
|
||||
public function GetDescription()
|
||||
{
|
||||
$sResult = '';
|
||||
$sTargetObjectClass = $this->Get('objclass');
|
||||
$oTargetObjectKey = $this->Get('objkey');
|
||||
$sAttCode = $this->Get('attcode');
|
||||
$oTargetSearch = new DBObjectSearch($sTargetObjectClass);
|
||||
$oTargetSearch->AddCondition('id', $oTargetObjectKey, '=');
|
||||
|
||||
$oMonoObjectSet = new DBObjectSet($oTargetSearch);
|
||||
if (UserRights::IsActionAllowedOnAttribute($sTargetObjectClass, $sAttCode, UR_ACTION_READ, $oMonoObjectSet) == UR_ALLOWED_YES)
|
||||
{
|
||||
if (!MetaModel::IsValidAttCode($this->Get('objclass'), $this->Get('attcode'))) return ''; // Protects against renamed attributes...
|
||||
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->Get('objclass'), $this->Get('attcode'));
|
||||
$sAttName = $oAttDef->GetLabel();
|
||||
$sNewValue = $this->Get('newvalue');
|
||||
$sOldValue = $this->Get('oldvalue');
|
||||
$sResult = $oAttDef->DescribeChangeAsHTML($sOldValue, $sNewValue);
|
||||
}
|
||||
return $sResult;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Record the modification of an URL
|
||||
*
|
||||
|
||||
@@ -188,6 +188,16 @@ abstract class CMDBObject extends DBObject
|
||||
self::$m_oCurrChange->DBInsert();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreCannotSaveObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \CoreWarning
|
||||
* @throws \MySQLException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
protected function RecordObjCreation()
|
||||
{
|
||||
// Delete any existing change tracking about the current object (IDs can be reused due to InnoDb bug; see TRAC #886)
|
||||
@@ -206,6 +216,7 @@ abstract class CMDBObject extends DBObject
|
||||
MetaModel::PurgeData($oFilter);
|
||||
|
||||
parent::RecordObjCreation();
|
||||
|
||||
$oMyChangeOp = MetaModel::NewObject("CMDBChangeOpCreate");
|
||||
$oMyChangeOp->Set("objclass", get_class($this));
|
||||
$oMyChangeOp->Set("objkey", $this->GetKey());
|
||||
@@ -232,9 +243,17 @@ abstract class CMDBObject extends DBObject
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $sAttCode
|
||||
* @param string $sAttCode
|
||||
* @param $original Original value
|
||||
* @param $value Current value
|
||||
*
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreCannotSaveObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \CoreWarning
|
||||
* @throws \MySQLException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
protected function RecordAttChange($sAttCode, $original, $value)
|
||||
{
|
||||
@@ -409,7 +428,19 @@ abstract class CMDBObject extends DBObject
|
||||
$oMyChangeOp->Set("newvalue", $value);
|
||||
$iId = $oMyChangeOp->DBInsertNoReload();
|
||||
}
|
||||
else
|
||||
elseif ($oAttDef instanceOf AttributeSet)
|
||||
{
|
||||
// Tag Set
|
||||
//
|
||||
$oMyChangeOp = MetaModel::NewObject("CMDBChangeOpSetAttributeTagSet");
|
||||
$oMyChangeOp->Set("objclass", get_class($this));
|
||||
$oMyChangeOp->Set("objkey", $this->GetKey());
|
||||
$oMyChangeOp->Set("attcode", $sAttCode);
|
||||
$oMyChangeOp->Set("oldvalue", implode(' ', $original->GetValues()));
|
||||
$oMyChangeOp->Set("newvalue", implode(' ', $value->GetValues()));
|
||||
$iId = $oMyChangeOp->DBInsertNoReload();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Scalars
|
||||
//
|
||||
@@ -426,6 +457,14 @@ abstract class CMDBObject extends DBObject
|
||||
/**
|
||||
* @param array $aValues
|
||||
* @param array $aOrigValues
|
||||
*
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreCannotSaveObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \CoreWarning
|
||||
* @throws \MySQLException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
protected function RecordAttChanges(array $aValues, array $aOrigValues)
|
||||
{
|
||||
@@ -551,6 +590,12 @@ abstract class CMDBObject extends DBObject
|
||||
$this->DBUpdate();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param null $oDeletionPlan
|
||||
*
|
||||
* @return \DeletionPlan|null
|
||||
* @throws \DeleteException
|
||||
*/
|
||||
public function DBDelete(&$oDeletionPlan = null)
|
||||
{
|
||||
return $this->DBDeleteTracked_Internal($oDeletionPlan);
|
||||
@@ -563,6 +608,12 @@ abstract class CMDBObject extends DBObject
|
||||
$this->DBDeleteTracked_Internal($oDeletionPlan);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param null $oDeletionPlan
|
||||
*
|
||||
* @return \DeletionPlan|null
|
||||
* @throws \DeleteException
|
||||
*/
|
||||
protected function DBDeleteTracked_Internal(&$oDeletionPlan = null)
|
||||
{
|
||||
$prevkey = $this->GetKey();
|
||||
@@ -645,6 +696,8 @@ abstract class CMDBObject extends DBObject
|
||||
* TODO: investigate how to get rid of this class that was made to workaround some language limitation... or a poor design!
|
||||
*
|
||||
* @package iTopORM
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class CMDBObjectSet extends DBObjectSet
|
||||
{
|
||||
|
||||
@@ -108,18 +108,22 @@ class MySQLHasGoneAwayException extends MySQLException
|
||||
*/
|
||||
class CMDBSource
|
||||
{
|
||||
const ENUM_DB_VENDOR_MYSQL = 'MySQL';
|
||||
const ENUM_DB_VENDOR_MARIADB = 'MariaDB';
|
||||
const ENUM_DB_VENDOR_PERCONA = 'Percona';
|
||||
|
||||
protected static $m_sDBHost;
|
||||
protected static $m_sDBUser;
|
||||
protected static $m_sDBPwd;
|
||||
protected static $m_sDBName;
|
||||
/**
|
||||
* @var boolean
|
||||
* @since 2.5 #1260 MySQL TLS first implementation
|
||||
* @since 2.5 N°1260 MySQL TLS first implementation
|
||||
*/
|
||||
protected static $m_bDBTlsEnabled;
|
||||
/**
|
||||
* @var string
|
||||
* @since 2.5 #1260 MySQL TLS first implementation
|
||||
* @since 2.5 N°1260 MySQL TLS first implementation
|
||||
*/
|
||||
protected static $m_sDBTlsCA;
|
||||
|
||||
@@ -133,7 +137,7 @@ class CMDBSource
|
||||
* use expression as value)
|
||||
*
|
||||
* @see https://dev.mysql.com/doc/refman/5.7/en/charset-column.html
|
||||
* @since 2.5 #1001 switch to utf8mb4
|
||||
* @since 2.5 N°1001 switch to utf8mb4
|
||||
*/
|
||||
public static function GetSqlStringColumnDefinition()
|
||||
{
|
||||
@@ -406,6 +410,27 @@ class CMDBSource
|
||||
return $aVersions[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the DB vendor between MySQL and its main forks
|
||||
* @return string
|
||||
*/
|
||||
static public function GetDBVendor()
|
||||
{
|
||||
$sDBVendor = static::ENUM_DB_VENDOR_MYSQL;
|
||||
|
||||
$sVersionComment = static::GetServerVariable('version') . ' - ' . static::GetServerVariable('version_comment');
|
||||
if(preg_match('/mariadb/i', $sVersionComment) === 1)
|
||||
{
|
||||
$sDBVendor = static::ENUM_DB_VENDOR_MARIADB;
|
||||
}
|
||||
else if(preg_match('/percona/i', $sVersionComment) === 1)
|
||||
{
|
||||
$sDBVendor = static::ENUM_DB_VENDOR_PERCONA;
|
||||
}
|
||||
|
||||
return $sDBVendor;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sSource
|
||||
*
|
||||
@@ -455,10 +480,15 @@ class CMDBSource
|
||||
public static function DropTable($sTable)
|
||||
{
|
||||
$res = self::Query("DROP TABLE `$sTable`");
|
||||
self::_TablesInfoCacheReset(true); // reset the table info cache!
|
||||
self::_TablesInfoCacheReset(); // reset the table info cache!
|
||||
return $res;
|
||||
}
|
||||
|
||||
public static function CacheReset($sTable)
|
||||
{
|
||||
self::_TablesInfoCacheReset($sTable);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \mysqli
|
||||
*/
|
||||
@@ -870,6 +900,20 @@ class CMDBSource
|
||||
return ($aFieldData["Type"]);
|
||||
}
|
||||
|
||||
private static function IsNumericType($aFieldData)
|
||||
{
|
||||
$aNumericTypes = array('tinyint(', 'decimal(', 'int(' );
|
||||
$sType = strtolower($aFieldData["Type"]);
|
||||
foreach ($aNumericTypes as $sNumericType)
|
||||
{
|
||||
if (strpos($sType, $sNumericType) === 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sTable
|
||||
* @param string $sField
|
||||
@@ -908,8 +952,15 @@ class CMDBSource
|
||||
}
|
||||
else
|
||||
{
|
||||
$default = $aFieldData["Default"] + 0; // Coerce to a numeric variable
|
||||
$sRet .= ' DEFAULT '.self::Quote($default);
|
||||
if (self::IsNumericType($aFieldData))
|
||||
{
|
||||
$sRet .= ' DEFAULT '.$aFieldData["Default"];
|
||||
}
|
||||
else
|
||||
{
|
||||
$default = $aFieldData["Default"] + 0; // Coerce to a numeric variable
|
||||
$sRet .= ' DEFAULT '.self::Quote($default);
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif (is_string($aFieldData["Default"]) == 'string')
|
||||
@@ -967,9 +1018,16 @@ class CMDBSource
|
||||
|
||||
// Cache the information about existing tables, and their fields
|
||||
private static $m_aTablesInfo = array();
|
||||
private static function _TablesInfoCacheReset()
|
||||
private static function _TablesInfoCacheReset($sTableName = null)
|
||||
{
|
||||
self::$m_aTablesInfo = array();
|
||||
if (is_null($sTableName))
|
||||
{
|
||||
self::$m_aTablesInfo = array();
|
||||
}
|
||||
else
|
||||
{
|
||||
self::$m_aTablesInfo[strtolower($sTableName)] = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1042,7 +1100,7 @@ class CMDBSource
|
||||
* @return string query to upgrade table charset and collation if needed, null if not
|
||||
* @throws \MySQLException
|
||||
*
|
||||
* @since 2.5 #1001 switch to utf8mb4
|
||||
* @since 2.5 N°1001 switch to utf8mb4
|
||||
* @see https://dev.mysql.com/doc/refman/5.7/en/charset-table.html
|
||||
*/
|
||||
public static function DBCheckTableCharsetAndCollation($sTableName)
|
||||
@@ -1192,7 +1250,7 @@ class CMDBSource
|
||||
* @return string query to upgrade database charset and collation if needed, null if not
|
||||
* @throws \MySQLException
|
||||
*
|
||||
* @since 2.5 #1001 switch to utf8mb4
|
||||
* @since 2.5 N°1001 switch to utf8mb4
|
||||
* @see https://dev.mysql.com/doc/refman/5.7/en/charset-database.html
|
||||
*/
|
||||
public static function DBCheckCharsetAndCollation()
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
define('ITOP_APPLICATION', 'iTop');
|
||||
define('ITOP_APPLICATION_SHORT', 'iTop');
|
||||
define('ITOP_VERSION', '2.5.0');
|
||||
define('ITOP_VERSION', '2.6.2');
|
||||
define('ITOP_REVISION', 'svn');
|
||||
define('ITOP_BUILD_DATE', '$WCNOW$');
|
||||
|
||||
@@ -37,6 +37,7 @@ define('ACCESS_READONLY', 0);
|
||||
|
||||
require_once('coreexception.class.inc.php');
|
||||
require_once('attributedef.class.inc.php'); // For the defines
|
||||
require_once('simplecrypt.class.inc.php');
|
||||
|
||||
class ConfigException extends CoreException
|
||||
{
|
||||
@@ -64,13 +65,16 @@ define('DEFAULT_FAST_RELOAD_INTERVAL', 1 * 60);
|
||||
define('DEFAULT_SECURE_CONNECTION_REQUIRED', false);
|
||||
define('DEFAULT_ALLOWED_LOGIN_TYPES', 'form|basic|external');
|
||||
define('DEFAULT_EXT_AUTH_VARIABLE', '$_SERVER[\'REMOTE_USER\']');
|
||||
define('DEFAULT_ENCRYPTION_KEY', '@iT0pEncr1pti0n!'); // We'll use a random value, later...
|
||||
|
||||
define('DEFAULT_ENCRYPTION_KEY', '@iT0pEncr1pti0n!'); // We'll use a random generated key later (if possible)
|
||||
define('DEFAULT_ENCRYPTION_LIB', 'Mcrypt'); // We'll define the best encryption available later
|
||||
/**
|
||||
* Config
|
||||
* configuration data (this class cannot not be localized, because it is responsible for loading the dictionaries)
|
||||
*
|
||||
* @package iTopORM
|
||||
*
|
||||
* @see \MetaModel::GetConfig() to get the config, if the metamodel was already loaded
|
||||
* @see utils::GetConfig() to load config from the current env, if metamodel is not loaded
|
||||
*/
|
||||
class Config
|
||||
{
|
||||
@@ -93,7 +97,7 @@ class Config
|
||||
protected $m_aSettings = array(
|
||||
'app_env_label' => array(
|
||||
'type' => 'string',
|
||||
'description' => 'Label displayed to describe the current application environnment, defaults to the environment name (e.g. "production")',
|
||||
'description' => 'Label displayed to describe the current application environment, defaults to the environment name (e.g. "production")',
|
||||
'default' => '',
|
||||
'value' => '',
|
||||
'source_of_value' => '',
|
||||
@@ -166,7 +170,7 @@ class Config
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
),
|
||||
'db_character_set' => array( // @deprecated to remove in 2.7 ? #1001 utf8mb4 switch
|
||||
'db_character_set' => array( // @deprecated to remove in 2.7 ? N°1001 utf8mb4 switch
|
||||
'type' => 'string',
|
||||
'description' => 'Deprecated since iTop 2.5 : now using utf8mb4',
|
||||
'default' => 'DEPRECATED_2.5',
|
||||
@@ -174,7 +178,7 @@ class Config
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
),
|
||||
'db_collation' => array( // @deprecated to remove in 2.7 ? #1001 utf8mb4 switch
|
||||
'db_collation' => array( // @deprecated to remove in 2.7 ? N°1001 utf8mb4 switch
|
||||
'type' => 'string',
|
||||
'description' => 'Deprecated since iTop 2.5 : now using utf8mb4_unicode_ci',
|
||||
'default' => 'DEPRECATED_2.5',
|
||||
@@ -200,7 +204,7 @@ class Config
|
||||
),
|
||||
'skip_strong_security' => array(
|
||||
'type' => 'bool',
|
||||
'description' => 'Disable strong security - TEMPORY: this flag should be removed when we are more confident in the recent change in security',
|
||||
'description' => 'Disable strong security - TEMPORARY: this flag should be removed when we are more confident in the recent change in security',
|
||||
'default' => true,
|
||||
'value' => true,
|
||||
'source_of_value' => '',
|
||||
@@ -216,7 +220,7 @@ class Config
|
||||
),
|
||||
'query_indentation_enabled' => array(
|
||||
'type' => 'bool',
|
||||
'description' => 'For developpers: format the SQL queries for human analysis',
|
||||
'description' => 'For developers: format the SQL queries for human analysis',
|
||||
'default' => false,
|
||||
'value' => false,
|
||||
'source_of_value' => '',
|
||||
@@ -224,7 +228,7 @@ class Config
|
||||
),
|
||||
'disable_mandatory_ext_keys' => array(
|
||||
'type' => 'bool',
|
||||
'description' => 'For developpers: allow every external keys to be undefined',
|
||||
'description' => 'For developers: allow every external keys to be undefined',
|
||||
'default' => false,
|
||||
'value' => false,
|
||||
'source_of_value' => '',
|
||||
@@ -407,6 +411,14 @@ class Config
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'tag_set_item_separator' => array(
|
||||
'type' => 'string',
|
||||
'description' => 'Tag set from string: tag label separator',
|
||||
'default' => '|',
|
||||
'value' => '|',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'cron_max_execution_time' => array(
|
||||
'type' => 'integer',
|
||||
'description' => 'Duration (seconds) of the page cron.php, must be shorter than php setting max_execution_time and shorter than the web server response timeout',
|
||||
@@ -441,7 +453,7 @@ class Config
|
||||
),
|
||||
'email_transport' => array(
|
||||
'type' => 'string',
|
||||
'description' => 'Mean to send emails: PHPMail (uses the function mail()) or SMTP (implements the client protocole)',
|
||||
'description' => 'Mean to send emails: PHPMail (uses the function mail()) or SMTP (implements the client protocol)',
|
||||
'default' => "PHPMail",
|
||||
'value' => "PHPMail",
|
||||
'source_of_value' => '',
|
||||
@@ -537,7 +549,7 @@ class Config
|
||||
),
|
||||
'timezone' => array(
|
||||
'type' => 'string',
|
||||
'description' => 'Timezone (reference: http://php.net/manual/en/timezones.php). If empty, it will be left unchanged and MUST be explicitely configured in PHP',
|
||||
'description' => 'Timezone (reference: http://php.net/manual/en/timezones.php). If empty, it will be left unchanged and MUST be explicitly configured in PHP',
|
||||
// examples... not used (nor 'description')
|
||||
'examples' => array(
|
||||
'America/Sao_Paulo',
|
||||
@@ -935,7 +947,7 @@ class Config
|
||||
),
|
||||
'tracking_level_linked_set_default' => array(
|
||||
'type' => 'integer',
|
||||
'description' => 'Default tracking level if not explicitely set at the attribute level, for AttributeLinkedSet (defaults to NONE in case of a fresh install, LIST otherwise - this to preserve backward compatibility while upgrading from a version older than 2.0.3 - see TRAC #936)',
|
||||
'description' => 'Default tracking level if not explicitly set at the attribute level, for AttributeLinkedSet (defaults to NONE in case of a fresh install, LIST otherwise - this to preserve backward compatibility while upgrading from a version older than 2.0.3 - see TRAC #936)',
|
||||
'default' => LINKSET_TRACKING_LIST,
|
||||
'value' => LINKSET_TRACKING_LIST,
|
||||
'source_of_value' => '',
|
||||
@@ -943,7 +955,7 @@ class Config
|
||||
),
|
||||
'tracking_level_linked_set_indirect_default' => array(
|
||||
'type' => 'integer',
|
||||
'description' => 'Default tracking level if not explicitely set at the attribute level, for AttributeLinkedSetIndirect',
|
||||
'description' => 'Default tracking level if not explicitly set at the attribute level, for AttributeLinkedSetIndirect',
|
||||
'default' => LINKSET_TRACKING_ALL,
|
||||
'value' => LINKSET_TRACKING_ALL,
|
||||
'source_of_value' => '',
|
||||
@@ -984,7 +996,7 @@ class Config
|
||||
'transaction_storage' => array(
|
||||
'type' => 'string',
|
||||
'description' => 'The type of mechanism to use for storing the unique identifiers for transactions (Session|File).',
|
||||
'default' => 'Session',
|
||||
'default' => 'File',
|
||||
'value' => '',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
@@ -1056,7 +1068,7 @@ class Config
|
||||
'draft_attachments_lifetime' => array(
|
||||
'type' => 'integer',
|
||||
'description' => 'Lifetime (in seconds) of drafts\' attachments and inline images: after this duration, the garbage collector will delete them.',
|
||||
'default' => 3600,
|
||||
'default' => 86400,
|
||||
'value' => '',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
@@ -1117,6 +1129,14 @@ class Config
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'optimize_requests_for_join_count' => array(
|
||||
'type' => 'bool',
|
||||
'description' => 'Optimize request joins to minimize the count (default is true, try to set it to false in case of performance issues)',
|
||||
'default' => true,
|
||||
'value' => true,
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'high_cardinality_classes' => array(
|
||||
'type' => 'array',
|
||||
'description' => 'List of classes with high cardinality (Force manual submit of search)',
|
||||
@@ -1125,6 +1145,22 @@ class Config
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'newsroom_enabled' => array(
|
||||
'type' => 'bool',
|
||||
'description' => 'Whether or not the whole newsroom is enabled',
|
||||
'default' => true,
|
||||
'value' => true,
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
),
|
||||
'regenerate_session_id_enabled' => array(
|
||||
'type' => 'bool',
|
||||
'description' => 'If true then session id will be regenerated on each login, to prevent session fixation.',
|
||||
'default' => true,
|
||||
'value' => true,
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
),
|
||||
);
|
||||
|
||||
public function IsProperty($sPropCode)
|
||||
@@ -1184,6 +1220,11 @@ class Config
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sPropCode
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function Get($sPropCode)
|
||||
{
|
||||
return $this->m_aSettings[$sPropCode]['value'];
|
||||
@@ -1246,13 +1287,29 @@ class Config
|
||||
*/
|
||||
protected $m_sEncryptionKey;
|
||||
|
||||
/**
|
||||
* @var string Encryption key used for all attributes of type "encrypted string". Can be set to a random value
|
||||
* unless you want to import a database from another iTop instance, in which case you must use
|
||||
* the same encryption key in order to properly decode the encrypted fields
|
||||
*/
|
||||
protected $m_sEncryptionLibrary;
|
||||
|
||||
/**
|
||||
* @var array Additional character sets to be supported by the interactive CSV import
|
||||
* 'iconv_code' => 'display name'
|
||||
*/
|
||||
protected $m_aCharsets;
|
||||
|
||||
public function __construct($sConfigFile = null, $bLoadConfig = true)
|
||||
/**
|
||||
* Config constructor.
|
||||
*
|
||||
* @param string|null $sConfigFile
|
||||
* @param bool $bLoadConfig
|
||||
*
|
||||
* @throws \ConfigException
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public function __construct($sConfigFile = null, $bLoadConfig = true)
|
||||
{
|
||||
$this->m_sFile = $sConfigFile;
|
||||
if (is_null($sConfigFile))
|
||||
@@ -1282,10 +1339,14 @@ class Config
|
||||
$this->m_sDefaultLanguage = 'EN US';
|
||||
$this->m_sAllowedLoginTypes = DEFAULT_ALLOWED_LOGIN_TYPES;
|
||||
$this->m_sExtAuthVariable = DEFAULT_EXT_AUTH_VARIABLE;
|
||||
$this->m_sEncryptionKey = DEFAULT_ENCRYPTION_KEY;
|
||||
$this->m_aCharsets = array();
|
||||
$this->m_bQueryCacheEnabled = DEFAULT_QUERY_CACHE_ENABLED;
|
||||
|
||||
//define default encryption params according to php install
|
||||
$aEncryptParams = SimpleCrypt::GetNewDefaultParams();
|
||||
$this->m_sEncryptionLibrary = isset($aEncryptParams['lib']) ? $aEncryptParams['lib'] : DEFAULT_ENCRYPTION_LIB;
|
||||
$this->m_sEncryptionKey= isset($aEncryptParams['key']) ? $aEncryptParams['key'] : DEFAULT_ENCRYPTION_KEY;
|
||||
|
||||
$this->m_aModuleSettings = array();
|
||||
|
||||
if ($bLoadConfig)
|
||||
@@ -1310,7 +1371,13 @@ class Config
|
||||
*/
|
||||
}
|
||||
|
||||
protected function CheckFile($sPurpose, $sFileName)
|
||||
/**
|
||||
* @param string $sPurpose
|
||||
* @param string $sFileName
|
||||
*
|
||||
* @throws \ConfigException
|
||||
*/
|
||||
protected function CheckFile($sPurpose, $sFileName)
|
||||
{
|
||||
if (!file_exists($sFileName))
|
||||
{
|
||||
@@ -1425,7 +1492,8 @@ class Config
|
||||
$this->m_sDefaultLanguage = isset($MySettings['default_language']) ? trim($MySettings['default_language']) : 'EN US';
|
||||
$this->m_sAllowedLoginTypes = isset($MySettings['allowed_login_types']) ? trim($MySettings['allowed_login_types']) : DEFAULT_ALLOWED_LOGIN_TYPES;
|
||||
$this->m_sExtAuthVariable = isset($MySettings['ext_auth_variable']) ? trim($MySettings['ext_auth_variable']) : DEFAULT_EXT_AUTH_VARIABLE;
|
||||
$this->m_sEncryptionKey = isset($MySettings['encryption_key']) ? trim($MySettings['encryption_key']) : DEFAULT_ENCRYPTION_KEY;
|
||||
$this->m_sEncryptionKey = isset($MySettings['encryption_key']) ? trim($MySettings['encryption_key']) : $this->m_sEncryptionKey;
|
||||
$this->m_sEncryptionLibrary = isset($MySettings['encryption_library']) ? trim($MySettings['encryption_library']) : $this->m_sEncryptionLibrary;
|
||||
$this->m_aCharsets = isset($MySettings['csv_import_charsets']) ? $MySettings['csv_import_charsets'] : array();
|
||||
}
|
||||
|
||||
@@ -1446,7 +1514,14 @@ class Config
|
||||
return $this->GetModuleParameter($sModule, $sProperty, $defaultvalue);
|
||||
}
|
||||
|
||||
public function GetModuleParameter($sModule, $sProperty, $defaultvalue = null)
|
||||
/**
|
||||
* @param string $sModule
|
||||
* @param string $sProperty
|
||||
* @param mixed|null $defaultvalue
|
||||
*
|
||||
* @return mixed|null
|
||||
*/
|
||||
public function GetModuleParameter($sModule, $sProperty, $defaultvalue = null)
|
||||
{
|
||||
$ret = $defaultvalue;
|
||||
if (class_exists('ModulesXMLParameters'))
|
||||
@@ -1478,6 +1553,7 @@ class Config
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*
|
||||
* @deprecated 2.5 will be removed in 2.6
|
||||
* @see Config::Get() as a replacement
|
||||
*/
|
||||
@@ -1488,6 +1564,7 @@ class Config
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*
|
||||
* @deprecated 2.5 will be removed in 2.6
|
||||
* @see Config::Get() as a replacement
|
||||
*/
|
||||
@@ -1498,6 +1575,7 @@ class Config
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*
|
||||
* @deprecated 2.5 will be removed in 2.6
|
||||
* @see Config::Get() as a replacement
|
||||
*/
|
||||
@@ -1508,7 +1586,8 @@ class Config
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @deprecated 2.5 will be removed in 2.6 #1001 utf8mb4 switch
|
||||
*
|
||||
* @deprecated 2.5 will be removed in 2.6 N°1001 utf8mb4 switch
|
||||
* @see Config::DEFAULT_CHARACTER_SET
|
||||
*/
|
||||
public function GetDBCharacterSet()
|
||||
@@ -1518,7 +1597,8 @@ class Config
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @deprecated 2.5 will be removed in 2.6 #1001 utf8mb4 switch
|
||||
*
|
||||
* @deprecated 2.5 will be removed in 2.6 N°1001 utf8mb4 switch
|
||||
* @see Config::DEFAULT_COLLATION
|
||||
*/
|
||||
public function GetDBCollation()
|
||||
@@ -1528,6 +1608,7 @@ class Config
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*
|
||||
* @deprecated 2.5 will be removed in 2.6
|
||||
* @see Config::Get() as a replacement
|
||||
*/
|
||||
@@ -1538,6 +1619,7 @@ class Config
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*
|
||||
* @deprecated 2.5 will be removed in 2.6
|
||||
* @see Config::Get() as a replacement
|
||||
*/
|
||||
@@ -1611,6 +1693,11 @@ class Config
|
||||
return $this->m_sEncryptionKey;
|
||||
}
|
||||
|
||||
public function GetEncryptionLibrary()
|
||||
{
|
||||
return $this->m_sEncryptionLibrary;
|
||||
}
|
||||
|
||||
public function GetAllowedLoginTypes()
|
||||
{
|
||||
return explode('|', $this->m_sAllowedLoginTypes);
|
||||
@@ -1739,6 +1826,7 @@ class Config
|
||||
$aSettings['allowed_login_types'] = $this->m_sAllowedLoginTypes;
|
||||
$aSettings['ext_auth_variable'] = $this->m_sExtAuthVariable;
|
||||
$aSettings['encryption_key'] = $this->m_sEncryptionKey;
|
||||
$aSettings['encryption_library'] = $this->m_sEncryptionLibrary;
|
||||
$aSettings['csv_import_charsets'] = $this->m_aCharsets;
|
||||
|
||||
foreach ($this->m_aModuleSettings as $sModule => $aProperties)
|
||||
@@ -1756,14 +1844,16 @@ class Config
|
||||
return $aSettings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the configuration to a file (php format) that can be reloaded later
|
||||
* By default write to the same file that was specified when constructing the object
|
||||
/**
|
||||
* Write the configuration to a file (php format) that can be reloaded later
|
||||
* By default write to the same file that was specified when constructing the object
|
||||
*
|
||||
* @param string $sFileName string Name of the file to write to (emtpy to write to the same file)
|
||||
*
|
||||
* @return boolean True otherwise throws an Exception
|
||||
*
|
||||
* @param $sFileName string Name of the file to write to (emtpy to write to the same file)
|
||||
*
|
||||
* @return boolean True otherwise throws an Exception
|
||||
*/
|
||||
* @throws \ConfigException
|
||||
*/
|
||||
public function WriteToFile($sFileName = '')
|
||||
{
|
||||
if (empty($sFileName))
|
||||
@@ -1825,6 +1915,7 @@ class Config
|
||||
'allowed_login_types' => $this->m_sAllowedLoginTypes,
|
||||
'ext_auth_variable' => $this->m_sExtAuthVariable,
|
||||
'encryption_key' => $this->m_sEncryptionKey,
|
||||
'encryption_library' => $this->m_sEncryptionLibrary,
|
||||
'csv_import_charsets' => $this->m_aCharsets,
|
||||
);
|
||||
foreach ($aOtherValues as $sKey => $value)
|
||||
@@ -1910,9 +2001,16 @@ class Config
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to initialize a configuration from the page arguments
|
||||
*/
|
||||
/**
|
||||
* Helper function to initialize a configuration from the page arguments
|
||||
*
|
||||
* @param array $aParamValues
|
||||
* @param string|null $sModulesDir
|
||||
* @param bool $bPreserveModuleSettings
|
||||
*
|
||||
* @throws \Exception
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public function UpdateFromParams($aParamValues, $sModulesDir = null, $bPreserveModuleSettings = false)
|
||||
{
|
||||
if (isset($aParamValues['application_path']))
|
||||
@@ -2042,9 +2140,13 @@ class Config
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper: for an array of string, change the prefix when found
|
||||
*/
|
||||
/**
|
||||
* Helper: for an array of string, change the prefix when found
|
||||
*
|
||||
* @param array $aStrings
|
||||
* @param string $sSearchPrefix
|
||||
* @param string $sNewPrefix
|
||||
*/
|
||||
protected static function ChangePrefix(&$aStrings, $sSearchPrefix, $sNewPrefix)
|
||||
{
|
||||
foreach ($aStrings as &$sFile)
|
||||
@@ -2056,10 +2158,13 @@ class Config
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Obsolete: kept only for backward compatibility of the Toolkit
|
||||
* Quick and dirty way to clone a config file into another environment
|
||||
*/
|
||||
/**
|
||||
* Obsolete: kept only for backward compatibility of the Toolkit
|
||||
* Quick and dirty way to clone a config file into another environment
|
||||
*
|
||||
* @param string $sSourceEnv
|
||||
* @param string $sTargetEnv
|
||||
*/
|
||||
public function ChangeModulesPath($sSourceEnv, $sTargetEnv)
|
||||
{
|
||||
// Now does nothing since the includes are built into the environment itself
|
||||
@@ -2096,5 +2201,3 @@ class Config
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
@@ -107,6 +107,82 @@ class CoreException extends Exception
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class CoreCannotSaveObjectException
|
||||
*
|
||||
* Specialized exception to raise if {@link DBObject::CheckToWrite()} fails, which allow easy data retrieval
|
||||
*
|
||||
* @see \DBObject::DBInsertNoReload()
|
||||
* @see \DBObject::DBUpdate()
|
||||
*
|
||||
* @since 2.6 N°659 uniqueness constraint
|
||||
*/
|
||||
class CoreCannotSaveObjectException extends CoreException
|
||||
{
|
||||
/** @var string[] */
|
||||
private $aIssues;
|
||||
/** @var int */
|
||||
private $iObjectId;
|
||||
/** @var string */
|
||||
private $sObjectClass;
|
||||
|
||||
/**
|
||||
* CoreCannotSaveObjectException constructor.
|
||||
*
|
||||
* @param array $aContextData containing at least those keys : issues, id, class
|
||||
*/
|
||||
public function __construct($aContextData)
|
||||
{
|
||||
$this->aIssues = $aContextData['issues'];
|
||||
$this->iObjectId = $aContextData['id'];
|
||||
$this->sObjectClass = $aContextData['class'];
|
||||
|
||||
$sIssues = implode(', ', $this->aIssues);
|
||||
parent::__construct($sIssues, $aContextData);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getHtmlMessage()
|
||||
{
|
||||
$sTitle = Dict::S('UI:Error:SaveFailed');
|
||||
$sContent = "<span><strong>{$sTitle}</strong></span>";
|
||||
|
||||
if (count($this->aIssues) == 1)
|
||||
{
|
||||
$sIssue = reset($this->aIssues);
|
||||
$sContent .= " <span>{$sIssue}</span>";
|
||||
}
|
||||
else
|
||||
{
|
||||
$sContent .= '<ul>';
|
||||
foreach ($this->aIssues as $sError)
|
||||
{
|
||||
$sContent .= "<li>$sError</li>";
|
||||
}
|
||||
$sContent .= '</ul>';
|
||||
}
|
||||
|
||||
return $sContent;
|
||||
}
|
||||
|
||||
public function getIssues()
|
||||
{
|
||||
return $this->aIssues;
|
||||
}
|
||||
|
||||
public function getObjectId()
|
||||
{
|
||||
return $this->iObjectId;
|
||||
}
|
||||
|
||||
public function getObjectClass()
|
||||
{
|
||||
return $this->sObjectClass;
|
||||
}
|
||||
}
|
||||
|
||||
class CoreWarning extends CoreException
|
||||
{
|
||||
}
|
||||
|
||||
@@ -266,7 +266,7 @@ EOF
|
||||
if ($this->aStatusInfo['charset'] != 'UTF-8')
|
||||
{
|
||||
// Note: due to bugs in the glibc library it's safer to call iconv on the smallest possible string
|
||||
// and thus to convert field by field and not the whole row or file at once (see ticket #991)
|
||||
// and thus to convert field by field and not the whole row or file at once (see ticket N°991)
|
||||
$aData[$idx] = @iconv('UTF-8', $this->aStatusInfo['charset'].'//IGNORE//TRANSLIT', $aData[$idx]);
|
||||
}
|
||||
}
|
||||
@@ -325,7 +325,7 @@ EOF
|
||||
if ($this->aStatusInfo['charset'] != 'UTF-8')
|
||||
{
|
||||
// Note: due to bugs in the glibc library it's safer to call iconv on the smallest possible string
|
||||
// and thus to convert field by field and not the whole row or file at once (see ticket #991)
|
||||
// and thus to convert field by field and not the whole row or file at once (see ticket N°991)
|
||||
$aData[] = @iconv('UTF-8', $this->aStatusInfo['charset'].'//IGNORE//TRANSLIT', $sField);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.5">
|
||||
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.6">
|
||||
<user_rights>
|
||||
<profiles>
|
||||
<profile id="1024" _delta="define">
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -17,9 +17,22 @@
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
//
|
||||
|
||||
// Dev hack for disabling the some query build optimizations (Folding/Merging)
|
||||
/** @internal Dev hack for disabling some query build optimizations (Folding/Merging) */
|
||||
define('ENABLE_OPT', true);
|
||||
|
||||
/**
|
||||
* A search over a DBObject
|
||||
*
|
||||
* This is the most common search cases, the other class representing a search is DBUnionSearch.
|
||||
* For clarity purpose, since only the constructor vary between DBObjectSearch and DBUnionSearch, all the API is documented on the common ancestor: DBSearch
|
||||
* Please refer to DBSearch's documentation
|
||||
*
|
||||
* @package iTopORM
|
||||
* @phpdoc-tuning-exclude-inherited this tag prevent PHPdoc from displaying inherited methods. This is done in order to force the API doc. location into DBSearch only.
|
||||
* @api
|
||||
* @see DBSearch
|
||||
* @see DBUnionSearch
|
||||
*/
|
||||
class DBObjectSearch extends DBSearch
|
||||
{
|
||||
private $m_aClasses; // queried classes (alias => class name), the first item is the class corresponding to this filter (the rest is coming from subfilters)
|
||||
@@ -29,11 +42,23 @@ class DBObjectSearch extends DBSearch
|
||||
private $m_aPointingTo;
|
||||
private $m_aReferencedBy;
|
||||
|
||||
// By default, some information may be hidden to the current user
|
||||
// But it may happen that we need to disable that feature
|
||||
/**
|
||||
* @var bool whether or not some information should be hidden to the current user. Default to false == hide information.
|
||||
* @see AllowAllData()
|
||||
*/
|
||||
protected $m_bAllowAllData = false;
|
||||
protected $m_bDataFiltered = false;
|
||||
|
||||
/**
|
||||
* DBObjectSearch constructor.
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @param string $sClass
|
||||
* @param string|null $sClassAlias
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __construct($sClass, $sClassAlias = null)
|
||||
{
|
||||
parent::__construct();
|
||||
@@ -480,6 +505,11 @@ class DBObjectSearch extends DBSearch
|
||||
$oNewCondition = Expression::FromOQL($sOQLCondition);
|
||||
break;
|
||||
|
||||
case 'MATCHES':
|
||||
$oRightExpr = new ScalarExpression($value);
|
||||
$oNewCondition = new MatchExpression($oField, $oRightExpr);
|
||||
break;
|
||||
|
||||
case 'Contains':
|
||||
case 'Begins with':
|
||||
case 'Finishes with':
|
||||
@@ -519,7 +549,7 @@ class DBObjectSearch extends DBSearch
|
||||
/**
|
||||
* Specify a condition on external keys or link sets
|
||||
* @param string $sAttSpec Can be either an attribute code or extkey->[sAttSpec] or linkset->[sAttSpec] and so on, recursively
|
||||
* Example: infra_list->ci_id->location_id->country
|
||||
* Example: infra_list->ci_id->location_id->country
|
||||
* @param $value
|
||||
* @return void
|
||||
* @throws \CoreException
|
||||
@@ -1299,6 +1329,13 @@ class DBObjectSearch extends DBSearch
|
||||
$oRight = $this->OQLExpressionToCondition($sQuery, $oExpression->GetRightExpr(), $aClassAliases);
|
||||
return new BinaryExpression($oLeft, $sOperator, $oRight);
|
||||
}
|
||||
elseif ($oExpression instanceof MatchOqlExpression)
|
||||
{
|
||||
$oLeft = $this->OQLExpressionToCondition($sQuery, $oExpression->GetLeftExpr(), $aClassAliases);
|
||||
$oRight = $this->OQLExpressionToCondition($sQuery, $oExpression->GetRightExpr(), $aClassAliases);
|
||||
|
||||
return new MatchExpression($oLeft, $oRight);
|
||||
}
|
||||
elseif ($oExpression instanceof FieldOqlExpression)
|
||||
{
|
||||
$sClassAlias = $oExpression->GetParent();
|
||||
@@ -1630,7 +1667,7 @@ class DBObjectSearch extends DBSearch
|
||||
// Query caching
|
||||
//
|
||||
$sOqlAPCCacheId = null;
|
||||
if (self::$m_bQueryCacheEnabled)
|
||||
if (self::$m_bQueryCacheEnabled && $bCanCache)
|
||||
{
|
||||
// Warning: using directly the query string as the key to the hash array can FAIL if the string
|
||||
// is long and the differences are only near the end... so it's safer (but not bullet proof?)
|
||||
@@ -1925,46 +1962,86 @@ class DBObjectSearch extends DBSearch
|
||||
}
|
||||
}
|
||||
|
||||
// First query built from the root, adding all tables including the leaf
|
||||
// Before N.1065 we were joining from the leaf first, but this wasn't a good choice :
|
||||
// most of the time (obsolescence, friendlyname, ...) we want to get a root attribute !
|
||||
//
|
||||
$oSelectBase = null;
|
||||
$aClassHierarchy = MetaModel::EnumParentClasses($sClass, ENUM_PARENT_CLASSES_ALL, true);
|
||||
$bIsClassStandaloneClass = (count($aClassHierarchy) == 1);
|
||||
foreach($aClassHierarchy as $sSomeClass)
|
||||
$bRootFirst = MetaModel::GetConfig()->Get('optimize_requests_for_join_count');
|
||||
if ($bRootFirst)
|
||||
{
|
||||
if (!MetaModel::HasTable($sSomeClass))
|
||||
// First query built from the root, adding all tables including the leaf
|
||||
// Before N.1065 we were joining from the leaf first, but this wasn't a good choice :
|
||||
// most of the time (obsolescence, friendlyname, ...) we want to get a root attribute !
|
||||
//
|
||||
$oSelectBase = null;
|
||||
$aClassHierarchy = MetaModel::EnumParentClasses($sClass, ENUM_PARENT_CLASSES_ALL, true);
|
||||
$bIsClassStandaloneClass = (count($aClassHierarchy) == 1);
|
||||
foreach($aClassHierarchy as $sSomeClass)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
self::DbgTrace("Adding join from root to leaf: $sSomeClass... let's call MakeSQLObjectQuerySingleTable()");
|
||||
$oSelectParentTable = $this->MakeSQLObjectQuerySingleTable($oBuild, $aAttToLoad, $sSomeClass, $aExtKeys, $aValues);
|
||||
if (is_null($oSelectBase))
|
||||
{
|
||||
$oSelectBase = $oSelectParentTable;
|
||||
if (!$bIsClassStandaloneClass && (MetaModel::IsRootClass($sSomeClass)))
|
||||
if (!MetaModel::HasTable($sSomeClass))
|
||||
{
|
||||
// As we're linking to root class first, we're adding a where clause on the finalClass attribute :
|
||||
// COALESCE($sRootClassFinalClass IN ('$sExpectedClasses'), 1)
|
||||
// If we don't, the child classes can be removed in the query optimisation phase, including the leaf that was queried
|
||||
// So we still need to filter records to only those corresponding to the child classes !
|
||||
// The coalesce is mandatory if we have a polymorphic query (left join)
|
||||
$oClassListExpr = ListExpression::FromScalars(MetaModel::EnumChildClasses($sClass, ENUM_CHILD_CLASSES_ALL));
|
||||
$sFinalClassSqlColumnName = MetaModel::DBGetClassField($sSomeClass);
|
||||
$oClassExpr = new FieldExpression($sFinalClassSqlColumnName, $oSelectBase->GetTableAlias());
|
||||
$oInExpression = new BinaryExpression($oClassExpr, 'IN', $oClassListExpr);
|
||||
$oTrueExpression = new TrueExpression();
|
||||
$aCoalesceAttr = array($oInExpression, $oTrueExpression);
|
||||
$oFinalClassRestriction = new FunctionExpression("COALESCE", $aCoalesceAttr);
|
||||
|
||||
$oBuild->m_oQBExpressions->AddCondition($oFinalClassRestriction);
|
||||
continue;
|
||||
}
|
||||
|
||||
self::DbgTrace("Adding join from root to leaf: $sSomeClass... let's call MakeSQLObjectQuerySingleTable()");
|
||||
$oSelectParentTable = $this->MakeSQLObjectQuerySingleTable($oBuild, $aAttToLoad, $sSomeClass, $aExtKeys, $aValues);
|
||||
if (is_null($oSelectBase))
|
||||
{
|
||||
$oSelectBase = $oSelectParentTable;
|
||||
if (!$bIsClassStandaloneClass && (MetaModel::IsRootClass($sSomeClass)))
|
||||
{
|
||||
// As we're linking to root class first, we're adding a where clause on the finalClass attribute :
|
||||
// COALESCE($sRootClassFinalClass IN ('$sExpectedClasses'), 1)
|
||||
// If we don't, the child classes can be removed in the query optimisation phase, including the leaf that was queried
|
||||
// So we still need to filter records to only those corresponding to the child classes !
|
||||
// The coalesce is mandatory if we have a polymorphic query (left join)
|
||||
$oClassListExpr = ListExpression::FromScalars(MetaModel::EnumChildClasses($sClass, ENUM_CHILD_CLASSES_ALL));
|
||||
$sFinalClassSqlColumnName = MetaModel::DBGetClassField($sSomeClass);
|
||||
$oClassExpr = new FieldExpression($sFinalClassSqlColumnName, $oSelectBase->GetTableAlias());
|
||||
$oInExpression = new BinaryExpression($oClassExpr, 'IN', $oClassListExpr);
|
||||
$oTrueExpression = new TrueExpression();
|
||||
$aCoalesceAttr = array($oInExpression, $oTrueExpression);
|
||||
$oFinalClassRestriction = new FunctionExpression("COALESCE", $aCoalesceAttr);
|
||||
|
||||
$oBuild->m_oQBExpressions->AddCondition($oFinalClassRestriction);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$oSelectBase->AddInnerJoin($oSelectParentTable, $sKeyField, MetaModel::DBGetKey($sSomeClass));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// First query built upon on the leaf (ie current) class
|
||||
//
|
||||
self::DbgTrace("Main (=leaf) class, call MakeSQLObjectQuerySingleTable()");
|
||||
if (MetaModel::HasTable($sClass))
|
||||
{
|
||||
$oSelectBase = $this->MakeSQLObjectQuerySingleTable($oBuild, $aAttToLoad, $sClass, $aExtKeys, $aValues);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oSelectBase->AddInnerJoin($oSelectParentTable, $sKeyField, MetaModel::DBGetKey($sSomeClass));
|
||||
$oSelectBase = null;
|
||||
|
||||
// As the join will not filter on the expected classes, we have to specify it explicitely
|
||||
$sExpectedClasses = implode("', '", MetaModel::EnumChildClasses($sClass, ENUM_CHILD_CLASSES_ALL));
|
||||
$oFinalClassRestriction = Expression::FromOQL("`$sClassAlias`.finalclass IN ('$sExpectedClasses')");
|
||||
$oBuild->m_oQBExpressions->AddCondition($oFinalClassRestriction);
|
||||
}
|
||||
|
||||
// Then we join the queries of the eventual parent classes (compound model)
|
||||
foreach(MetaModel::EnumParentClasses($sClass) as $sParentClass)
|
||||
{
|
||||
if (!MetaModel::HasTable($sParentClass)) continue;
|
||||
|
||||
self::DbgTrace("Parent class: $sParentClass... let's call MakeSQLObjectQuerySingleTable()");
|
||||
$oSelectParentTable = $this->MakeSQLObjectQuerySingleTable($oBuild, $aAttToLoad, $sParentClass, $aExtKeys, $aValues);
|
||||
if (is_null($oSelectBase))
|
||||
{
|
||||
$oSelectBase = $oSelectParentTable;
|
||||
}
|
||||
else
|
||||
{
|
||||
$oSelectBase->AddInnerJoin($oSelectParentTable, $sKeyField, MetaModel::DBGetKey($sParentClass));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2292,8 +2369,8 @@ class DBObjectSearch extends DBSearch
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the expression for the class and its subclasses (if finalclass = 'subclass' ...)
|
||||
* Simplifies the final expression by grouping classes having the same expression
|
||||
* Get the expression for the class and its subclasses (if finalclass = 'subclass' ...)
|
||||
* Simplifies the final expression by grouping classes having the same expression
|
||||
* @param $sClass
|
||||
* @param $sAttCode
|
||||
* @return \FunctionExpression|mixed|null
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -22,24 +22,35 @@ require_once('dbunionsearch.class.php');
|
||||
|
||||
/**
|
||||
* An object search
|
||||
*
|
||||
*
|
||||
* DBSearch provides an API that leverage the possibility to construct a search against iTop's persisted objects.
|
||||
* In order to do so, it let you declare the classes you want to fetch, the conditions you want to apply, ...
|
||||
*
|
||||
* Note: in the ancient times of iTop, a search was named after DBObjectSearch.
|
||||
* When the UNION has been introduced, it has been decided to:
|
||||
* - declare a hierarchy of search classes, with two leafs :
|
||||
* - one class to cope with a single query (A JOIN B... WHERE...)
|
||||
* - and the other to cope with several queries (query1 UNION query2)
|
||||
* - in order to preserve forward/backward compatibility of the existing modules
|
||||
* - keep the name of DBObjectSearch even if it a little bit confusing
|
||||
* - do not provide a type-hint for function parameters defined in the modules
|
||||
* - leave the statements DBObjectSearch::FromOQL in the modules, though DBSearch is more relevant
|
||||
* When the UNION has been introduced, it has been decided to:
|
||||
* * declare a hierarchy of search classes : `DBObjectSearch` & `DBUnionSearch`
|
||||
* * DBObjectSearch cope with single query (A JOIN B... WHERE...)
|
||||
* * DBUnionSearch cope with several queries (query1 UNION query2)
|
||||
* * in order to preserve forward/backward compatibility of the existing modules
|
||||
* * keep the name of DBObjectSearch even if it a little bit confusing
|
||||
* * do not provide a type-hint for function parameters defined in the modules
|
||||
* * leave the statements DBObjectSearch::FromOQL in the modules, though DBSearch is more relevant
|
||||
*
|
||||
* @copyright Copyright (C) 2015-2017 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*
|
||||
*
|
||||
* @package iTopORM
|
||||
* @api
|
||||
* @see DBObjectSearch::__construct()
|
||||
* @see DBUnionSearch::__construct()
|
||||
*/
|
||||
|
||||
abstract class DBSearch
|
||||
{
|
||||
/** @internal */
|
||||
const JOIN_POINTING_TO = 0;
|
||||
/** @internal */
|
||||
const JOIN_REFERENCED_BY = 1;
|
||||
|
||||
protected $m_bNoContextParameters = false;
|
||||
@@ -47,14 +58,23 @@ abstract class DBSearch
|
||||
protected $m_bArchiveMode = false;
|
||||
protected $m_bShowObsoleteData = true;
|
||||
|
||||
/**
|
||||
* DBSearch constructor.
|
||||
*
|
||||
* @api
|
||||
* @see DBSearch::FromOQL()
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->Init();
|
||||
}
|
||||
|
||||
/**
|
||||
* called by the constructor
|
||||
* @internal Set the obsolete and archive modes to the default ones
|
||||
*/
|
||||
protected function Init()
|
||||
{
|
||||
// Set the obsolete and archive modes to the default ones
|
||||
$this->m_bArchiveMode = utils::IsArchiveMode();
|
||||
$this->m_bShowObsoleteData = true;
|
||||
}
|
||||
@@ -62,6 +82,8 @@ abstract class DBSearch
|
||||
/**
|
||||
* Perform a deep clone (as opposed to "clone" which does copy a reference to the underlying objects)
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @return \DBSearch
|
||||
**/
|
||||
public function DeepClone()
|
||||
@@ -69,22 +91,62 @@ abstract class DBSearch
|
||||
return unserialize(serialize($this)); // Beware this serializes/unserializes the search and its parameters as well
|
||||
}
|
||||
|
||||
/**
|
||||
* whether or not some information should be hidden to the current user.
|
||||
*
|
||||
* @api
|
||||
* @see IsAllDataAllowed()
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function AllowAllData();
|
||||
|
||||
/**
|
||||
* Current state of AllowAllData
|
||||
*
|
||||
* @internal
|
||||
* @see AllowAllData()
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function IsAllDataAllowed();
|
||||
|
||||
/**
|
||||
* Should the archives be fetched
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @param $bEnable
|
||||
*/
|
||||
public function SetArchiveMode($bEnable)
|
||||
{
|
||||
$this->m_bArchiveMode = $bEnable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @return bool
|
||||
*/
|
||||
public function GetArchiveMode()
|
||||
{
|
||||
return $this->m_bArchiveMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should the obsolete data be fetched
|
||||
*
|
||||
* @internal
|
||||
* @param $bShow
|
||||
*/
|
||||
public function SetShowObsoleteData($bShow)
|
||||
{
|
||||
$this->m_bShowObsoleteData = $bShow;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @return bool
|
||||
*/
|
||||
public function GetShowObsoleteData()
|
||||
{
|
||||
if ($this->m_bArchiveMode || $this->IsAllDataAllowed())
|
||||
@@ -99,14 +161,36 @@ abstract class DBSearch
|
||||
return $bRet;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function NoContextParameters() {$this->m_bNoContextParameters = true;}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @return bool
|
||||
*/
|
||||
public function HasContextParameters() {return $this->m_bNoContextParameters;}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @param $sPluginClass
|
||||
* @param $sProperty
|
||||
* @param $value
|
||||
*/
|
||||
public function SetModifierProperty($sPluginClass, $sProperty, $value)
|
||||
{
|
||||
$this->m_aModifierProperties[$sPluginClass][$sProperty] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @param $sPluginClass
|
||||
*
|
||||
* @return array|mixed
|
||||
*/
|
||||
public function GetModifierProperties($sPluginClass)
|
||||
{
|
||||
if (array_key_exists($sPluginClass, $this->m_aModifierProperties))
|
||||
@@ -119,18 +203,44 @@ abstract class DBSearch
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @param $sAlias
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function GetClassName($sAlias);
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function GetClass();
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function GetClassAlias();
|
||||
|
||||
/**
|
||||
* Change the class (only subclasses are supported as of now, because the conditions must fit the new class)
|
||||
* Defaults to the first selected class (most of the time it is also the first joined class
|
||||
*/
|
||||
* Change the class
|
||||
*
|
||||
* Defaults to the first selected class (most of the time it is also the first joined class
|
||||
* only subclasses are supported as of now, because the conditions must fit the new class
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
abstract public function ChangeClass($sNewClass, $sAlias = null);
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function GetSelectedClasses();
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @param array $aSelectedClasses array of aliases
|
||||
* @throws CoreException
|
||||
*/
|
||||
@@ -139,64 +249,207 @@ abstract class DBSearch
|
||||
/**
|
||||
* Change any alias of the query tree
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @param $sOldName
|
||||
* @param $sNewName
|
||||
* @return bool True if the alias has been found and changed
|
||||
*/
|
||||
abstract public function RenameAlias($sOldName, $sNewName);
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function IsAny();
|
||||
|
||||
/**
|
||||
* @deprecated use ToOQL() instead
|
||||
* @internal
|
||||
* @return string
|
||||
*/
|
||||
public function Describe(){return 'deprecated - use ToOQL() instead';}
|
||||
/**
|
||||
* @deprecated use ToOQL() instead
|
||||
* @internal
|
||||
* @return string
|
||||
*/
|
||||
public function DescribeConditionPointTo($sExtKeyAttCode, $aPointingTo){return 'deprecated - use ToOQL() instead';}
|
||||
/**
|
||||
* @deprecated use ToOQL() instead
|
||||
* @internal
|
||||
* @return string
|
||||
*/
|
||||
public function DescribeConditionRefBy($sForeignClass, $sForeignExtKeyAttCode){return 'deprecated - use ToOQL() instead';}
|
||||
/**
|
||||
* @deprecated use ToOQL() instead
|
||||
* @internal
|
||||
* @return string
|
||||
*/
|
||||
public function DescribeConditionRelTo($aRelInfo){return 'deprecated - use ToOQL() instead';}
|
||||
/**
|
||||
* @deprecated use ToOQL() instead
|
||||
* @internal
|
||||
* @return string
|
||||
*/
|
||||
public function DescribeConditions(){return 'deprecated - use ToOQL() instead';}
|
||||
/**
|
||||
* @deprecated use ToOQL() instead
|
||||
* @internal
|
||||
* @return string
|
||||
*/
|
||||
public function __DescribeHTML(){return 'deprecated - use ToOQL() instead';}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function ResetCondition();
|
||||
|
||||
/**
|
||||
* add $oExpression as a OR
|
||||
*
|
||||
* @api
|
||||
* @see DBSearch::AddConditionExpression()
|
||||
*
|
||||
* @param Expression $oExpression
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function MergeConditionExpression($oExpression);
|
||||
|
||||
/**
|
||||
* add $oExpression as a AND
|
||||
*
|
||||
* @api
|
||||
* @see DBSearch::MergeConditionExpression()
|
||||
*
|
||||
* @param Expression $oExpression
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function AddConditionExpression($oExpression);
|
||||
|
||||
/**
|
||||
* Condition on the friendlyname
|
||||
*
|
||||
* Restrict the query to only the corresponding selected class' friendlyname
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @param string $sName the desired friendlyname
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function AddNameCondition($sName);
|
||||
|
||||
/**
|
||||
* Add a condition
|
||||
*
|
||||
* This is the simplest way to express a AND condition. For complex use cases, use MergeConditionExpression or AddConditionExpression instead
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @param string $sFilterCode
|
||||
* @param mixed $value
|
||||
* @param string $sOpCode operator to use : '=' (default), '!=', 'IN', 'NOT IN'
|
||||
*
|
||||
* @throws \CoreException
|
||||
*
|
||||
*/
|
||||
abstract public function AddCondition($sFilterCode, $value, $sOpCode = null);
|
||||
/**
|
||||
* Specify a condition on external keys or link sets
|
||||
* @param sAttSpec Can be either an attribute code or extkey->[sAttSpec] or linkset->[sAttSpec] and so on, recursively
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @param string $sAttSpec Can be either an attribute code or extkey->[sAttSpec] or linkset->[sAttSpec] and so on, recursively
|
||||
* Example: infra_list->ci_id->location_id->country
|
||||
* @param value The value to match (can be an array => IN(val1, val2...)
|
||||
* @param mixed $value The value to match (can be an array => IN(val1, val2...)
|
||||
* @return void
|
||||
*/
|
||||
abstract public function AddConditionAdvanced($sAttSpec, $value);
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @param string $sFullText
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function AddCondition_FullText($sFullText);
|
||||
|
||||
/**
|
||||
* Perform a join, the remote class being matched by the mean of its primary key
|
||||
*
|
||||
* The join is performed
|
||||
* * from the searched class, based on the $sExtKeyAttCode attribute
|
||||
* * against the oFilter searched class, based on its primary key
|
||||
* Note : if several classes have already being joined (SELECT a join b ON...), the first joined class (a in the example) is considered as being the searched class.
|
||||
*
|
||||
* @api
|
||||
* @see AddCondition_ReferencedBy()
|
||||
*
|
||||
* @param DBObjectSearch $oFilter
|
||||
* @param $sExtKeyAttCode
|
||||
* @param int $iOperatorCode
|
||||
* @param null $aRealiasingMap array of <old-alias> => <new-alias>, for each alias that has changed
|
||||
* @param string $sExtKeyAttCode
|
||||
* @param int $iOperatorCode the comparison operator to use. For the list of all possible values, see the constant defined in core/oql/oqlquery.class.inc.php
|
||||
* @param array|null $aRealiasingMap array of <old-alias> => <new-alias>, for each alias that has changed in the newly attached oFilter (in case of collisions between the two filters)
|
||||
*
|
||||
* @throws CoreException
|
||||
* @throws CoreWarning
|
||||
*/
|
||||
abstract public function AddCondition_PointingTo(DBObjectSearch $oFilter, $sExtKeyAttCode, $iOperatorCode = TREE_OPERATOR_EQUALS, &$aRealiasingMap = null);
|
||||
|
||||
/**
|
||||
* Inverse operation of AddCondition_PointingTo
|
||||
*
|
||||
* The join is performed
|
||||
* * from the olFilter searched class, based on the $sExtKeyAttCode attribute
|
||||
* * against the searched class, based on its primary key
|
||||
* Note : if several classes have already being joined (SELECT a join b ON...), the first joined class (a in the example) is considered as being the searched class.
|
||||
*
|
||||
*
|
||||
* @api
|
||||
* @see AddCondition_PointingTo()
|
||||
*
|
||||
* @param DBObjectSearch $oFilter
|
||||
* @param $sForeignExtKeyAttCode
|
||||
* @param int $iOperatorCode
|
||||
* @param null $aRealiasingMap array of <old-alias> => <new-alias>, for each alias that has changed
|
||||
* @param array|null $aRealiasingMap array of <old-alias> => <new-alias>, for each alias that has changed in the newly attached oFilter (in case of collisions between the two filters)
|
||||
*/
|
||||
abstract public function AddCondition_ReferencedBy(DBObjectSearch $oFilter, $sForeignExtKeyAttCode, $iOperatorCode = TREE_OPERATOR_EQUALS, &$aRealiasingMap = null);
|
||||
|
||||
/**
|
||||
* Filter the result
|
||||
*
|
||||
* The filter is performed by returning only the values in common with the given $oFilter
|
||||
* The impact on the resulting query performance/viability can be significant.
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @param DBSearch $oFilter
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function Intersect(DBSearch $oFilter);
|
||||
|
||||
/**
|
||||
* @param DBSearch $oFilter
|
||||
* @param integer $iDirection
|
||||
* @param string $sExtKeyAttCode
|
||||
* @param integer $iOperatorCode
|
||||
* @param array &$RealisasingMap Map of aliases from the attached query, that could have been renamed by the optimization process
|
||||
* @return DBSearch
|
||||
*/
|
||||
/**
|
||||
* Perform a join
|
||||
*
|
||||
* The join is performed against $oFilter selected class using $sExtKeyAttCode of the current selected class
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @param DBSearch $oFilter The join is performed against $oFilter selected class
|
||||
* @param integer $iDirection can be either DBSearch::JOIN_POINTING_TO or DBSearch::JOIN_REFERENCED_BY
|
||||
* @param string $sExtKeyAttCode The join is performed against $sExtKeyAttCode wetheir it is compared aginst the current DBSearch or $oFilter depend of $iDirection
|
||||
* @param integer $iOperatorCode See DBSearch::AddCondition_PointingTo()
|
||||
* @param array|null $aRealiasingMap Map of aliases from the attached query, that could have been renamed by the optimization process
|
||||
*
|
||||
* @return DBSearch
|
||||
* @throws CoreException
|
||||
* @throws CoreWarning
|
||||
*/
|
||||
public function Join(DBSearch $oFilter, $iDirection, $sExtKeyAttCode, $iOperatorCode = TREE_OPERATOR_EQUALS, &$aRealiasingMap = null)
|
||||
{
|
||||
$oSourceFilter = $this->DeepClone();
|
||||
@@ -231,33 +484,151 @@ abstract class DBSearch
|
||||
return $oRet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the internal params.
|
||||
*
|
||||
* If any params pre-existed, they are lost.
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @param mixed[string] $aParams array of mixed params index by string name
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function SetInternalParams($aParams);
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function GetInternalParams();
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @param bool $bExcludeMagicParams
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function GetQueryParams($bExcludeMagicParams = true);
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function ListConstantFields();
|
||||
|
||||
|
||||
/**
|
||||
* Turn the parameters (:xxx) into scalar values in order to easily
|
||||
* serialize a search
|
||||
* Turn the parameters (:xxx) into scalar values
|
||||
*
|
||||
* The goal is to easily serialize a search
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @param array $aArgs
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract public function ApplyParameters($aArgs);
|
||||
|
||||
public function serialize($bDevelopParams = false, $aContextParams = null)
|
||||
/**
|
||||
* Convert a query to a string representation
|
||||
*
|
||||
* This operation can be revert back to a DBSearch using DBSearch::unserialize()
|
||||
*
|
||||
* @api
|
||||
* @see DBSearch::unserialize()
|
||||
*
|
||||
* @param bool $bDevelopParams
|
||||
* @param array $aContextParams
|
||||
*
|
||||
* @return false|string
|
||||
* @throws ArchivedObjectException
|
||||
* @throws CoreException
|
||||
*/
|
||||
public function serialize($bDevelopParams = false, $aContextParams = array())
|
||||
{
|
||||
$aQueryParams = $this->GetQueryParams();
|
||||
|
||||
$aContextParams = array_merge($this->GetInternalParams(), $aContextParams);
|
||||
|
||||
foreach($aQueryParams as $sParam => $sValue)
|
||||
{
|
||||
if (isset($aContextParams[$sParam]))
|
||||
{
|
||||
$aQueryParams[$sParam] = $aContextParams[$sParam];
|
||||
}
|
||||
elseif (($iPos = strpos($sParam, '->')) !== false)
|
||||
{
|
||||
$sParamName = substr($sParam, 0, $iPos);
|
||||
if (isset($aContextParams[$sParamName.'->object()']))
|
||||
{
|
||||
$sAttCode = substr($sParam, $iPos + 2);
|
||||
/** @var \DBObject $oObj */
|
||||
$oObj = $aContextParams[$sParamName.'->object()'];
|
||||
if ($oObj->IsModified())
|
||||
{
|
||||
if ($sAttCode == 'id')
|
||||
{
|
||||
$aQueryParams[$sParam] = $oObj->GetKey();
|
||||
}
|
||||
else
|
||||
{
|
||||
$aQueryParams[$sParam] = $oObj->Get($sAttCode);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
unset($aQueryParams[$sParam]);
|
||||
// For database objects, serialize only class, key
|
||||
$aQueryParams[$sParamName.'->id'] = $oObj->GetKey();
|
||||
$aQueryParams[$sParamName.'->class'] = get_class($oObj);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$sOql = $this->ToOql($bDevelopParams, $aContextParams);
|
||||
return rawurlencode(base64_encode(serialize(array($sOql, $this->GetInternalParams(), $this->m_aModifierProperties))));
|
||||
return json_encode(array($sOql, $aQueryParams, $this->m_aModifierProperties));
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a serialized query back to an instance of DBSearch
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @param string $sValue Serialized OQL query
|
||||
*
|
||||
* @return \DBSearch
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
static public function unserialize($sValue)
|
||||
{
|
||||
$aData = unserialize(base64_decode(rawurldecode($sValue)));
|
||||
$aData = json_decode($sValue, true);
|
||||
if (is_null($aData))
|
||||
{
|
||||
throw new CoreException("Invalid filter parameter");
|
||||
}
|
||||
$sOql = $aData[0];
|
||||
$aParams = $aData[1];
|
||||
$aExtraParams = array();
|
||||
foreach($aParams as $sParam => $sValue)
|
||||
{
|
||||
if (($iPos = strpos($sParam, '->class')) !== false)
|
||||
{
|
||||
$sParamName = substr($sParam, 0, $iPos);
|
||||
if (isset($aParams[$sParamName.'->id']))
|
||||
{
|
||||
$sClass = $aParams[$sParamName.'->class'];
|
||||
$iKey = $aParams[$sParamName.'->id'];
|
||||
$oObj = MetaModel::GetObject($sClass, $iKey);
|
||||
$aExtraParams[$sParamName.'->object()'] = $oObj;
|
||||
}
|
||||
}
|
||||
}
|
||||
$aParams = array_merge($aExtraParams, $aParams);
|
||||
// We've tried to use gzcompress/gzuncompress, but for some specific queries
|
||||
// it was not working at all (See Trac #193)
|
||||
// gzuncompress was issuing a warning "data error" and the return object was null
|
||||
@@ -269,11 +640,13 @@ abstract class DBSearch
|
||||
/**
|
||||
* Create a new DBObjectSearch from $oSearch with a new alias $sAlias
|
||||
*
|
||||
* Note : This has not be tested with UNION queries.
|
||||
* @internal Note : This has not be tested with UNION queries.
|
||||
*
|
||||
* @param DBSearch $oSearch
|
||||
* @param string $sAlias
|
||||
* @param string $sAlias
|
||||
*
|
||||
* @return DBObjectSearch
|
||||
* @throws CoreException
|
||||
*/
|
||||
static public function CloneWithAlias(DBSearch $oSearch, $sAlias)
|
||||
{
|
||||
@@ -282,12 +655,37 @@ abstract class DBSearch
|
||||
return $oSearchWithAlias;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the DBSearch to an OQL representation
|
||||
*
|
||||
* @api
|
||||
* @see DBSearch::FromOQL()
|
||||
*
|
||||
* @param bool $bDevelopParams
|
||||
* @param null $aContextParams
|
||||
* @param bool $bWithAllowAllFlag
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function ToOQL($bDevelopParams = false, $aContextParams = null, $bWithAllowAllFlag = false);
|
||||
|
||||
static protected $m_aOQLQueries = array();
|
||||
|
||||
// Do not filter out depending on user rights
|
||||
// In particular when we are currently in the process of evaluating the user rights...
|
||||
/**
|
||||
* FromOQL with AllowAllData enabled
|
||||
*
|
||||
* The goal is to not filter out depending on user rights.
|
||||
* In particular when we are currently in the process of evaluating the user rights...
|
||||
*
|
||||
* @internal
|
||||
* @see DBSearch::FromOQL()
|
||||
*
|
||||
* @param string $sQuery
|
||||
* @param null $aParams
|
||||
*
|
||||
* @return DBSearch
|
||||
* @throws OQLException
|
||||
*/
|
||||
static public function FromOQL_AllData($sQuery, $aParams = null)
|
||||
{
|
||||
$oRes = self::FromOQL($sQuery, $aParams);
|
||||
@@ -296,9 +694,19 @@ abstract class DBSearch
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sQuery
|
||||
* @param array $aParams
|
||||
* @return self
|
||||
* Create a new DBSearch from the given OQL.
|
||||
*
|
||||
* This is the simplest way to create a DBSearch.
|
||||
* For almost every cases, this is the easiest way.
|
||||
*
|
||||
* @api
|
||||
* @see DBSearch::ToOQL()
|
||||
*
|
||||
* @param string $sQuery The OQL to convert to a DBSearch
|
||||
* @param mixed[string] $aParams array of <mixed> params index by <string> name
|
||||
*
|
||||
* @return DBObjectSearch|DBUnionSearch
|
||||
*
|
||||
* @throws OQLException
|
||||
*/
|
||||
static public function FromOQL($sQuery, $aParams = null)
|
||||
@@ -335,6 +743,7 @@ abstract class DBSearch
|
||||
}
|
||||
}
|
||||
|
||||
/** @var DBObjectSearch | null $oResultFilter */
|
||||
if (!isset($oResultFilter))
|
||||
{
|
||||
$oKPI = new ExecutionKPI();
|
||||
@@ -373,11 +782,26 @@ abstract class DBSearch
|
||||
return $oResultFilter;
|
||||
}
|
||||
|
||||
// Alternative to object mapping: the data are transfered directly into an array
|
||||
// This is 10 times faster than creating a set of objects, and makes sense when optimization is required
|
||||
/**
|
||||
* @param hash $aOrderBy Array of '[<classalias>.]attcode' => bAscending
|
||||
*/
|
||||
* Fetch the result has an array structure.
|
||||
*
|
||||
* Alternative to object mapping: the data are transfered directly into an array
|
||||
* This is 10 times faster than creating a set of objects, and makes sense when optimization is required
|
||||
* But this speed comes at the cost of not obtaining the easy to manipulates DBObject instances but simple array structure.
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @param array $aColumns The columns you'd like to fetch.
|
||||
* @param array $aOrderBy Array of '[<classalias>.]attcode' => bAscending
|
||||
* @param array $aArgs
|
||||
*
|
||||
* @return array|void
|
||||
*
|
||||
* @throws \CoreException
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
*/
|
||||
public function ToDataArray($aColumns = array(), $aOrderBy = array(), $aArgs = array())
|
||||
{
|
||||
$sSQL = $this->MakeSelectQuery($aOrderBy, $aArgs);
|
||||
@@ -429,7 +853,11 @@ abstract class DBSearch
|
||||
protected static $m_aQueryStructCache = array();
|
||||
|
||||
|
||||
/** Generate a Group By SQL request from a search
|
||||
/**
|
||||
* Generate a Group By SQL query from the current search
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @param array $aArgs
|
||||
* @param array $aGroupByExpr array('alias' => Expression)
|
||||
* @param bool $bExcludeNullValues
|
||||
@@ -437,7 +865,9 @@ abstract class DBSearch
|
||||
* @param array $aOrderBy array('alias' => bool) true = ASC false = DESC
|
||||
* @param int $iLimitCount
|
||||
* @param int $iLimitStart
|
||||
*
|
||||
* @return string SQL query generated
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function MakeGroupByQuery($aArgs, $aGroupByExpr, $bExcludeNullValues = false, $aSelectExpr = array(), $aOrderBy = array(), $iLimitCount = 0, $iLimitStart = 0)
|
||||
@@ -513,6 +943,10 @@ abstract class DBSearch
|
||||
|
||||
|
||||
/**
|
||||
* Generate a SQL query from the current search
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @param array|hash $aOrderBy Array of '[<classalias>.]attcode' => bAscending
|
||||
* @param array $aArgs
|
||||
* @param null $aAttToLoad
|
||||
@@ -607,9 +1041,33 @@ abstract class DBSearch
|
||||
return $sRes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @return mixed
|
||||
*/
|
||||
protected abstract function IsDataFiltered();
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @return mixed
|
||||
*/
|
||||
protected abstract function SetDataFiltered();
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @param $aOrderBy
|
||||
* @param $aArgs
|
||||
* @param $aAttToLoad
|
||||
* @param $aExtendedDataSpec
|
||||
* @param $iLimitCount
|
||||
* @param $iLimitStart
|
||||
* @param $bGetCount
|
||||
* @param null $aGroupByExpr
|
||||
* @param null $aSelectExpr
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function GetSQLQuery($aOrderBy, $aArgs, $aAttToLoad, $aExtendedDataSpec, $iLimitCount, $iLimitStart, $bGetCount, $aGroupByExpr = null, $aSelectExpr = null)
|
||||
{
|
||||
$oSearch = $this;
|
||||
@@ -650,18 +1108,46 @@ abstract class DBSearch
|
||||
return $oSQLQuery;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @param $aAttToLoad
|
||||
* @param $bGetCount
|
||||
* @param null $aGroupByExpr
|
||||
* @param null $aSelectedClasses
|
||||
* @param null $aSelectExpr
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public abstract function GetSQLQueryStructure(
|
||||
$aAttToLoad, $bGetCount, $aGroupByExpr = null, $aSelectedClasses = null, $aSelectExpr = null
|
||||
);
|
||||
|
||||
/**
|
||||
* Get the current search conditions
|
||||
*
|
||||
* @internal
|
||||
* @see DBSearch $m_oSearchCondition
|
||||
*
|
||||
* @return \Expression
|
||||
*/
|
||||
public abstract function GetCriteria();
|
||||
|
||||
/**
|
||||
* Shortcut to add efficient IN condition
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @param $sFilterCode
|
||||
* @param $aValues
|
||||
* @param bool $bPositiveMatch if true a `IN` is performed, if false, a `NOT IN` is performed
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public abstract function AddConditionForInOperatorUsingParam($sFilterCode, $aValues, $bPositiveMatch = true);
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @return string a unique param name
|
||||
*/
|
||||
protected function GenerateUniqueParamName() {
|
||||
@@ -682,36 +1168,78 @@ abstract class DBSearch
|
||||
protected static $m_bIndentQueries = false;
|
||||
protected static $m_bOptimizeQueries = false;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public static function StartDebugQuery()
|
||||
{
|
||||
$aBacktrace = debug_backtrace();
|
||||
self::$m_bDebugQuery = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public static function StopDebugQuery()
|
||||
{
|
||||
self::$m_bDebugQuery = false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @param bool $bEnabled
|
||||
* @param bool $bUseAPC
|
||||
* @param int $iTimeToLive
|
||||
*/
|
||||
public static function EnableQueryCache($bEnabled, $bUseAPC, $iTimeToLive = 3600)
|
||||
{
|
||||
self::$m_bQueryCacheEnabled = $bEnabled;
|
||||
self::$m_bUseAPCCache = $bUseAPC;
|
||||
self::$m_iQueryCacheTTL = $iTimeToLive;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @param $bEnabled
|
||||
*/
|
||||
public static function EnableQueryTrace($bEnabled)
|
||||
{
|
||||
self::$m_bTraceQueries = $bEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @param $bEnabled
|
||||
*/
|
||||
public static function EnableQueryIndentation($bEnabled)
|
||||
{
|
||||
self::$m_bIndentQueries = $bEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @param $bEnabled
|
||||
*/
|
||||
public static function EnableOptimizeQuery($bEnabled)
|
||||
{
|
||||
self::$m_bOptimizeQueries = $bEnabled;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @param $aOrderBy
|
||||
* @param $aArgs
|
||||
* @param $aAttToLoad
|
||||
* @param $aExtendedDataSpec
|
||||
* @param $iLimitCount
|
||||
* @param $iLimitStart
|
||||
* @param $bGetCount
|
||||
* @param $sSql
|
||||
*
|
||||
* @throws MySQLException
|
||||
*/
|
||||
protected function AddQueryTraceSelect($aOrderBy, $aArgs, $aAttToLoad, $aExtendedDataSpec, $iLimitCount, $iLimitStart, $bGetCount, $sSql)
|
||||
{
|
||||
if (self::$m_bTraceQueries)
|
||||
@@ -731,7 +1259,16 @@ abstract class DBSearch
|
||||
self::AddQueryTrace($aQueryData, $sOql, $sSql);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @param $aArgs
|
||||
* @param $aGroupByExpr
|
||||
* @param $sSql
|
||||
*
|
||||
* @throws MySQLException
|
||||
*/
|
||||
protected function AddQueryTraceGroupBy($aArgs, $aGroupByExpr, $sSql)
|
||||
{
|
||||
if (self::$m_bTraceQueries)
|
||||
@@ -747,6 +1284,15 @@ abstract class DBSearch
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @param $aQueryData
|
||||
* @param $sOql
|
||||
* @param $sSql
|
||||
*
|
||||
* @throws MySQLException
|
||||
*/
|
||||
protected static function AddQueryTrace($aQueryData, $sOql, $sSql)
|
||||
{
|
||||
if (self::$m_bTraceQueries)
|
||||
@@ -777,6 +1323,9 @@ abstract class DBSearch
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public static function RecordQueryTrace()
|
||||
{
|
||||
if (!self::$m_bTraceQueries)
|
||||
@@ -837,6 +1386,10 @@ abstract class DBSearch
|
||||
file_put_contents($sAllQueries, $sLog);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @param $value
|
||||
*/
|
||||
protected static function DbgTrace($value)
|
||||
{
|
||||
if (!self::$m_bDebugQuery)
|
||||
@@ -872,7 +1425,9 @@ abstract class DBSearch
|
||||
|
||||
/**
|
||||
* Experimental!
|
||||
* todo: implement the change tracking
|
||||
* @todo implement the change tracking
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @param $bArchive
|
||||
* @throws Exception
|
||||
@@ -948,6 +1503,9 @@ abstract class DBSearch
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function UpdateContextFromUser()
|
||||
{
|
||||
$this->SetShowObsoleteData(utils::ShowObsoleteData());
|
||||
|
||||
@@ -18,10 +18,21 @@
|
||||
|
||||
|
||||
/**
|
||||
* A union of DBObjectSearches
|
||||
* A union of DBObjectSearches
|
||||
*
|
||||
* This search class represent an union over a collection of DBObjectSearch.
|
||||
* For clarity purpose, since only the constructor vary between DBObjectSearch and DBUnionSearch, all the API is documented on the common ancestor: DBSearch
|
||||
* Please refer to DBSearch's documentation
|
||||
*
|
||||
* @copyright Copyright (C) 2015-2017 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*
|
||||
*
|
||||
* @package iTopORM
|
||||
* @phpdoc-tuning-exclude-inherited this tag prevent PHPdoc from displaying inherited methods. This is done in order to force the API doc. location into DBSearch only.
|
||||
* @api
|
||||
* @see DBSearch
|
||||
* @see DBObjectSearch
|
||||
*/
|
||||
|
||||
class DBUnionSearch extends DBSearch
|
||||
@@ -29,6 +40,15 @@ class DBUnionSearch extends DBSearch
|
||||
protected $aSearches; // source queries
|
||||
protected $aSelectedClasses; // alias => classes (lowest common ancestors) computed at construction
|
||||
|
||||
/**
|
||||
* DBUnionSearch constructor.
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @param $aSearches
|
||||
*
|
||||
* @throws CoreException
|
||||
*/
|
||||
public function __construct($aSearches)
|
||||
{
|
||||
if (count ($aSearches) == 0)
|
||||
|
||||
@@ -116,6 +116,22 @@ class Dict
|
||||
self::$m_iErrorMode = $iErrorMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a dictionary entry exists or not
|
||||
* @param $sStringCode
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function Exists($sStringCode)
|
||||
{
|
||||
$sImpossibleString = 'aVlHYKEI3TZuDV5o0pghv7fvhYNYuzYkTk7WL0Zoqw8rggE7aq';
|
||||
if (static::S($sStringCode, $sImpossibleString) === $sImpossibleString)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a localised string from the dictonary
|
||||
*
|
||||
@@ -197,7 +213,7 @@ class Dict
|
||||
/**
|
||||
* Initialize a the entries for a given language (replaces the former Add() method)
|
||||
* @param string $sLanguageCode Code identifying the language i.e. 'FR-FR', 'EN-US'
|
||||
* @param hash $aEntries Hash array of dictionnary entries
|
||||
* @param array $aEntries Hash array of dictionnary entries
|
||||
*/
|
||||
public static function SetEntries($sLanguageCode, $aEntries)
|
||||
{
|
||||
|
||||
@@ -188,11 +188,16 @@ EOF
|
||||
$oAttDef = MetaModel::GetAttributeDef(get_class($oObj), $sAttCode);
|
||||
$sRet = $oAttDef->GetAsCSV($value, '', '', $oObj);
|
||||
}
|
||||
else if ($value instanceOf ormDocument)
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef(get_class($oObj), $sAttCode);
|
||||
$sRet = $oAttDef->GetAsCSV($value, '', '', $oObj);
|
||||
}
|
||||
else if ($value instanceOf ormDocument)
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef(get_class($oObj), $sAttCode);
|
||||
$sRet = $oAttDef->GetAsCSV($value, '', '', $oObj);
|
||||
}
|
||||
else if ($value instanceOf ormTagSet)
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef(get_class($oObj), $sAttCode);
|
||||
$sRet = $oAttDef->GetAsCSV($value, '', '', $oObj);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef(get_class($oObj), $sAttCode);
|
||||
|
||||
@@ -154,7 +154,7 @@ class HTMLDOMSanitizer extends HTMLSanitizer
|
||||
|
||||
/**
|
||||
* @var array
|
||||
* @see https://www.itophub.io/wiki/page?id=2_5_0%3Aadmin%3Arich_text_limitations
|
||||
* @see https://www.itophub.io/wiki/page?id=2_6_0%3Aadmin%3Arich_text_limitations
|
||||
*/
|
||||
protected static $aTagsWhiteList = array(
|
||||
'html' => array(),
|
||||
@@ -211,7 +211,7 @@ class HTMLDOMSanitizer extends HTMLSanitizer
|
||||
|
||||
/**
|
||||
* @var array
|
||||
* @see https://www.itophub.io/wiki/page?id=2_5_0%3Aadmin%3Arich_text_limitations
|
||||
* @see https://www.itophub.io/wiki/page?id=2_6_0%3Aadmin%3Arich_text_limitations
|
||||
*/
|
||||
protected static $aStylesWhiteList = array(
|
||||
'background-color',
|
||||
@@ -230,7 +230,9 @@ class HTMLDOMSanitizer extends HTMLSanitizer
|
||||
'margin',
|
||||
'padding',
|
||||
'text-align',
|
||||
'vertical-align',
|
||||
'width',
|
||||
'white-space',
|
||||
);
|
||||
|
||||
public function __construct()
|
||||
@@ -241,10 +243,16 @@ class HTMLDOMSanitizer extends HTMLSanitizer
|
||||
{
|
||||
// Regular urls
|
||||
$sUrlPattern = utils::GetConfig()->Get('url_validation_pattern');
|
||||
|
||||
// Mailto urls
|
||||
$sMailtoPattern = '(mailto:(' . utils::GetConfig()->Get('email_validation_pattern') . ')(?:\?(?:subject|body)=([a-zA-Z0-9+\$_.-]*)(?:&(?:subject|body)=([a-zA-Z0-9+\$_.-]*))?)?)';
|
||||
|
||||
$sPattern = $sUrlPattern . '|' . $sMailtoPattern;
|
||||
// Notification placeholders
|
||||
// eg. $this->caller_id$, $this->hyperlink()$, $this->hyperlink(portal)$, $APP_URL$, $MODULES_URL$, ...
|
||||
// Note: Authorize both $xxx$ and %24xxx%24 as the latter one is encoded when used in HTML attributes (eg. a[href])
|
||||
$sPlaceholderPattern = '(\$|%24)[\w-]*(->[\w]*(\([\w-]*?\))?)?(\$|%24)';
|
||||
|
||||
$sPattern = $sUrlPattern . '|' . $sMailtoPattern . '|' . $sPlaceholderPattern;
|
||||
$sPattern = '/'.str_replace('/', '\/', $sPattern).'/i';
|
||||
self::$aAttrsWhiteList['href'] = $sPattern;
|
||||
}
|
||||
@@ -259,7 +267,7 @@ class HTMLDOMSanitizer extends HTMLSanitizer
|
||||
// We have to transform that into <p><br></p> (which is how Thunderbird implements empty lines)
|
||||
// Unfortunately, DOMDocument::loadHTML does not take the tag namespaces into account (once loaded there is no way to know if the tag did have a namespace)
|
||||
// therefore we have to do the transformation upfront
|
||||
$sHTML = preg_replace('@<o:p>\s*</o:p>@', '<br>', $sHTML);
|
||||
$sHTML = preg_replace('@<o:p>(\s| )*</o:p>@', '<br>', $sHTML);
|
||||
|
||||
@$this->oDoc->loadHTML('<?xml encoding="UTF-8"?>'.$sHTML); // For loading HTML chunks where the character set is not specified
|
||||
|
||||
|
||||
@@ -166,7 +166,7 @@ class InlineImage extends DBObject
|
||||
*/
|
||||
public static function FinalizeInlineImages(DBObject $oObject)
|
||||
{
|
||||
$iTransactionId = utils::ReadParam('transaction_id', null);
|
||||
$iTransactionId = utils::ReadParam('transaction_id', null, false, 'transaction_id');
|
||||
if (!is_null($iTransactionId))
|
||||
{
|
||||
// Attach new (temporary) inline images
|
||||
@@ -183,6 +183,19 @@ class InlineImage extends DBObject
|
||||
$oInlineImage->DBUpdate();
|
||||
}
|
||||
}
|
||||
// For tracing issues with Inline Images... but beware not all updates are interactive, so this trace happens when creating objects non-interactively (REST, Synchro...)
|
||||
// else
|
||||
// {
|
||||
// IssueLog::Error('InlineImage: Error during FinalizeInlineImages(), no transaction ID for object '.get_class($oObject).'#'.$oObject->GetKey().'.');
|
||||
//
|
||||
// IssueLog::Error('|- Call stack:');
|
||||
// $oException = new Exception();
|
||||
// $sStackTrace = $oException->getTraceAsString();
|
||||
// IssueLog::Error($sStackTrace);
|
||||
//
|
||||
// IssueLog::Error('|- POST vars:');
|
||||
// IssueLog::Error(print_r($_POST, true));
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -299,8 +312,12 @@ EOF
|
||||
|
||||
/**
|
||||
* Check if an the given mimeType is an image that can be processed by the system
|
||||
*
|
||||
* @param string $sMimeType
|
||||
* @return boolean
|
||||
*
|
||||
* @return boolean always false if php-gd not installed
|
||||
* otherwise true if file is one of those type : image/gif, image/jpeg, image/png
|
||||
* @uses php-gd extension
|
||||
*/
|
||||
public static function IsImage($sMimeType)
|
||||
{
|
||||
@@ -446,9 +463,11 @@ EOF
|
||||
* Get the fragment of javascript needed to complete the initialization of
|
||||
* CKEditor when creating/modifying an object
|
||||
*
|
||||
* @param DBObject $oObject The object being edited
|
||||
* @param string $sTempId The concatenation of session_id().'_'.$iTransactionId.
|
||||
* @param \DBObject $oObject The object being edited
|
||||
* @param string $sTempId Generated through utils::GetUploadTempId($iTransactionId)
|
||||
*
|
||||
* @return string The JS fragment to insert in "on document ready"
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function EnableCKEditorImageUpload(DBObject $oObject, $sTempId)
|
||||
{
|
||||
@@ -541,49 +560,67 @@ class InlineImageGC implements iBackgroundProcess
|
||||
{
|
||||
public function GetPeriodicity()
|
||||
{
|
||||
return 3600; // Runs every hour
|
||||
return 1; // Runs every 8 hours
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $iTimeLimit
|
||||
*
|
||||
* @return string
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \DeleteException
|
||||
* @throws \MySQLException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public function Process($iTimeLimit)
|
||||
{
|
||||
$sDateLimit = date(AttributeDateTime::GetSQLFormat(), time()); // Every temporary InlineImage/Attachment expired will be deleted
|
||||
|
||||
$iProcessed = 0;
|
||||
$sOQL = "SELECT InlineImage WHERE (item_id = 0) AND (expire < '$sDateLimit')";
|
||||
while (time() < $iTimeLimit)
|
||||
$aResults = array();
|
||||
$aClasses = array('InlineImage', 'Attachment');
|
||||
foreach($aClasses as $sClass)
|
||||
{
|
||||
// Next one ?
|
||||
$oSet = new CMDBObjectSet(DBObjectSearch::FromOQL($sOQL), array('expire' => true) /* order by*/, array(), null, 1 /* limit count */);
|
||||
$oSet->OptimizeColumnLoad(array());
|
||||
$oResult = $oSet->Fetch();
|
||||
if (is_null($oResult))
|
||||
$iProcessed = 0;
|
||||
if(class_exists($sClass))
|
||||
{
|
||||
// Nothing to be done
|
||||
break;
|
||||
$iProcessed = $this->DeleteExpiredDocuments($sClass, $iTimeLimit, $sDateLimit);
|
||||
}
|
||||
$iProcessed++;
|
||||
$oResult->DBDelete();
|
||||
$aResults[] = "$iProcessed old temporary $sClass(s)";
|
||||
}
|
||||
|
||||
$iProcessed2 = 0;
|
||||
if (class_exists('Attachment'))
|
||||
{
|
||||
$sOQL = "SELECT Attachment WHERE (item_id = 0) AND (expire < '$sDateLimit')";
|
||||
while (time() < $iTimeLimit)
|
||||
{
|
||||
// Next one ?
|
||||
$oSet = new CMDBObjectSet(DBObjectSearch::FromOQL($sOQL), array('expire' => true) /* order by*/, array(), null, 1 /* limit count */);
|
||||
$oSet->OptimizeColumnLoad(array());
|
||||
$oResult = $oSet->Fetch();
|
||||
if (is_null($oResult))
|
||||
{
|
||||
// Nothing to be done
|
||||
break;
|
||||
}
|
||||
$iProcessed2++;
|
||||
$oResult->DBDelete();
|
||||
}
|
||||
}
|
||||
return "Cleaned $iProcessed old temporary InlineImage(s) and $iProcessed2 old temporary Attachment(s).";
|
||||
|
||||
return "Cleaned ".implode(' and ', $aResults).".";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sClass
|
||||
* @param int $iTimeLimit
|
||||
* @param string $sDateLimit
|
||||
*
|
||||
* @return int
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \DeleteException
|
||||
* @throws \MySQLException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
protected function DeleteExpiredDocuments($sClass, $iTimeLimit, $sDateLimit)
|
||||
{
|
||||
$iProcessed = 0;
|
||||
$sOQL = "SELECT $sClass WHERE (item_id = 0) AND (expire < '$sDateLimit')";
|
||||
// Next one ?
|
||||
$oSet = new CMDBObjectSet(DBObjectSearch::FromOQL($sOQL), array('expire' => true) /* order by*/, array(), null,
|
||||
1 /* limit count */);
|
||||
$oSet->OptimizeColumnLoad(array());
|
||||
while ((time() < $iTimeLimit) && ($oResult = $oSet->Fetch()))
|
||||
{
|
||||
/** @var \ormDocument $oDocument */
|
||||
$oDocument = $oResult->Get('contents');
|
||||
IssueLog::Info($sClass.' GC: Removed temp. file '.$oDocument->GetFileName().' on "'.$oResult->Get('item_class').'" #'.$oResult->Get('item_id').' as it has expired.');
|
||||
$oResult->DBDelete();
|
||||
$iProcessed++;
|
||||
}
|
||||
|
||||
return $iProcessed;
|
||||
}
|
||||
}
|
||||
@@ -116,13 +116,14 @@ class ExecutionKPI
|
||||
foreach (self::$m_aExecData as $aOpStats)
|
||||
{
|
||||
$sOperation = $aOpStats['op'];
|
||||
$sBegin = $sEnd = $sDuration = $sMemBegin = $sMemEnd = $sMemPeak = '?';
|
||||
|
||||
$sBegin = round($aOpStats['time_begin'], 3);
|
||||
$sEnd = round($aOpStats['time_end'], 3);
|
||||
$fDuration = $aOpStats['time_end'] - $aOpStats['time_begin'];
|
||||
$sDuration = round($fDuration, 3);
|
||||
|
||||
$sMemBegin = 'n/a';
|
||||
$sMemEnd = 'n/a';
|
||||
$sMemPeak = 'n/a';
|
||||
if (isset($aOpStats['mem_begin']))
|
||||
{
|
||||
$sMemBegin = self::MemStr($aOpStats['mem_begin']);
|
||||
@@ -197,12 +198,13 @@ class ExecutionKPI
|
||||
|
||||
self::Report("</div>");
|
||||
|
||||
self::Report("<p><a href=\"#end-".md5($sExecId)."\">Next page stats</a></p>");
|
||||
|
||||
// Report operation details
|
||||
foreach (self::$m_aStats as $sOperation => $aOpStats)
|
||||
{
|
||||
$sOperationHtml = '<a name="'.md5($sExecId.$sOperation).'">'.$sOperation.'</a>';
|
||||
self::Report("<h4>$sOperationHtml</h4>");
|
||||
self::Report("<p><a href=\"#".md5($sExecId)."\">Back to page stats</a></p>");
|
||||
self::Report("<table border=\"1\" style=\"$sTableStyle\">");
|
||||
self::Report("<thead>");
|
||||
self::Report(" <th>Operation details (+ blame caller if log_kpi_duration = 2)</th><th>Count</th><th>Duration</th><th>Min</th><th>Max</th>");
|
||||
@@ -251,7 +253,9 @@ class ExecutionKPI
|
||||
self::Report("</tr>");
|
||||
}
|
||||
self::Report("</table>");
|
||||
self::Report("<p><a href=\"#".md5($sExecId)."\">Back to page stats</a></p>");
|
||||
}
|
||||
self::Report('<a name="end-'.md5($sExecId).'"> </a>');
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -97,8 +97,9 @@ define('MYSQL_ENGINE', 'innodb');
|
||||
|
||||
|
||||
/**
|
||||
* (API) The objects definitions as well as their mapping to the database
|
||||
* The objects definitions as well as their mapping to the database
|
||||
*
|
||||
* @api
|
||||
* @package iTopORM
|
||||
*/
|
||||
abstract class MetaModel
|
||||
@@ -144,7 +145,7 @@ abstract class MetaModel
|
||||
// $aBacktrace[1] is the info we want
|
||||
if (!empty($sExpectedFunctionName))
|
||||
{
|
||||
assert('$aBacktrace[2]["function"] == $sExpectedFunctionName');
|
||||
assert($aBacktrace[2]['function'] == $sExpectedFunctionName);
|
||||
}
|
||||
if ($bRecordSourceFile)
|
||||
{
|
||||
@@ -320,8 +321,7 @@ abstract class MetaModel
|
||||
final static public function GetName($sClass)
|
||||
{
|
||||
self::_check_subclass($sClass);
|
||||
$sStringCode = 'Class:'.$sClass;
|
||||
return Dict::S($sStringCode, str_replace('_', ' ', $sClass));
|
||||
return $sClass::GetClassName($sClass);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -411,8 +411,7 @@ abstract class MetaModel
|
||||
final static public function GetClassDescription($sClass)
|
||||
{
|
||||
self::_check_subclass($sClass);
|
||||
$sStringCode = 'Class:'.$sClass.'+';
|
||||
return Dict::S($sStringCode, '');
|
||||
return $sClass::GetClassDescription($sClass);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -528,6 +527,170 @@ abstract class MetaModel
|
||||
return $oRet;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sClass
|
||||
* @param bool $bClassDefinitionOnly if true then will only return properties defined in the specified class on not the properties
|
||||
* from its parent classes
|
||||
*
|
||||
* @return array rule id as key, rule properties as value
|
||||
* @throws \CoreException
|
||||
* @since 2.6 N°659 uniqueness constraint
|
||||
* @see #SetUniquenessRuleRootClass that fixes a specific 'root_class' property to know which class is root per rule
|
||||
*/
|
||||
final public static function GetUniquenessRules($sClass, $bClassDefinitionOnly = false)
|
||||
{
|
||||
if (!isset(self::$m_aClassParams[$sClass]))
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
$aCurrentUniquenessRules = array();
|
||||
|
||||
if (array_key_exists('uniqueness_rules', self::$m_aClassParams[$sClass]))
|
||||
{
|
||||
$aCurrentUniquenessRules = self::$m_aClassParams[$sClass]['uniqueness_rules'];
|
||||
}
|
||||
|
||||
if ($bClassDefinitionOnly)
|
||||
{
|
||||
return $aCurrentUniquenessRules;
|
||||
}
|
||||
|
||||
$sParentClass = self::GetParentClass($sClass);
|
||||
if ($sParentClass)
|
||||
{
|
||||
$aParentUniquenessRules = self::GetUniquenessRules($sParentClass);
|
||||
foreach ($aParentUniquenessRules as $sUniquenessRuleId => $aParentUniquenessRuleProperties)
|
||||
{
|
||||
$bCopyDisabledKey = true;
|
||||
$bCurrentDisabledValue = null;
|
||||
|
||||
if (array_key_exists($sUniquenessRuleId, $aCurrentUniquenessRules))
|
||||
{
|
||||
if (self::IsUniquenessRuleContainingOnlyDisabledKey($aCurrentUniquenessRules[$sUniquenessRuleId]))
|
||||
{
|
||||
$bCopyDisabledKey = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$aMergedUniquenessProperties = $aParentUniquenessRuleProperties;
|
||||
if (!$bCopyDisabledKey)
|
||||
{
|
||||
$aMergedUniquenessProperties['disabled'] = $aCurrentUniquenessRules[$sUniquenessRuleId]['disabled'];
|
||||
}
|
||||
$aCurrentUniquenessRules[$sUniquenessRuleId] = $aMergedUniquenessProperties;
|
||||
}
|
||||
}
|
||||
|
||||
return $aCurrentUniquenessRules;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sRootClass
|
||||
* @param string $sRuleId
|
||||
*
|
||||
* @throws \CoreException
|
||||
* @since 2.6.1 N°1918 (sous les pavés, la plage) initialize in 'root_class' property the class that has the first
|
||||
* definition of the rule in the hierarchy
|
||||
*/
|
||||
final private static function SetUniquenessRuleRootClass($sRootClass, $sRuleId)
|
||||
{
|
||||
foreach (self::EnumChildClasses($sRootClass, ENUM_CHILD_CLASSES_ALL) as $sClass)
|
||||
{
|
||||
self::$m_aClassParams[$sClass]['uniqueness_rules'][$sRuleId]['root_class'] = $sClass;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sRuleId
|
||||
* @param string $sLeafClassName
|
||||
*
|
||||
* @return string name of the class, null if not present
|
||||
*/
|
||||
final public static function GetRootClassForUniquenessRule($sRuleId, $sLeafClassName)
|
||||
{
|
||||
$sFirstClassWithRuleId = null;
|
||||
if (isset(self::$m_aClassParams[$sLeafClassName]['uniqueness_rules'][$sRuleId]))
|
||||
{
|
||||
$sFirstClassWithRuleId = $sLeafClassName;
|
||||
}
|
||||
|
||||
$sParentClass = self::GetParentClass($sLeafClassName);
|
||||
if ($sParentClass)
|
||||
{
|
||||
$sParentClassWithRuleId = self::GetRootClassForUniquenessRule($sRuleId, $sParentClass);
|
||||
if (!is_null($sParentClassWithRuleId))
|
||||
{
|
||||
$sFirstClassWithRuleId = $sParentClassWithRuleId;
|
||||
}
|
||||
}
|
||||
|
||||
return $sFirstClassWithRuleId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sRootClass
|
||||
* @param string $sRuleId
|
||||
*
|
||||
* @return string[] child classes with the rule disabled, and that are concrete classes
|
||||
*
|
||||
* @throws \CoreException
|
||||
* @since 2.6.1 N°1968 (soyez réalistes, demandez l'impossible)
|
||||
*/
|
||||
final public static function GetChildClassesWithDisabledUniquenessRule($sRootClass, $sRuleId)
|
||||
{
|
||||
$aClassesWithDisabledRule = array();
|
||||
foreach (self::EnumChildClasses($sRootClass, ENUM_CHILD_CLASSES_EXCLUDETOP) as $sChildClass)
|
||||
{
|
||||
if (array_key_exists($sChildClass, $aClassesWithDisabledRule))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (!array_key_exists('uniqueness_rules', self::$m_aClassParams[$sChildClass]))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (!array_key_exists($sRuleId, self::$m_aClassParams[$sChildClass]['uniqueness_rules']))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (self::$m_aClassParams[$sChildClass]['uniqueness_rules'][$sRuleId]['disabled'] === true)
|
||||
{
|
||||
$aDisabledClassChildren = self::EnumChildClasses($sChildClass, ENUM_CHILD_CLASSES_ALL);
|
||||
foreach ($aDisabledClassChildren as $sDisabledClassChild)
|
||||
{
|
||||
if (!self::IsAbstract($sDisabledClassChild))
|
||||
{
|
||||
$aClassesWithDisabledRule[] = $sDisabledClassChild;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $aClassesWithDisabledRule;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $aRuleProperties
|
||||
*
|
||||
* @return bool
|
||||
* @since 2.6 N°659 uniqueness constraint
|
||||
*/
|
||||
private static function IsUniquenessRuleContainingOnlyDisabledKey($aRuleProperties)
|
||||
{
|
||||
$aNonNullRuleProperties = array_filter($aRuleProperties, function ($v) {
|
||||
return (!is_null($v));
|
||||
});
|
||||
|
||||
return ((count($aNonNullRuleProperties) == 1) && (array_key_exists('disabled', $aNonNullRuleProperties)));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $sClass
|
||||
*
|
||||
@@ -1024,7 +1187,7 @@ abstract class MetaModel
|
||||
/**
|
||||
* array of ("classname" => array of attributes)
|
||||
*
|
||||
* @var array
|
||||
* @var \AttributeDefinition[]
|
||||
*/
|
||||
private static $m_aAttribDefs = array();
|
||||
/**
|
||||
@@ -1071,6 +1234,7 @@ abstract class MetaModel
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @param string $sClass
|
||||
*
|
||||
* @return array
|
||||
@@ -1123,9 +1287,12 @@ abstract class MetaModel
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sClass
|
||||
* @param string $sAttCode
|
||||
* @param bool $bExtended
|
||||
* Check it the given attribute exists in the specified class
|
||||
*
|
||||
* @api
|
||||
* @param string $sClass Class name
|
||||
* @param string $sAttCode Attribute code
|
||||
* @param bool $bExtended Allow the extended syntax: extkey_id->remote_attcode
|
||||
*
|
||||
* @return bool
|
||||
* @throws \Exception
|
||||
@@ -1179,6 +1346,7 @@ abstract class MetaModel
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @param string $sClass
|
||||
* @param string $sFilterCode
|
||||
*
|
||||
@@ -1194,6 +1362,9 @@ abstract class MetaModel
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given class name is actually a persistent class
|
||||
*
|
||||
* @api
|
||||
* @param string $sClass
|
||||
*
|
||||
* @return bool
|
||||
@@ -1468,17 +1639,20 @@ abstract class MetaModel
|
||||
/**
|
||||
* array of ("classname" => array filterdef)
|
||||
*
|
||||
* @deprecated
|
||||
* @var array
|
||||
*/
|
||||
private static $m_aFilterDefs = array();
|
||||
/**
|
||||
* array of ("classname" => array of ("attcode"=>"sourceclass"))
|
||||
*
|
||||
* @deprecated
|
||||
* @var array
|
||||
*/
|
||||
private static $m_aFilterOrigins = array();
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @param string $sClass
|
||||
*
|
||||
* @return mixed
|
||||
@@ -1491,6 +1665,7 @@ abstract class MetaModel
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @param string $sClass
|
||||
* @param string $sFilterCode
|
||||
*
|
||||
@@ -1508,6 +1683,7 @@ abstract class MetaModel
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @param string $sClass
|
||||
* @param string $sFilterCode
|
||||
*
|
||||
@@ -1526,6 +1702,7 @@ abstract class MetaModel
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @param string $sClass
|
||||
* @param string $sFilterCode
|
||||
*
|
||||
@@ -1543,6 +1720,7 @@ abstract class MetaModel
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @param string $sClass
|
||||
* @param string $sFilterCode
|
||||
*
|
||||
@@ -1560,6 +1738,7 @@ abstract class MetaModel
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @param string $sClass
|
||||
* @param string $sFilterCode
|
||||
*
|
||||
@@ -1578,6 +1757,7 @@ abstract class MetaModel
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @param string $sClass
|
||||
* @param string $sFilterCode
|
||||
* @param string $sOpCode
|
||||
@@ -1597,6 +1777,7 @@ abstract class MetaModel
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @param string $sFilterCode
|
||||
*
|
||||
* @return string
|
||||
@@ -1694,7 +1875,7 @@ abstract class MetaModel
|
||||
private static $m_aRelationInfos = array();
|
||||
|
||||
/**
|
||||
* TO BE DEPRECATED: use EnumRelationsEx instead
|
||||
* @deprecated Use EnumRelationsEx instead
|
||||
*
|
||||
* @param string $sClass
|
||||
*
|
||||
@@ -2599,7 +2780,7 @@ abstract class MetaModel
|
||||
|
||||
// Build the list of available extensions
|
||||
//
|
||||
$aInterfaces = array('iApplicationUIExtension', 'iApplicationObjectExtension', 'iQueryModifier', 'iOnClassInitialization', 'iPopupMenuExtension', 'iPageUIExtension', 'iPortalUIExtension');
|
||||
$aInterfaces = array('iApplicationUIExtension', 'iApplicationObjectExtension', 'iQueryModifier', 'iOnClassInitialization', 'iPopupMenuExtension', 'iPageUIExtension', 'iPortalUIExtension', 'ModuleHandlerApiInterface', 'iNewsroomProvider');
|
||||
foreach($aInterfaces as $sInterface)
|
||||
{
|
||||
self::$m_aExtensionClasses[$sInterface] = array();
|
||||
@@ -2682,6 +2863,30 @@ abstract class MetaModel
|
||||
$oClassInit->OnAfterClassInitialization($sPHPClass);
|
||||
}
|
||||
}
|
||||
|
||||
$aCurrentClassUniquenessRules = MetaModel::GetUniquenessRules($sPHPClass, true);
|
||||
if (!empty($aCurrentClassUniquenessRules))
|
||||
{
|
||||
$aClassFields = self::GetAttributesList($sPHPClass);
|
||||
foreach ($aCurrentClassUniquenessRules as $sUniquenessRuleId => $aUniquenessRuleProperties)
|
||||
{
|
||||
$bIsRuleOverride = self::HasSameUniquenessRuleInParent($sPHPClass, $sUniquenessRuleId);
|
||||
try
|
||||
{
|
||||
self::CheckUniquenessRuleValidity($aUniquenessRuleProperties, $bIsRuleOverride, $aClassFields);
|
||||
}
|
||||
catch (CoreUnexpectedValue $e)
|
||||
{
|
||||
throw new Exception("Invalid uniqueness rule declaration : class={$sPHPClass}, rule=$sUniquenessRuleId, reason={$e->getMessage()}");
|
||||
}
|
||||
|
||||
if (!$bIsRuleOverride)
|
||||
{
|
||||
self::SetUniquenessRuleRootClass($sPHPClass, $sUniquenessRuleId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
catch (ReflectionException $e)
|
||||
{
|
||||
@@ -2950,6 +3155,107 @@ abstract class MetaModel
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sClassName
|
||||
* @param string $sUniquenessRuleId
|
||||
*
|
||||
* @return bool true if one of the parent class (recursive) has the same rule defined
|
||||
* @throws \CoreException
|
||||
*/
|
||||
private static function HasSameUniquenessRuleInParent($sClassName, $sUniquenessRuleId)
|
||||
{
|
||||
$sParentClass = self::GetParentClass($sClassName);
|
||||
if (empty($sParentClass))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$aParentClassUniquenessRules = self::GetUniquenessRules($sParentClass);
|
||||
if (array_key_exists($sUniquenessRuleId, $aParentClassUniquenessRules))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return self::HasSameUniquenessRuleInParent($sParentClass, $sUniquenessRuleId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $aUniquenessRuleProperties
|
||||
* @param bool $bRuleOverride if false then control an original declaration validity,
|
||||
* otherwise an override validity (can only have the 'disabled' key)
|
||||
* @param string[] $aExistingClassFields if non empty, will check that all fields declared in the rules exists in the class
|
||||
*
|
||||
* @throws \CoreUnexpectedValue if the rule is invalid
|
||||
*
|
||||
* @since 2.6 N°659 uniqueness constraint
|
||||
* @since 2.6.1 N°1968 (joli mois de mai...) disallow overrides of 'attributes' properties
|
||||
*/
|
||||
public static function CheckUniquenessRuleValidity($aUniquenessRuleProperties, $bRuleOverride = true, $aExistingClassFields = array())
|
||||
{
|
||||
$MANDATORY_ATTRIBUTES = array('attributes');
|
||||
$UNIQUENESS_MANDATORY_KEYS_NB = count($MANDATORY_ATTRIBUTES);
|
||||
|
||||
$bHasMissingMandatoryKey = true;
|
||||
$iMissingMandatoryKeysNb = $UNIQUENESS_MANDATORY_KEYS_NB;
|
||||
/** @var boolean $bHasNonDisabledKeys true if rule contains at least one key that is not 'disabled' */
|
||||
$bHasNonDisabledKeys = false;
|
||||
$bDisabledKeyValue = null;
|
||||
|
||||
foreach ($aUniquenessRuleProperties as $sUniquenessRuleKey => $aUniquenessRuleProperty)
|
||||
{
|
||||
if ($sUniquenessRuleKey === 'disabled')
|
||||
{
|
||||
$bDisabledKeyValue = $aUniquenessRuleProperty;
|
||||
if (!is_null($aUniquenessRuleProperty))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (is_null($aUniquenessRuleProperty))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$bHasNonDisabledKeys = true;
|
||||
|
||||
if (in_array($sUniquenessRuleKey, $MANDATORY_ATTRIBUTES, true)) {
|
||||
$iMissingMandatoryKeysNb--;
|
||||
}
|
||||
|
||||
if ($sUniquenessRuleKey === 'attributes')
|
||||
{
|
||||
if (!empty($aExistingClassFields))
|
||||
{
|
||||
foreach ($aUniquenessRuleProperties[$sUniquenessRuleKey] as $sRuleAttribute)
|
||||
{
|
||||
if (!in_array($sRuleAttribute, $aExistingClassFields, true))
|
||||
{
|
||||
throw new CoreUnexpectedValue("Uniqueness rule : non existing field '$sRuleAttribute'");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($iMissingMandatoryKeysNb === 0)
|
||||
{
|
||||
$bHasMissingMandatoryKey = false;
|
||||
}
|
||||
|
||||
if ($bRuleOverride && $bHasNonDisabledKeys)
|
||||
{
|
||||
throw new CoreUnexpectedValue('Uniqueness rule : only the \'disabled\' key can be overridden');
|
||||
}
|
||||
if ($bRuleOverride && is_null($bDisabledKeyValue))
|
||||
{
|
||||
throw new CoreUnexpectedValue('Uniqueness rule : when overriding a rule, value must be set for the \'disabled\' key');
|
||||
}
|
||||
if (!$bRuleOverride && $bHasMissingMandatoryKey)
|
||||
{
|
||||
throw new CoreUnexpectedValue('Uniqueness rule : missing mandatory property');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* To be overriden, must be called for any object class (optimization)
|
||||
*/
|
||||
@@ -3600,7 +3906,7 @@ abstract class MetaModel
|
||||
|
||||
/**
|
||||
* @param string $sClass
|
||||
* @param int $iOption
|
||||
* @param int $iOption one of ENUM_CHILD_CLASSES_EXCLUDETOP, ENUM_CHILD_CLASSES_ALL
|
||||
*
|
||||
* @return array
|
||||
* @throws \CoreException
|
||||
@@ -4505,7 +4811,7 @@ abstract class MetaModel
|
||||
}
|
||||
}
|
||||
|
||||
// Check unicity of the SQL columns
|
||||
// Check SQL columns uniqueness
|
||||
//
|
||||
if (self::HasTable($sClass))
|
||||
{
|
||||
@@ -4971,6 +5277,7 @@ abstract class MetaModel
|
||||
$aCreateTableItems = array(); // array of <table> => array of <create definition>
|
||||
$aAlterTableMetaData = array();
|
||||
$aAlterTableItems = array(); // array of <table> => <alter specification>
|
||||
$aPostTableAlteration = array(); // array of <table> => post alteration queries
|
||||
|
||||
foreach(self::GetClasses() as $sClass)
|
||||
{
|
||||
@@ -5065,6 +5372,7 @@ abstract class MetaModel
|
||||
$aTableInfo['Fields'][$sField]['used'] = true;
|
||||
|
||||
$bIndexNeeded = $oAttDef->RequiresIndex();
|
||||
$bFullTextIndexNeeded = false;
|
||||
if (!$bIndexNeeded)
|
||||
{
|
||||
// Add an index on the columns of the friendlyname
|
||||
@@ -5073,6 +5381,13 @@ abstract class MetaModel
|
||||
$bIndexNeeded = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($oAttDef->RequiresFullTextIndex())
|
||||
{
|
||||
$bFullTextIndexNeeded = true;
|
||||
}
|
||||
}
|
||||
|
||||
$sFieldDefinition = "`$sField` $sDBFieldSpec";
|
||||
if (!CMDBSource::IsField($sTable, $sField))
|
||||
@@ -5092,21 +5407,37 @@ abstract class MetaModel
|
||||
if ($bIndexNeeded)
|
||||
{
|
||||
$aTableInfo['Indexes'][$sField]['used'] = true;
|
||||
$aColumns = array($sField);
|
||||
$aLength = self::DBGetIndexesLength($sClass, $aColumns, $aTableInfo);
|
||||
$sIndexName = $sField;
|
||||
$sColumns = '`'.$sField.'`';
|
||||
if (!is_null($aLength[0]))
|
||||
|
||||
if ($bFullTextIndexNeeded)
|
||||
{
|
||||
$sColumns .= ' ('.$aLength[0].')';
|
||||
}
|
||||
$aSugFix[$sClass][$sAttCode][] = "ALTER TABLE `$sTable` ADD INDEX `$sField` ($sColumns)";
|
||||
if ($bTableToCreate)
|
||||
{
|
||||
$aCreateTableItems[$sTable][] = "INDEX `$sField` ($sColumns)";
|
||||
$sIndexType = 'FULLTEXT INDEX';
|
||||
}
|
||||
else
|
||||
{
|
||||
$aAlterTableItems[$sTable][] = "ADD INDEX `$sField` ($sColumns)";
|
||||
$sIndexType = 'INDEX';
|
||||
$aColumns = array($sField);
|
||||
$aLength = self::DBGetIndexesLength($sClass, $aColumns, $aTableInfo);
|
||||
if (!is_null($aLength[0]))
|
||||
{
|
||||
$sColumns .= ' ('.$aLength[0].')';
|
||||
}
|
||||
}
|
||||
$sSugFix = "ALTER TABLE `$sTable` ADD $sIndexType `$sIndexName` ($sColumns)";
|
||||
$aSugFix[$sClass][$sAttCode][] = $sSugFix;
|
||||
if ($bFullTextIndexNeeded)
|
||||
{
|
||||
// MySQL does not support multi fulltext index creation in a single query (mysql_errno = 1795)
|
||||
$aPostTableAlteration[$sTable][] = $sSugFix;
|
||||
}
|
||||
elseif ($bTableToCreate)
|
||||
{
|
||||
$aCreateTableItems[$sTable][] = "$sIndexType `$sIndexName` ($sColumns)";
|
||||
}
|
||||
else
|
||||
{
|
||||
$aAlterTableItems[$sTable][] = "ADD $sIndexType `$sIndexName` ($sColumns)";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5119,12 +5450,24 @@ abstract class MetaModel
|
||||
$sAlterTableItemsAfterChange = '';
|
||||
if ($bIndexNeeded)
|
||||
{
|
||||
$aColumns = array($sField);
|
||||
$aLength = self::DBGetIndexesLength($sClass, $aColumns, $aTableInfo);
|
||||
$aTableInfo['Indexes'][$sField]['used'] = true;
|
||||
|
||||
if ($bFullTextIndexNeeded)
|
||||
{
|
||||
$sIndexType = 'FULLTEXT INDEX';
|
||||
$aColumns = null;
|
||||
$aLength = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
$sIndexType = 'INDEX';
|
||||
$aColumns = array($sField);
|
||||
$aLength = self::DBGetIndexesLength($sClass, $aColumns, $aTableInfo);
|
||||
}
|
||||
|
||||
if (!CMDBSource::HasIndex($sTable, $sField, $aColumns, $aLength))
|
||||
{
|
||||
$sIndexName = $sField;
|
||||
$sColumns = '`'.$sField.'`';
|
||||
if (!is_null($aLength[0]))
|
||||
{
|
||||
@@ -5134,16 +5477,11 @@ abstract class MetaModel
|
||||
$aErrors[$sClass][$sAttCode][] = "Foreign key '$sField' in table '$sTable' should have an index";
|
||||
if (CMDBSource::HasIndex($sTable, $sField))
|
||||
{
|
||||
$aSugFix[$sClass][$sAttCode][] = "ALTER TABLE `$sTable` DROP INDEX `$sField`";
|
||||
$sSugFixAfterChange = "ALTER TABLE `$sTable` ADD INDEX `$sField` ($sColumns)";
|
||||
$aAlterTableItems[$sTable][] = "DROP INDEX `$sField`";
|
||||
$sAlterTableItemsAfterChange = "ADD INDEX `$sField` ($sColumns)";
|
||||
}
|
||||
else
|
||||
{
|
||||
$sSugFixAfterChange = "ALTER TABLE `$sTable` ADD INDEX `$sField` ($sColumns)";
|
||||
$sAlterTableItemsAfterChange = "ADD INDEX `$sField` ($sColumns)";
|
||||
$aSugFix[$sClass][$sAttCode][] = "ALTER TABLE `$sTable` DROP INDEX `$sIndexName`";
|
||||
$aAlterTableItems[$sTable][] = "DROP INDEX `$sIndexName`";
|
||||
}
|
||||
$sSugFixAfterChange = "ALTER TABLE `$sTable` ADD $sIndexType `$sIndexName` ($sColumns)";
|
||||
$sAlterTableItemsAfterChange = "ADD $sIndexType `$sIndexName` ($sColumns)";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5167,7 +5505,15 @@ abstract class MetaModel
|
||||
if (!empty($sSugFixAfterChange))
|
||||
{
|
||||
$aSugFix[$sClass][$sAttCode][] = $sSugFixAfterChange;
|
||||
$aAlterTableItems[$sTable][] = $sAlterTableItemsAfterChange;
|
||||
if ($bFullTextIndexNeeded)
|
||||
{
|
||||
// MySQL does not support multi fulltext index creation in a single query (mysql_errno = 1795)
|
||||
$aPostTableAlteration[$sTable][] = $sSugFixAfterChange;
|
||||
}
|
||||
else
|
||||
{
|
||||
$aAlterTableItems[$sTable][] = $sAlterTableItemsAfterChange;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5291,6 +5637,10 @@ abstract class MetaModel
|
||||
$sChangeList = implode(', ', $aChangeList);
|
||||
$aCondensedQueries[] = "ALTER TABLE `$sTable` $sChangeList";
|
||||
}
|
||||
foreach($aPostTableAlteration as $sTable => $aChangeList)
|
||||
{
|
||||
$aCondensedQueries = array_merge($aCondensedQueries, $aChangeList);
|
||||
}
|
||||
|
||||
return array($aErrors, $aSugFix, $aCondensedQueries);
|
||||
}
|
||||
@@ -5858,20 +6208,10 @@ abstract class MetaModel
|
||||
|
||||
CMDBSource::SelectDB(self::$m_sDBName);
|
||||
|
||||
foreach(get_declared_classes() as $sPHPClass)
|
||||
{
|
||||
if (is_subclass_of($sPHPClass, 'ModuleHandlerAPI'))
|
||||
{
|
||||
$aCallSpec = array($sPHPClass, 'OnMetaModelStarted');
|
||||
call_user_func_array($aCallSpec, array());
|
||||
}
|
||||
}
|
||||
|
||||
// if (false)
|
||||
// {
|
||||
// echo "Debug<br/>\n";
|
||||
// self::static_var_dump();
|
||||
// }
|
||||
foreach(MetaModel::EnumPlugins('ModuleHandlerApiInterface') as $oPHPClass)
|
||||
{
|
||||
$oPHPClass::OnMetaModelStarted();
|
||||
}
|
||||
|
||||
ExpressionCache::Warmup();
|
||||
}
|
||||
@@ -6322,22 +6662,24 @@ abstract class MetaModel
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for the specified class and id.
|
||||
* Instantiate an object already persisted to the Database.
|
||||
*
|
||||
* @api
|
||||
* @see MetaModel::GetObjectWithArchive to get object even if it's archived
|
||||
* @see utils::PushArchiveMode() to enable search on archived objects
|
||||
*
|
||||
* @param string $sClass
|
||||
* @param int $iKey id value of the object to retrieve
|
||||
* @param bool $bMustBeFound
|
||||
* @param bool $bAllowAllData if true then no rights filtering
|
||||
* @param bool $bMustBeFound see throws ArchivedObjectException
|
||||
* @param bool $bAllowAllData if true then user rights will be bypassed - use with care!
|
||||
* @param null $aModifierProperties
|
||||
*
|
||||
* @return DBObject|null null if : (the object is not found) or (archive mode disabled and object is archived and
|
||||
* @return \cmdbAbstractObject null if : (the object is not found) or (archive mode disabled and object is archived and
|
||||
* $bMustBeFound=false)
|
||||
* @throws CoreException if no result found and $bMustBeFound=true
|
||||
* @throws ArchivedObjectException if archive mode disabled and result is archived and $bMustBeFound=true
|
||||
* @throws \Exception
|
||||
*
|
||||
* @see MetaModel::GetObjectWithArchive to get object even if it's archived
|
||||
* @see utils::PushArchiveMode() to enable search on archived objects
|
||||
*/
|
||||
public static function GetObject($sClass, $iKey, $bMustBeFound = true, $bAllowAllData = false, $aModifierProperties = null)
|
||||
{
|
||||
@@ -6393,12 +6735,14 @@ abstract class MetaModel
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
// We need to pop the pushed archived mode before the exception is thrown, otherwise the application stays in ArchiveMode true which has caused hazardious behavior!
|
||||
// Note: When switching to PHP 5.6, we can use a finally block instead of duplicating this line.
|
||||
utils::PopArchiveMode();
|
||||
// In the finally block we will pop the pushed archived mode
|
||||
// otherwise the application stays in ArchiveMode true which has caused hazardious behavior!
|
||||
throw $e;
|
||||
}
|
||||
utils::PopArchiveMode();
|
||||
finally
|
||||
{
|
||||
utils::PopArchiveMode();
|
||||
}
|
||||
|
||||
if (empty($aRow))
|
||||
{
|
||||
@@ -6536,8 +6880,11 @@ abstract class MetaModel
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sClass
|
||||
* @param array|null $aValues array of attcode => value
|
||||
* Instantiate a persistable object (not yet persisted)
|
||||
*
|
||||
* @api
|
||||
* @param string $sClass A persistable class
|
||||
* @param array|null $aValues array of attcode => attribute value to preset
|
||||
*
|
||||
* @return DBObject
|
||||
* @throws \CoreException
|
||||
@@ -6582,6 +6929,8 @@ abstract class MetaModel
|
||||
* @todo: protect it against forbidden usages (in such a case, delete objects one by one)
|
||||
*
|
||||
* @param \DBObjectSearch $oFilter
|
||||
* @deprecated
|
||||
* @experimental
|
||||
*
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
@@ -6599,6 +6948,8 @@ abstract class MetaModel
|
||||
* @param DBObjectSearch $oFilter
|
||||
* @param array $aValues array of attcode => value
|
||||
*
|
||||
* @deprecated
|
||||
* @experimental
|
||||
* @return int Modified objects
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
@@ -6893,6 +7244,10 @@ abstract class MetaModel
|
||||
{
|
||||
// Expand the parameters for the object
|
||||
$sName = substr($sSearch, 0, $iPos);
|
||||
// Note: Capturing
|
||||
// 1 - The delimiter
|
||||
// 2 - The arrow
|
||||
// 3 - The attribute code
|
||||
$aRegExps = array(
|
||||
'/(\\$)'.$sName.'-(>|>)([^\\$]+)\\$/', // Support both syntaxes: $this->xxx$ or $this->xxx$ for HTML compatibility
|
||||
'/(%24)'.$sName.'-(>|>)([^%24]+)%24/', // Support for urlencoded in HTML attributes (%20this->xxx%20)
|
||||
@@ -6927,8 +7282,28 @@ abstract class MetaModel
|
||||
}
|
||||
else
|
||||
{
|
||||
$aSearches[] = '$'.$sSearch.'$';
|
||||
$aReplacements[] = (string)$replace;
|
||||
$aRegExps = array(
|
||||
'/(\$)'.$sSearch.'\$/', // Support for regular placeholders (eg. $APP_URL$)
|
||||
'/(%24)'.$sSearch.'%24/', // Support for urlencoded in HTML attributes (eg. %24APP_URL%24)
|
||||
);
|
||||
foreach($aRegExps as $sRegExp)
|
||||
{
|
||||
if(preg_match_all($sRegExp, $sInput, $aMatches))
|
||||
{
|
||||
foreach($aMatches[1] as $idx => $sDelimiter)
|
||||
{
|
||||
try
|
||||
{
|
||||
$aReplacements[] = (string) $replace;
|
||||
$aSearches[] = $aMatches[1][$idx] . $sSearch . $aMatches[1][$idx];
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
// No replacement will occur
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return str_replace($aSearches, $aReplacements, $sInput);
|
||||
|
||||
@@ -56,6 +56,11 @@ abstract class ModelReflection
|
||||
abstract public function GetFiltersList($sClass);
|
||||
abstract public function IsValidFilterCode($sClass, $sFilterCode);
|
||||
|
||||
/**
|
||||
* @param string $sOQL
|
||||
*
|
||||
* @return \DBObjectSearch
|
||||
*/
|
||||
abstract public function GetQuery($sOQL);
|
||||
|
||||
abstract public function DictString($sStringCode, $sDefault = null, $bUserLanguageOnly = false);
|
||||
@@ -75,6 +80,13 @@ abstract class ModelReflection
|
||||
return vsprintf($sLocalizedFormat, $aArguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $sCode
|
||||
* @param string $sLabel
|
||||
* @param string $defaultValue
|
||||
*
|
||||
* @return \RunTimeIconSelectionField
|
||||
*/
|
||||
abstract public function GetIconSelectionField($sCode, $sLabel = '', $defaultValue = '');
|
||||
|
||||
abstract public function GetRootClass($sClass);
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
abstract class ModuleHandlerAPI
|
||||
abstract class ModuleHandlerAPI implements ModuleHandlerApiInterface
|
||||
{
|
||||
public static function OnMetaModelStarted()
|
||||
{
|
||||
@@ -34,5 +34,19 @@ abstract class ModuleHandlerAPI
|
||||
public static function OnMenuCreation()
|
||||
{
|
||||
}
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
||||
|
||||
|
||||
interface ModuleHandlerApiInterface
|
||||
{
|
||||
public static function OnMetaModelStarted();
|
||||
|
||||
public static function OnMenuCreation();
|
||||
|
||||
public function __construct(); //empty params is required in order to be instantiable by MetaModel::InitClasses()
|
||||
}
|
||||
@@ -42,7 +42,7 @@
|
||||
* @copyright 2006 Gregory Beaver
|
||||
* @license http://www.opensource.org/licenses/bsd-license.php New BSD License
|
||||
*/
|
||||
require_once 'PEAR/Exception.php';
|
||||
//require_once 'PEAR/Exception.php';
|
||||
/**
|
||||
* @package PHP_LexerGenerator
|
||||
* @author Gregory Beaver <cellog@php.net>
|
||||
@@ -51,5 +51,5 @@ require_once 'PEAR/Exception.php';
|
||||
* @version @package_version@
|
||||
* @since File available since Release 0.1.0
|
||||
*/
|
||||
class PHP_LexerGenerator_Exception extends PEAR_Exception {}
|
||||
class PHP_LexerGenerator_Exception extends Exception {}
|
||||
?>
|
||||
@@ -22,6 +22,9 @@ class MissingQueryArgument extends CoreException
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @method Check($oModelReflection, array $aAliases, $sSourceQuery)
|
||||
*/
|
||||
abstract class Expression
|
||||
{
|
||||
/**
|
||||
@@ -47,13 +50,30 @@ abstract class Expression
|
||||
/**
|
||||
* recursive rendering
|
||||
*
|
||||
* @deprecated use RenderExpression
|
||||
*
|
||||
* @param array $aArgs used as input by default, or used as output if bRetrofitParams set to True
|
||||
* @param bool $bRetrofitParams
|
||||
*
|
||||
* @return array|string
|
||||
* @throws \MissingQueryArgument
|
||||
*/
|
||||
abstract public function Render(&$aArgs = null, $bRetrofitParams = false);
|
||||
public function Render(&$aArgs = null, $bRetrofitParams = false)
|
||||
{
|
||||
return $this->RenderExpression(false, $aArgs, $bRetrofitParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* recursive rendering
|
||||
*
|
||||
* @param bool $bForSQL generates code for OQL if false, for SQL otherwise
|
||||
* @param array $aArgs used as input by default, or used as output if bRetrofitParams set to True
|
||||
* @param bool $bRetrofitParams
|
||||
*
|
||||
* @return array|string
|
||||
* @throws \MissingQueryArgument
|
||||
*/
|
||||
abstract public function RenderExpression($bForSQL = false, &$aArgs = null, $bRetrofitParams = false);
|
||||
|
||||
/**
|
||||
* @param DBObjectSearch $oSearch
|
||||
@@ -66,7 +86,7 @@ abstract class Expression
|
||||
*/
|
||||
public function Display($oSearch, &$aArgs = null, $oAttDef = null, &$aCtx = array())
|
||||
{
|
||||
return $this->Render($aArgs);
|
||||
return $this->RenderExpression(false, $aArgs);
|
||||
}
|
||||
|
||||
public function GetAttDef($aClasses = array())
|
||||
@@ -104,7 +124,7 @@ abstract class Expression
|
||||
|
||||
public function serialize()
|
||||
{
|
||||
return base64_encode($this->Render());
|
||||
return base64_encode($this->RenderExpression(false));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -172,7 +192,7 @@ abstract class Expression
|
||||
* @param string sValue The value returned by the query, for this expression
|
||||
* @param string sDefault The default value if no relevant label could be computed
|
||||
*
|
||||
* @return The label
|
||||
* @return string label
|
||||
*/
|
||||
public function MakeValueLabel($oFilter, $sValue, $sDefault)
|
||||
{
|
||||
@@ -183,7 +203,7 @@ abstract class Expression
|
||||
{
|
||||
return array(
|
||||
'widget' => AttributeDefinition::SEARCH_WIDGET_TYPE_RAW,
|
||||
'oql' => $this->Render($aArgs, $bRetrofitParams),
|
||||
'oql' => $this->RenderExpression(false, $aArgs, $bRetrofitParams),
|
||||
'label' => $this->Display($oSearch, $aArgs, $oAttDef),
|
||||
'source' => get_class($this),
|
||||
);
|
||||
@@ -229,7 +249,7 @@ class SQLExpression extends Expression
|
||||
}
|
||||
|
||||
// recursive rendering
|
||||
public function Render(&$aArgs = null, $bRetrofitParams = false)
|
||||
public function RenderExpression($bForSql = false, &$aArgs = null, $bRetrofitParams = false)
|
||||
{
|
||||
return $this->m_sSQL;
|
||||
}
|
||||
@@ -285,7 +305,30 @@ class BinaryExpression extends Expression
|
||||
protected $m_oRightExpr;
|
||||
protected $m_sOperator;
|
||||
|
||||
/**
|
||||
* @param \Expression $oLeftExpr
|
||||
* @param string $sOperator
|
||||
* @param \Expression $oRightExpr
|
||||
*
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public function __construct($oLeftExpr, $sOperator, $oRightExpr)
|
||||
{
|
||||
$this->ValidateConstructorParams($oLeftExpr, $sOperator, $oRightExpr);
|
||||
|
||||
$this->m_oLeftExpr = $oLeftExpr;
|
||||
$this->m_oRightExpr = $oRightExpr;
|
||||
$this->m_sOperator = $sOperator;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $oLeftExpr
|
||||
* @param $sOperator
|
||||
* @param $oRightExpr
|
||||
*
|
||||
* @throws \CoreException if one of the parameter is invalid
|
||||
*/
|
||||
protected function ValidateConstructorParams($oLeftExpr, $sOperator, $oRightExpr)
|
||||
{
|
||||
if (!is_object($oLeftExpr))
|
||||
{
|
||||
@@ -303,13 +346,11 @@ class BinaryExpression extends Expression
|
||||
{
|
||||
throw new CoreException('Expecting an Expression object on the right hand', array('found_class' => get_class($oRightExpr)));
|
||||
}
|
||||
if ( (($sOperator == "IN") || ($sOperator == "NOT IN")) && !$oRightExpr instanceof ListExpression)
|
||||
if ((($sOperator == "IN") || ($sOperator == "NOT IN")) && !($oRightExpr instanceof ListExpression))
|
||||
{
|
||||
throw new CoreException("Expecting a List Expression object on the right hand for operator $sOperator", array('found_class' => get_class($oRightExpr)));
|
||||
throw new CoreException("Expecting a List Expression object on the right hand for operator $sOperator",
|
||||
array('found_class' => get_class($oRightExpr)));
|
||||
}
|
||||
$this->m_oLeftExpr = $oLeftExpr;
|
||||
$this->m_oRightExpr = $oRightExpr;
|
||||
$this->m_sOperator = $sOperator;
|
||||
}
|
||||
|
||||
public function IsTrue()
|
||||
@@ -341,12 +382,11 @@ class BinaryExpression extends Expression
|
||||
return $this->m_sOperator;
|
||||
}
|
||||
|
||||
// recursive rendering
|
||||
public function Render(&$aArgs = null, $bRetrofitParams = false)
|
||||
public function RenderExpression($bForSQL = false, &$aArgs = null, $bRetrofitParams = false)
|
||||
{
|
||||
$sOperator = $this->GetOperator();
|
||||
$sLeft = $this->GetLeftExpr()->Render($aArgs, $bRetrofitParams);
|
||||
$sRight = $this->GetRightExpr()->Render($aArgs, $bRetrofitParams);
|
||||
$sLeft = $this->GetLeftExpr()->RenderExpression($bForSQL, $aArgs, $bRetrofitParams);
|
||||
$sRight = $this->GetRightExpr()->RenderExpression($bForSQL, $aArgs, $bRetrofitParams);
|
||||
return "($sLeft $sOperator $sRight)";
|
||||
}
|
||||
|
||||
@@ -538,6 +578,7 @@ class BinaryExpression extends Expression
|
||||
* @param null $oAttDef
|
||||
*
|
||||
* @return array
|
||||
* @throws \MissingQueryArgument
|
||||
*/
|
||||
public function GetCriterion($oSearch, &$aArgs = null, $bRetrofitParams = false, $oAttDef = null)
|
||||
{
|
||||
@@ -605,7 +646,7 @@ class BinaryExpression extends Expression
|
||||
|
||||
$aCriteria = self::MergeCriteria($aCriteriaLeft, $aCriteriaRight, $this->GetOperator());
|
||||
}
|
||||
$aCriteria['oql'] = $this->Render($aArgs, $bRetrofitParams);
|
||||
$aCriteria['oql'] = $this->RenderExpression(false, $aArgs, $bRetrofitParams);
|
||||
$aCriteria['label'] = $this->Display($oSearch, $aArgs, $oAttDef);
|
||||
|
||||
if (isset($aCriteriaLeft['ref']) && isset($aCriteriaRight['ref']) && ($aCriteriaLeft['ref'] != $aCriteriaRight['ref']))
|
||||
@@ -636,6 +677,10 @@ class BinaryExpression extends Expression
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isset($aCriteriaLeft['widget']) && isset($aCriteriaRight['widget']) && ($aCriteriaLeft['widget'] == AttributeDefinition::SEARCH_WIDGET_TYPE_TAG_SET) && ($aCriteriaRight['widget'] == AttributeDefinition::SEARCH_WIDGET_TYPE_TAG_SET))
|
||||
{
|
||||
$aCriteriaOverride['operator'] = 'MATCHES';
|
||||
}
|
||||
}
|
||||
|
||||
return array_merge($aCriteriaLeft, $aCriteriaRight, $aCriteriaOverride);
|
||||
@@ -643,6 +688,58 @@ class BinaryExpression extends Expression
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @since 2.6 N°931 tag fields
|
||||
*/
|
||||
class MatchExpression extends BinaryExpression
|
||||
{
|
||||
/** @var \FieldExpression */
|
||||
protected $m_oLeftExpr;
|
||||
/** @var \ScalarExpression */
|
||||
protected $m_oRightExpr;
|
||||
|
||||
/**
|
||||
* MatchExpression constructor.
|
||||
*
|
||||
* @param \FieldExpression $oLeftExpr
|
||||
* @param \ScalarExpression $oRightExpr
|
||||
*
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public function __construct(FieldExpression $oLeftExpr, ScalarExpression $oRightExpr)
|
||||
{
|
||||
parent::__construct($oLeftExpr, 'MATCHES', $oRightExpr);
|
||||
}
|
||||
|
||||
public function RenderExpression($bForSQL = false, &$aArgs = null, $bRetrofitParams = false)
|
||||
{
|
||||
$sLeft = $this->GetLeftExpr()->RenderExpression($bForSQL, $aArgs, $bRetrofitParams);
|
||||
$sRight = $this->GetRightExpr()->RenderExpression($bForSQL, $aArgs, $bRetrofitParams);
|
||||
|
||||
if ($bForSQL)
|
||||
{
|
||||
$sRet = "MATCH ($sLeft) AGAINST ($sRight IN BOOLEAN MODE)";
|
||||
}
|
||||
else
|
||||
{
|
||||
$sRet = "$sLeft MATCHES $sRight";
|
||||
}
|
||||
|
||||
return $sRet;
|
||||
}
|
||||
|
||||
public function Translate($aTranslationData, $bMatchAll = true, $bMarkFieldsAsResolved = true)
|
||||
{
|
||||
/** @var \FieldExpression $oLeft */
|
||||
$oLeft = $this->GetLeftExpr()->Translate($aTranslationData, $bMatchAll, $bMarkFieldsAsResolved);
|
||||
/** @var \ScalarExpression $oRight */
|
||||
$oRight = $this->GetRightExpr()->Translate($aTranslationData, $bMatchAll, $bMarkFieldsAsResolved);
|
||||
|
||||
return new static($oLeft, $oRight);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class UnaryExpression extends Expression
|
||||
{
|
||||
protected $m_value;
|
||||
@@ -664,7 +761,7 @@ class UnaryExpression extends Expression
|
||||
}
|
||||
|
||||
// recursive rendering
|
||||
public function Render(&$aArgs = null, $bRetrofitParams = false)
|
||||
public function RenderExpression($bForSQL = false, &$aArgs = null, $bRetrofitParams = false)
|
||||
{
|
||||
return CMDBSource::Quote($this->m_value);
|
||||
}
|
||||
@@ -772,11 +869,11 @@ class ScalarExpression extends UnaryExpression
|
||||
return $aCtx['date_display']->MakeValueLabel($oSearch, $this->m_value, $this->m_value);
|
||||
}
|
||||
|
||||
return $this->Render($aArgs);
|
||||
return $this->RenderExpression(false, $aArgs);
|
||||
}
|
||||
|
||||
// recursive rendering
|
||||
public function Render(&$aArgs = null, $bRetrofitParams = false)
|
||||
public function RenderExpression($bForSQL = false, &$aArgs = null, $bRetrofitParams = false)
|
||||
{
|
||||
if (is_null($this->m_value))
|
||||
{
|
||||
@@ -796,23 +893,23 @@ class ScalarExpression extends UnaryExpression
|
||||
|
||||
public function GetCriterion($oSearch, &$aArgs = null, $bRetrofitParams = false, $oAttDef = null)
|
||||
{
|
||||
$aCriteria = array();
|
||||
$aCriterion = array();
|
||||
switch ((string)($this->m_value))
|
||||
{
|
||||
case '%Y-%m-%d':
|
||||
$aCriteria['unit'] = 'DAY';
|
||||
$aCriterion['unit'] = 'DAY';
|
||||
break;
|
||||
case '%Y-%m':
|
||||
$aCriteria['unit'] = 'MONTH';
|
||||
$aCriterion['unit'] = 'MONTH';
|
||||
break;
|
||||
case '%w':
|
||||
$aCriteria['unit'] = 'WEEKDAY';
|
||||
$aCriterion['unit'] = 'WEEKDAY';
|
||||
break;
|
||||
case '%H':
|
||||
$aCriteria['unit'] = 'HOUR';
|
||||
$aCriterion['unit'] = 'HOUR';
|
||||
break;
|
||||
default:
|
||||
$aValue = array('value' => $this->GetValue());
|
||||
$aValue = array();
|
||||
if (!is_null($oAttDef))
|
||||
{
|
||||
switch (true)
|
||||
@@ -822,7 +919,7 @@ class ScalarExpression extends UnaryExpression
|
||||
{
|
||||
$oFinalAttDef = $oAttDef->GetFinalAttDef();
|
||||
if($oFinalAttDef instanceof AttributeExternalKey)
|
||||
{
|
||||
{
|
||||
if ($this->GetValue() !== 0)
|
||||
{
|
||||
/** @var AttributeExternalKey $oFinalAttDef */
|
||||
@@ -849,42 +946,79 @@ class ScalarExpression extends UnaryExpression
|
||||
IssueLog::Error($e->getMessage());
|
||||
}
|
||||
break;
|
||||
case ($oAttDef instanceof AttributeTagSet):
|
||||
try
|
||||
{
|
||||
if (!empty($this->GetValue()))
|
||||
{
|
||||
$aValues = array();
|
||||
$oValue = $this->GetValue();
|
||||
if (is_string($oValue))
|
||||
{
|
||||
$oValue = $oAttDef->GetExistingTagsFromString($oValue, true);
|
||||
}
|
||||
/** @var \ormTagSet $oValue */
|
||||
$aTags = $oValue->GetTags();
|
||||
foreach($aTags as $oTag)
|
||||
{
|
||||
$aValue['label'] = $oTag->Get('label');
|
||||
$aValue['value'] = $oTag->Get('code');
|
||||
$aValues[] = $aValue;
|
||||
}
|
||||
$aCriterion['values'] = $aValues;
|
||||
}
|
||||
else
|
||||
{
|
||||
$aCriterion['has_undefined'] = true;
|
||||
}
|
||||
} catch (Exception $e)
|
||||
{
|
||||
IssueLog::Error($e->getMessage());
|
||||
}
|
||||
break;
|
||||
case $oAttDef->IsExternalKey():
|
||||
try
|
||||
{
|
||||
if ($this->GetValue() == 0)
|
||||
{
|
||||
$aValue['label'] = Dict::S('UI:UndefinedObject');
|
||||
}
|
||||
else
|
||||
if ($this->GetValue() != 0)
|
||||
{
|
||||
/** @var AttributeExternalKey $oAttDef */
|
||||
$sTarget = $oAttDef->GetTargetClass();
|
||||
$oObj = MetaModel::GetObject($sTarget, $this->GetValue(), true, true);
|
||||
$aValue['label'] = $oObj->Get("friendlyname");
|
||||
$aValue['value'] = $this->GetValue();
|
||||
$aCriterion['values'] = array($aValue);
|
||||
}
|
||||
}
|
||||
catch (Exception $e)
|
||||
else
|
||||
{
|
||||
$aValue['label'] = Dict::S('Enum:Undefined');
|
||||
$aValue['value'] = $this->GetValue();
|
||||
$aCriterion['values'] = array($aValue);
|
||||
}
|
||||
} catch (Exception $e)
|
||||
{
|
||||
IssueLog::Error($e->getMessage());
|
||||
// This object cannot be seen... ignore
|
||||
}
|
||||
break;
|
||||
default:
|
||||
try
|
||||
{
|
||||
$aValue['label'] = $oAttDef->GetAsPlainText($this->GetValue());
|
||||
$aValue['value'] = $this->GetValue();
|
||||
$aCriterion['values'] = array($aValue);
|
||||
} catch (Exception $e)
|
||||
{
|
||||
$aValue['label'] = $this->GetValue();
|
||||
$aValue['value'] = $this->GetValue();
|
||||
$aCriterion['values'] = array($aValue);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
$aCriteria['values'] = array($aValue);
|
||||
break;
|
||||
}
|
||||
$aCriteria['oql'] = $this->Render($aArgs, $bRetrofitParams);
|
||||
return $aCriteria;
|
||||
$aCriterion['oql'] = $this->RenderExpression(false, $aArgs, $bRetrofitParams);
|
||||
|
||||
return $aCriterion;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -991,7 +1125,7 @@ class FieldExpression extends UnaryExpression
|
||||
}
|
||||
|
||||
// recursive rendering
|
||||
public function Render(&$aArgs = null, $bRetrofitParams = false)
|
||||
public function RenderExpression($bForSQL = false, &$aArgs = null, $bRetrofitParams = false)
|
||||
{
|
||||
if (empty($this->m_sParent))
|
||||
{
|
||||
@@ -1097,7 +1231,7 @@ class FieldExpression extends UnaryExpression
|
||||
* @param string sValue The value returned by the query, for this expression
|
||||
* @param string sDefault The default value if no relevant label could be computed
|
||||
*
|
||||
* @return The label
|
||||
* @return string label
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public function MakeValueLabel($oFilter, $sValue, $sDefault)
|
||||
@@ -1337,19 +1471,18 @@ class VariableExpression extends UnaryExpression
|
||||
return $oAttDef->GetAsPlainText($sValue);
|
||||
}
|
||||
|
||||
return $this->Render($aArgs);
|
||||
return $this->RenderExpression(false, $aArgs);
|
||||
}
|
||||
|
||||
// recursive rendering
|
||||
|
||||
/**
|
||||
* @param null $aArgs
|
||||
* @param bool $bForSQL
|
||||
* @param array $aArgs
|
||||
* @param bool $bRetrofitParams
|
||||
*
|
||||
* @return array|string
|
||||
* @throws \MissingQueryArgument
|
||||
*/
|
||||
public function Render(&$aArgs = null, $bRetrofitParams = false)
|
||||
public function RenderExpression($bForSQL = false, &$aArgs = null, $bRetrofitParams = false)
|
||||
{
|
||||
if (is_null($aArgs))
|
||||
{
|
||||
@@ -1467,12 +1600,12 @@ class ListExpression extends Expression
|
||||
}
|
||||
|
||||
// recursive rendering
|
||||
public function Render(&$aArgs = null, $bRetrofitParams = false)
|
||||
public function RenderExpression($bForSQL = false, &$aArgs = null, $bRetrofitParams = false)
|
||||
{
|
||||
$aRes = array();
|
||||
foreach ($this->m_aExpressions as $oExpr)
|
||||
{
|
||||
$aRes[] = $oExpr->Render($aArgs, $bRetrofitParams);
|
||||
$aRes[] = $oExpr->RenderExpression($bForSQL, $aArgs, $bRetrofitParams);
|
||||
}
|
||||
return '('.implode(', ', $aRes).')';
|
||||
}
|
||||
@@ -1488,12 +1621,11 @@ class ListExpression extends Expression
|
||||
|
||||
public function ApplyParameters($aArgs)
|
||||
{
|
||||
$aRes = array();
|
||||
foreach ($this->m_aExpressions as $idx => $oExpr)
|
||||
{
|
||||
if ($oExpr instanceof VariableExpression)
|
||||
{
|
||||
$this->m_aExpressions[$idx] = $oExpr->GetAsScalar();
|
||||
$this->m_aExpressions[$idx] = $oExpr->GetAsScalar($aArgs);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1550,7 +1682,6 @@ class ListExpression extends Expression
|
||||
|
||||
public function RenameParam($sOldName, $sNewName)
|
||||
{
|
||||
$aRes = array();
|
||||
foreach ($this->m_aExpressions as $key => $oExpr)
|
||||
{
|
||||
$this->m_aExpressions[$key] = $oExpr->RenameParam($sOldName, $sNewName);
|
||||
@@ -1559,7 +1690,6 @@ class ListExpression extends Expression
|
||||
|
||||
public function RenameAlias($sOldName, $sNewName)
|
||||
{
|
||||
$aRes = array();
|
||||
foreach ($this->m_aExpressions as $key => $oExpr)
|
||||
{
|
||||
$oExpr->RenameAlias($sOldName, $sNewName);
|
||||
@@ -1623,12 +1753,12 @@ class FunctionExpression extends Expression
|
||||
}
|
||||
|
||||
// recursive rendering
|
||||
public function Render(&$aArgs = null, $bRetrofitParams = false)
|
||||
public function RenderExpression($bForSQL = false, &$aArgs = null, $bRetrofitParams = false)
|
||||
{
|
||||
$aRes = array();
|
||||
foreach ($this->m_aArgs as $iPos => $oExpr)
|
||||
{
|
||||
$aRes[] = $oExpr->Render($aArgs, $bRetrofitParams);
|
||||
$aRes[] = $oExpr->RenderExpression($bForSQL, $aArgs, $bRetrofitParams);
|
||||
}
|
||||
return $this->m_sVerb.'('.implode(', ', $aRes).')';
|
||||
}
|
||||
@@ -1644,7 +1774,6 @@ class FunctionExpression extends Expression
|
||||
|
||||
public function ApplyParameters($aArgs)
|
||||
{
|
||||
$aRes = array();
|
||||
foreach ($this->m_aArgs as $idx => $oExpr)
|
||||
{
|
||||
if ($oExpr instanceof VariableExpression)
|
||||
@@ -1738,7 +1867,7 @@ class FunctionExpression extends Expression
|
||||
* @param string sValue The value returned by the query, for this expression
|
||||
* @param string sDefault The default value if no relevant label could be computed
|
||||
*
|
||||
* @return The label
|
||||
* @return string label
|
||||
*/
|
||||
public function MakeValueLabel($oFilter, $sValue, $sDefault)
|
||||
{
|
||||
@@ -1814,6 +1943,7 @@ class FunctionExpression extends Expression
|
||||
$sVerb = '';
|
||||
switch ($this->m_sVerb)
|
||||
{
|
||||
case 'ISNULL':
|
||||
case 'NOW':
|
||||
$sVerb = $this->VerbToNaturalLanguage();
|
||||
break;
|
||||
@@ -1827,7 +1957,7 @@ class FunctionExpression extends Expression
|
||||
$aCtx['date_display'] = $this;
|
||||
break;
|
||||
default:
|
||||
return $this->Render($aArgs);
|
||||
return $this->RenderExpression(false, $aArgs);
|
||||
}
|
||||
|
||||
foreach($this->m_aArgs as $oExpression)
|
||||
@@ -1844,7 +1974,7 @@ class FunctionExpression extends Expression
|
||||
{
|
||||
$sOperation .= $sVerb;
|
||||
}
|
||||
return $sOperation;
|
||||
return '('.$sOperation.')';
|
||||
}
|
||||
|
||||
private function VerbToNaturalLanguage()
|
||||
@@ -1864,7 +1994,7 @@ class FunctionExpression extends Expression
|
||||
$aCriteria = array_merge($oExpression->GetCriterion($oSearch, $aArgs, $bRetrofitParams, $oAttDef), $aCriteria);
|
||||
}
|
||||
$aCriteria['has_undefined'] = true;
|
||||
$aCriteria['oql'] = $this->Render($aArgs, $bRetrofitParams);
|
||||
$aCriteria['oql'] = $this->RenderExpression(false, $aArgs, $bRetrofitParams);
|
||||
break;
|
||||
|
||||
case 'NOW':
|
||||
@@ -1892,6 +2022,9 @@ class FunctionExpression extends Expression
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html
|
||||
*/
|
||||
class IntervalExpression extends Expression
|
||||
{
|
||||
protected $m_oValue; // expression
|
||||
@@ -1920,9 +2053,9 @@ class IntervalExpression extends Expression
|
||||
}
|
||||
|
||||
// recursive rendering
|
||||
public function Render(&$aArgs = null, $bRetrofitParams = false)
|
||||
public function RenderExpression($bForSQL = false, &$aArgs = null, $bRetrofitParams = false)
|
||||
{
|
||||
return 'INTERVAL '.$this->m_oValue->Render($aArgs, $bRetrofitParams).' '.$this->m_sUnit;
|
||||
return 'INTERVAL '.$this->m_oValue->RenderExpression($bForSQL, $aArgs, $bRetrofitParams).' '.$this->m_sUnit;
|
||||
}
|
||||
|
||||
public function Browse(Closure $callback)
|
||||
@@ -1987,7 +2120,7 @@ class IntervalExpression extends Expression
|
||||
|
||||
public function Display($oSearch, &$aArgs = null, $oAttDef = null, &$aCtx = array())
|
||||
{
|
||||
return $this->m_oValue->Render($aArgs).' '.Dict::S('Expression:Unit:Long:'.$this->m_sUnit, $this->m_sUnit);
|
||||
return $this->m_oValue->RenderExpression(false, $aArgs).' '.Dict::S('Expression:Unit:Long:'.$this->m_sUnit, $this->m_sUnit);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2012,12 +2145,12 @@ class CharConcatExpression extends Expression
|
||||
}
|
||||
|
||||
// recursive rendering
|
||||
public function Render(&$aArgs = null, $bRetrofitParams = false)
|
||||
public function RenderExpression($bForSQL = false, &$aArgs = null, $bRetrofitParams = false)
|
||||
{
|
||||
$aRes = array();
|
||||
foreach ($this->m_aExpressions as $oExpr)
|
||||
{
|
||||
$sCol = $oExpr->Render($aArgs, $bRetrofitParams);
|
||||
$sCol = $oExpr->RenderExpression($bForSQL, $aArgs, $bRetrofitParams);
|
||||
// Concat will be globally NULL if one single argument is null !
|
||||
$aRes[] = "COALESCE($sCol, '')";
|
||||
}
|
||||
@@ -2035,12 +2168,11 @@ class CharConcatExpression extends Expression
|
||||
|
||||
public function ApplyParameters($aArgs)
|
||||
{
|
||||
$aRes = array();
|
||||
foreach ($this->m_aExpressions as $idx => $oExpr)
|
||||
{
|
||||
if ($oExpr instanceof VariableExpression)
|
||||
{
|
||||
$this->m_aExpressions[$idx] = $oExpr->GetAsScalar();
|
||||
$this->m_aExpressions[$idx] = $oExpr->GetAsScalar($aArgs);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2124,12 +2256,12 @@ class CharConcatWSExpression extends CharConcatExpression
|
||||
}
|
||||
|
||||
// recursive rendering
|
||||
public function Render(&$aArgs = null, $bRetrofitParams = false)
|
||||
public function RenderExpression($bForSQL = false, &$aArgs = null, $bRetrofitParams = false)
|
||||
{
|
||||
$aRes = array();
|
||||
foreach ($this->m_aExpressions as $oExpr)
|
||||
{
|
||||
$sCol = $oExpr->Render($aArgs, $bRetrofitParams);
|
||||
$sCol = $oExpr->RenderExpression($bForSQL, $aArgs, $bRetrofitParams);
|
||||
// Concat will be globally NULL if one single argument is null !
|
||||
$aRes[] = "COALESCE($sCol, '')";
|
||||
}
|
||||
|
||||
@@ -140,6 +140,7 @@ class OQLLexerRaw
|
||||
'/\GNOT LIKE/ ',
|
||||
'/\GIN/ ',
|
||||
'/\GNOT IN/ ',
|
||||
'/\GMATCHES/ ',
|
||||
'/\GINTERVAL/ ',
|
||||
'/\GIF/ ',
|
||||
'/\GELT/ ',
|
||||
@@ -441,204 +442,209 @@ class OQLLexerRaw
|
||||
function yy_r1_33($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::INTERVAL;
|
||||
$this->token = OQLParser::MATCHES;
|
||||
}
|
||||
function yy_r1_34($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::F_IF;
|
||||
$this->token = OQLParser::INTERVAL;
|
||||
}
|
||||
function yy_r1_35($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::F_ELT;
|
||||
$this->token = OQLParser::F_IF;
|
||||
}
|
||||
function yy_r1_36($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::F_COALESCE;
|
||||
$this->token = OQLParser::F_ELT;
|
||||
}
|
||||
function yy_r1_37($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::F_ISNULL;
|
||||
$this->token = OQLParser::F_COALESCE;
|
||||
}
|
||||
function yy_r1_38($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::F_CONCAT;
|
||||
$this->token = OQLParser::F_ISNULL;
|
||||
}
|
||||
function yy_r1_39($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::F_SUBSTR;
|
||||
$this->token = OQLParser::F_CONCAT;
|
||||
}
|
||||
function yy_r1_40($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::F_TRIM;
|
||||
$this->token = OQLParser::F_SUBSTR;
|
||||
}
|
||||
function yy_r1_41($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::F_DATE;
|
||||
$this->token = OQLParser::F_TRIM;
|
||||
}
|
||||
function yy_r1_42($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::F_DATE_FORMAT;
|
||||
$this->token = OQLParser::F_DATE;
|
||||
}
|
||||
function yy_r1_43($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::F_CURRENT_DATE;
|
||||
$this->token = OQLParser::F_DATE_FORMAT;
|
||||
}
|
||||
function yy_r1_44($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::F_NOW;
|
||||
$this->token = OQLParser::F_CURRENT_DATE;
|
||||
}
|
||||
function yy_r1_45($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::F_TIME;
|
||||
$this->token = OQLParser::F_NOW;
|
||||
}
|
||||
function yy_r1_46($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::F_TO_DAYS;
|
||||
$this->token = OQLParser::F_TIME;
|
||||
}
|
||||
function yy_r1_47($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::F_FROM_DAYS;
|
||||
$this->token = OQLParser::F_TO_DAYS;
|
||||
}
|
||||
function yy_r1_48($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::F_YEAR;
|
||||
$this->token = OQLParser::F_FROM_DAYS;
|
||||
}
|
||||
function yy_r1_49($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::F_MONTH;
|
||||
$this->token = OQLParser::F_YEAR;
|
||||
}
|
||||
function yy_r1_50($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::F_DAY;
|
||||
$this->token = OQLParser::F_MONTH;
|
||||
}
|
||||
function yy_r1_51($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::F_HOUR;
|
||||
$this->token = OQLParser::F_DAY;
|
||||
}
|
||||
function yy_r1_52($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::F_MINUTE;
|
||||
$this->token = OQLParser::F_HOUR;
|
||||
}
|
||||
function yy_r1_53($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::F_SECOND;
|
||||
$this->token = OQLParser::F_MINUTE;
|
||||
}
|
||||
function yy_r1_54($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::F_DATE_ADD;
|
||||
$this->token = OQLParser::F_SECOND;
|
||||
}
|
||||
function yy_r1_55($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::F_DATE_SUB;
|
||||
$this->token = OQLParser::F_DATE_ADD;
|
||||
}
|
||||
function yy_r1_56($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::F_ROUND;
|
||||
$this->token = OQLParser::F_DATE_SUB;
|
||||
}
|
||||
function yy_r1_57($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::F_FLOOR;
|
||||
$this->token = OQLParser::F_ROUND;
|
||||
}
|
||||
function yy_r1_58($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::F_INET_ATON;
|
||||
$this->token = OQLParser::F_FLOOR;
|
||||
}
|
||||
function yy_r1_59($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::F_INET_NTOA;
|
||||
$this->token = OQLParser::F_INET_ATON;
|
||||
}
|
||||
function yy_r1_60($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::BELOW;
|
||||
$this->token = OQLParser::F_INET_NTOA;
|
||||
}
|
||||
function yy_r1_61($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::BELOW_STRICT;
|
||||
$this->token = OQLParser::BELOW;
|
||||
}
|
||||
function yy_r1_62($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::NOT_BELOW;
|
||||
$this->token = OQLParser::BELOW_STRICT;
|
||||
}
|
||||
function yy_r1_63($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::NOT_BELOW_STRICT;
|
||||
$this->token = OQLParser::NOT_BELOW;
|
||||
}
|
||||
function yy_r1_64($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::ABOVE;
|
||||
$this->token = OQLParser::NOT_BELOW_STRICT;
|
||||
}
|
||||
function yy_r1_65($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::ABOVE_STRICT;
|
||||
$this->token = OQLParser::ABOVE;
|
||||
}
|
||||
function yy_r1_66($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::NOT_ABOVE;
|
||||
$this->token = OQLParser::ABOVE_STRICT;
|
||||
}
|
||||
function yy_r1_67($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::NOT_ABOVE_STRICT;
|
||||
$this->token = OQLParser::NOT_ABOVE;
|
||||
}
|
||||
function yy_r1_68($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::HEXVAL;
|
||||
$this->token = OQLParser::NOT_ABOVE_STRICT;
|
||||
}
|
||||
function yy_r1_69($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::NUMVAL;
|
||||
$this->token = OQLParser::HEXVAL;
|
||||
}
|
||||
function yy_r1_70($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::STRVAL;
|
||||
$this->token = OQLParser::NUMVAL;
|
||||
}
|
||||
function yy_r1_71($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::NAME;
|
||||
$this->token = OQLParser::STRVAL;
|
||||
}
|
||||
function yy_r1_72($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::VARNAME;
|
||||
$this->token = OQLParser::NAME;
|
||||
}
|
||||
function yy_r1_73($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::VARNAME;
|
||||
}
|
||||
function yy_r1_74($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::DOT;
|
||||
@@ -666,25 +672,25 @@ class OQLLexer extends OQLLexerRaw
|
||||
|
||||
function yylex()
|
||||
{
|
||||
try
|
||||
{
|
||||
return parent::yylex();
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
$sMessage = $e->getMessage();
|
||||
if (substr($sMessage, 0, strlen(UNEXPECTED_INPUT_AT_LINE)) == UNEXPECTED_INPUT_AT_LINE)
|
||||
{
|
||||
$sLineAndChar = substr($sMessage, strlen(UNEXPECTED_INPUT_AT_LINE));
|
||||
if (preg_match('#^([0-9]+): (.+)$#', $sLineAndChar, $aMatches))
|
||||
{
|
||||
$iLine = $aMatches[1];
|
||||
$sUnexpected = $aMatches[2];
|
||||
throw new OQLLexerException($this->data, $iLine, $this->count, $sUnexpected);
|
||||
}
|
||||
}
|
||||
// Default: forward the exception
|
||||
throw $e;
|
||||
try
|
||||
{
|
||||
return parent::yylex();
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
$sMessage = $e->getMessage();
|
||||
if (substr($sMessage, 0, strlen(UNEXPECTED_INPUT_AT_LINE)) == UNEXPECTED_INPUT_AT_LINE)
|
||||
{
|
||||
$sLineAndChar = substr($sMessage, strlen(UNEXPECTED_INPUT_AT_LINE));
|
||||
if (preg_match('#^([0-9]+): (.+)$#', $sLineAndChar, $aMatches))
|
||||
{
|
||||
$iLine = $aMatches[1];
|
||||
$sUnexpected = $aMatches[2];
|
||||
throw new OQLLexerException($this->data, $iLine, $this->count, $sUnexpected);
|
||||
}
|
||||
}
|
||||
// Default: forward the exception
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,6 +139,7 @@ f_round = "ROUND"
|
||||
f_floor = "FLOOR"
|
||||
f_inet_aton = "INET_ATON"
|
||||
f_inet_ntoa = "INET_NTOA"
|
||||
matches = "MATCHES"
|
||||
below = "BELOW"
|
||||
below_strict = "BELOW STRICT"
|
||||
not_below = "NOT BELOW"
|
||||
@@ -273,6 +274,9 @@ in {
|
||||
not_in {
|
||||
$this->token = OQLParser::NOT_IN;
|
||||
}
|
||||
matches {
|
||||
$this->token = OQLParser::MATCHES;
|
||||
}
|
||||
interval {
|
||||
$this->token = OQLParser::INTERVAL;
|
||||
}
|
||||
@@ -419,25 +423,25 @@ class OQLLexer extends OQLLexerRaw
|
||||
|
||||
function yylex()
|
||||
{
|
||||
try
|
||||
{
|
||||
return parent::yylex();
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
$sMessage = $e->getMessage();
|
||||
if (substr($sMessage, 0, strlen(UNEXPECTED_INPUT_AT_LINE)) == UNEXPECTED_INPUT_AT_LINE)
|
||||
{
|
||||
$sLineAndChar = substr($sMessage, strlen(UNEXPECTED_INPUT_AT_LINE));
|
||||
if (preg_match('#^([0-9]+): (.+)$#', $sLineAndChar, $aMatches))
|
||||
{
|
||||
$iLine = $aMatches[1];
|
||||
$sUnexpected = $aMatches[2];
|
||||
throw new OQLLexerException($this->data, $iLine, $this->count, $sUnexpected);
|
||||
}
|
||||
}
|
||||
// Default: forward the exception
|
||||
throw $e;
|
||||
try
|
||||
{
|
||||
return parent::yylex();
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
$sMessage = $e->getMessage();
|
||||
if (substr($sMessage, 0, strlen(UNEXPECTED_INPUT_AT_LINE)) == UNEXPECTED_INPUT_AT_LINE)
|
||||
{
|
||||
$sLineAndChar = substr($sMessage, strlen(UNEXPECTED_INPUT_AT_LINE));
|
||||
if (preg_match('#^([0-9]+): (.+)$#', $sLineAndChar, $aMatches))
|
||||
{
|
||||
$iLine = $aMatches[1];
|
||||
$sUnexpected = $aMatches[2];
|
||||
throw new OQLLexerException($this->data, $iLine, $this->count, $sUnexpected);
|
||||
}
|
||||
}
|
||||
// Default: forward the exception
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user